Compare commits

..
Author SHA1 Message Date
Dominik Sokal 4ebf6c1d2c use release-it to handle releases 2019-01-18 11:38:20 +01:00
51 changed files with 752 additions and 4344 deletions

No files matched your search

+3 -60
View File
@@ -5,76 +5,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added
- `--config` parameter for turtle-cli commands, which allows to specify a custom path to app.json file
## [0.5.13] - 2019-03-12
### Added
- Android SDK version support validation.
### Changed
- iOS Enterprise builds don't compile bitcode now.
## [0.5.12] - 2019-02-26
### Added
- Google Cloud logger (as a bunyan stream).
### Changed
- Android builder passes the manifest from a build job message if it's available.
## [0.5.11] - 2019-02-22
### Added
- Builder for iOS client apps.
## [0.5.10] - 2019-02-19
### Added
- Register Turtle version in Redis.
### Changed
- Update Android shell app for SDK 32 to fix [update](https://github.com/expo/expo/issues/3504) and [back button](https://github.com/expo/expo/issues/1786) issues.
## [0.5.9] - 2019-02-06
- Update iOS shell app for SDK 32 (fixes bare notifications [issue](https://github.com/expo/expo/issues/3223)).
## [0.5.7] - 2019-01-31
- Update Android shell app for SDK 32 to fix bundled assets issue.
## [0.5.6] - 2019-01-25
- Update iOS shell app for SDK 30, 31 and 32 (built with xcode 10.1).
## [0.5.5] - 2019-01-24
### Added
- Sending build duration in AWS SQS messages (of `FINISHED` and `ERRORED` types).
## [0.5.4] - 2019-01-22
### Changed
- Update iOS shell app for SDK32 to [`expo/expo#0847c10`](https://github.com/expo/expo/commit/0847c1073d38c366866f3d9279ddd662da47dc9b), i.e. v2.10.3 with fixed WebView navigation scheme and upgraded Facebook SDK.
## [0.5.3] - 2019-01-21
### Fixed
- Building Android standalone apps ([not accepted license issue](https://github.com/expo/expo/issues/3266)) - updated Android build tools (`build-tools;28.0.3`, `platforms;android-28`).
## [0.5.2] - 2019-01-18
### Added
- The link (in README) to the repository containing `turtle-cli` usage example.
- [Contributing guide](CONTRIBUTING.md).
- [Code of Conduct](CODE_OF_CONDUCT.md).
### Removed
- `eslint`
### Changed
- Fix all `tslint` errors.
## [0.5.1] - 2019-01-16
### Changed
- Update Android shell app for SDK32 that includes `[email protected]`.
- Update Android shell app for SDK32 that includes react-native-screens@1.0.0-alpha.22
## [0.5.0] - 2019-01-16
### Added
- Turtle version is added to the `onFinish` and `onError` build messages.
### Changed
- A version property value being sent to the queue. It's now the version number
from `package.json` instead of `new`/`old` indicator.
- Turtle version is added to onFinish and onError build messages.
### Removed
- `--push-p12-path` parameter for `turtle build:ios` command,
a Push Notifications Certificate is no longer required to perform a successful
iOS standalone app build.
- new/old Turtle version build argument
## [0.4.3] - 2019-01-09
### Changed
-33
View File
@@ -1,33 +0,0 @@
# Contributing to Turtle CLI
## How to contribute
You can contribute to Turtle CLI in various ways, including:
- [Reporting bugs or issues](https://github.com/expo/turtle/issues/new) on GitHub. Please make sure to fill in all the details suggested by the template to make sure the issue can be addressed as quickly as possible.
- [Submitting improvements to the documentation](https://github.com/expo/expo/tree/master/docs). Updates, enhancements, new guides, spelling fixes…
- Helping other people on [Expo Forums](https://forums.expo.io/) and on [Expo Developers Slack](http://slack.expo.io).
- Looking at existing [issues](https://github.com/expo/turtle/issues) and adding more information, particularly helping to reproduce the issues.
- [Submitting a pull request](#submitting-a-pull-request) with a bug fix or an improvement.
## Turtle CLI repository
### Codebase
This repository contains the codebase for the `turtle-cli` NPM package. The same codebase is used to run standalone app builders on the Expo servers.
### Branches
The `master` branch of the repository should be kept releasable at any time. This way we can continuously release fixes and improvements without costly managing of different branches and issues will be noticed and fixed quickly. This also ensures other contributors can check out the latest version from GitHub and work on it with minimal disruption from other features in progress.
## Setting up the repository for development
*TODO*
## Submitting a pull request
To submit a pull request:
1. Fork the [repository](https://github.com/expo/turtle) and create a feature branch. (Existing contributors can create feature branches without forking. Prefix the branch name with `@your-github-username/`.)
2. Write the description of your pull request. Make sure to include a test plan and test your changes.
3. Make sure all tests pass on CircleCI.
4. Wait for a review and adjust the code if necessary.
## Publishing a release
- To release a new version of `turtle-cli`, run `yarn release` command.
- If you wish to release a new *beta* version of `turtle-cli`, run `yarn release:beta` instead.
- Update [Changelog](CHANGELOG.md).
- In a terminal, `cd` into [expo/turtle-cli-example](https://github.com/expo/turtle-cli-example) repository, run `yarn update-turtle-cli-version` (this script updates `turtle-cli` version number in CI configuration files and commits the changes) and then run `git push`. Thanks!
+9 -13
View File
@@ -36,34 +36,30 @@ RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-
# Download and untar SDK
ENV ANDROID_HOME /usr/local/android-sdk-linux
ENV ANDROID_SDK /usr/local/android-sdk-linux
ENV ANDROID_SDK_URL https://dl.google.com/android/repository/sdk-tools-linux-4333796.zip
ENV ANDROID_SDK_URL https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip
RUN mkdir -p ${ANDROID_HOME} && \
curl -L "${ANDROID_SDK_URL}" > ${ANDROID_HOME}/sdk.zip && \
cd ${ANDROID_HOME} && \
unzip -qq sdk.zip && \
rm sdk.zip && \
# prevents warnings about missing repo config
mkdir -p ${HOME}/.android && \
touch ${HOME}/.android/repositories.cfg
ENV PATH ${ANDROID_HOME}/platform-tools:${PATH}
ENV PATH ${ANDROID_HOME}/tools:${PATH}
ENV PATH ${ANDROID_HOME}/tools/bin:${PATH}
ENV PATH ${ANDROID_HOME}/build-tools/28.0.3/:${PATH}
ENV PATH ${ANDROID_HOME}/build-tools/25.0.0/:${PATH}
RUN yes | sdkmanager --licenses > /dev/null
RUN yes | sdkmanager \
# Install Android SDK components
RUN sdkmanager \
"platform-tools" \
"platforms;android-23" \
"platforms;android-24" \
"platforms;android-25" \
"platforms;android-26" \
"platforms;android-27" \
"platforms;android-28"
RUN yes | sdkmanager "platform-tools"
RUN yes | sdkmanager "build-tools;28.0.3"
RUN yes | sdkmanager \
"build-tools;25.0.0" \
"extras;android;m2repository" \
"extras;google;m2repository" \
"extras;google;google_play_services"
"extras;google;m2repository"
# Install Android NDK
ENV ANDROID_NDK_VERSION android-ndk-r10e
+4 -18
View File
@@ -1,39 +1,25 @@
# Turtle CLI
[![CircleCI](https://img.shields.io/circleci/project/github/expo/turtle/master.svg)](https://circleci.com/gh/expo/turtle)
[![NPM](https://img.shields.io/npm/v/turtle-cli/latest.svg)](https://npmjs.com/package/turtle-cli)
[![License](https://img.shields.io/badge/license-MIT-green.svg?style=flat)](https://github.com/expo/turtle/blob/master/LICENSE)
[![Expo Developers Slack](https://img.shields.io/badge/Expo%20Developers-e01563.svg?logo=slack)](http://slack.expo.io)
[![Expo Forums](https://img.shields.io/badge/Expo%20Forums-blue.svg)](https://forums.expo.io/)
[![NPM](https://img.shields.io/npm/v/turtle-cli/latest.svg)](https://rubygems.org/gems/fastlane)
[![CircleCI](https://img.shields.io/circleci/project/github/expo/turtle/master.svg)](https://circleci.com/gh/expo/turtle)
Turtle CLI is a command line interface for building Expo standalone apps.
You can use it both on your CI and your private computer.
- [Changelog](CHANGELOG.md)
- [Contributing to Turtle CLI](CONTRIBUTING.md)
- [Code of Conduct](CODE_OF_CONDUCT.md)
### Glossary
## Glossary
- **Turtle** - script which takes a shell app, fills it with user's code and produces a standalone app
- **Shell app** — precompiled (in case of iOS builds) Expo app which doesn't have user's code
- **Standalone app** - .ipa/.apk file, a user uploads standalone apps to the Google Play Store/Apple App Store
## Installation
[Installation instructions and documentation here.](https://docs.expo.io/versions/latest/distribution/turtle-cli)
## Usage example
See the [expo/turtle-cli-example](https://github.com/expo/turtle-cli-example) repository to learn how to use Turtle CLI in order to build Expo standalone apps on your CI.
## Do you need help?
- Make sure you've read [the Expo Docs](https://docs.expo.io/), especially [Building Standalone Apps on Your CI
](https://docs.expo.io/versions/latest/distribution/turtle-cli) and [Building Standalone Apps](https://docs.expo.io/versions/latest/distribution/building-standalone-apps) guides.
- Search for existing GitHub issues [in this repository](https://github.com/expo/turtle/issues) and in [expo/expo](https://github.com/expo/expo/issues) repository.
- Ask for help in **one** of the following ways:
* create [a GitHub issue](https://github.com/expo/turtle/issues/new).
* create a new topic on [Expo Forums](https://forums.expo.io/).
* ask a question on [Expo Developers Slack](http://slack.expo.io).
## License
The Turtle CLI source code is made available under the [MIT license](LICENSE).
Some of the dependencies are licensed differently, with the BSD license, for example.
+1 -1
View File
@@ -9,6 +9,6 @@
"^.+\\.ts$": "ts-jest"
},
"testRegex": "(test|spec)\\.ts$",
"moduleFileExtensions": ["ts", "js", "json"],
"moduleFileExtensions": ["ts", "js"],
"verbose": true
}
+1 -1
View File
@@ -9,6 +9,6 @@
"^.+\\.ts$": "ts-jest"
},
"testMatch": [ "**/__smoke__/*.test.ts" ],
"moduleFileExtensions": ["ts", "js", "json"],
"moduleFileExtensions": ["ts", "js"],
"verbose": true
}
+1 -1
View File
@@ -9,6 +9,6 @@
"^.+\\.ts$": "ts-jest"
},
"testMatch": [ "**/__tests__/*.ts" ],
"moduleFileExtensions": ["ts", "js", "json"],
"moduleFileExtensions": ["ts", "js"],
"verbose": true
}
+4 -9
View File
@@ -1,6 +1,6 @@
{
"name": "turtle-cli",
"version": "0.5.14",
"version": "0.5.1",
"description": "The command-line tool for building standalone Expo apps",
"preferGlobal": true,
"scripts": {
@@ -28,8 +28,8 @@
"test:smoke": "yarn test --config jest/smoke-config.json --forceExit",
"test:smoke:android": "yarn test:smoke --testNamePattern=android",
"test:smoke:ios": "PLATFORM=ios yarn test:smoke --testNamePattern=iOS",
"release": "./scripts/release.sh",
"release:beta": "./scripts/releaseBeta.sh",
"release": "release-it",
"release:beta": "yarn release -c .release-it.beta.json --preRelease=beta",
"ssh:android:pods-names": "./scripts/ssh/findAndroidPods.sh",
"ssh:android:connect": "./scripts/ssh/connectToAndroidPod.sh",
"ssh:ios:ips": "./scripts/ssh/findIosIps.sh",
@@ -99,8 +99,6 @@
"typescript": "^3.0.1"
},
"dependencies": {
"@expo/spawn-async": "^1.4.0",
"@google-cloud/logging-bunyan": "^0.9.5",
"async-retry": "^1.2.1",
"aws-sdk": "^2.226.1",
"bunyan": "^1.8.12",
@@ -124,9 +122,6 @@
"tar": "^4.4.6",
"uuid": "^3.2.1",
"which": "^1.3.1",
"xdl": "53.1.6-alpha.2"
},
"optionalDependencies": {
"@expo/traveling-fastlane-darwin": "^1.8.1"
"xdl": "52.0.14-alpha.6+371be041"
}
}
+2 -9
View File
@@ -2,23 +2,16 @@
set -xeo pipefail
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/.. && pwd )"
if [ -z "$1" ]; then
echo "Please specify a platform to build"
exit 1
fi
PLATFORM=$1
export PLATFORM=$1
yarn
yarn run build
if [ "$PLATFORM" = "android" ]; then
$ROOT_DIR/scripts/android/fetchRemoteAndroidTarball.sh
elif [ "$PLATFORM" = "ios" ]; then
$ROOT_DIR/scripts/ios/fetchRemoteIosTarball.sh
fi
yarn set-workingdir:remote
if [[ -z "${TARBALL}" ]]; then
echo "TARBALL is not set, building tarball skipped"
+6 -9
View File
@@ -1,12 +1,9 @@
#!/bin/bash
SDKMANAGER=$ANDROID_HOME/tools/bin/sdkmanager
yes | $SDKMANAGER --licenses > /dev/null
yes | $SDKMANAGER "platforms;android-28"
yes | $SDKMANAGER "platform-tools"
yes | $SDKMANAGER "build-tools;28.0.3"
yes | $SDKMANAGER \
yes | $ANDROID_HOME/tools/bin/sdkmanager --licenses > /dev/null
$ANDROID_HOME/tools/bin/sdkmanager \
"platform-tools" \
"platforms;android-23" \
"build-tools;25.0.0" \
"extras;android;m2repository" \
"extras;google;m2repository" \
"extras;google;google_play_services"
"extras;google;m2repository"
-11
View File
@@ -1,11 +0,0 @@
#!/usr/bin/env bash
set -eo pipefail
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/.. && pwd )"
$ROOT_DIR/node_modules/.bin/release-it
echo
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
echo "!!!! PLEASE REMEMBER TO UPDATE CHANGELOG !!!!"
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
-7
View File
@@ -1,7 +0,0 @@
#!/usr/bin/env bash
set -eo pipefail
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/.. && pwd )"
$ROOT_DIR/node_modules/.bin/release-it -c $ROOT_DIR/.release-it.beta.json --preRelease=beta
+2 -2
View File
@@ -48,10 +48,10 @@ setup_remote() {
echo "Shell apps already fetched"
else
echo "Fetching shell apps"
if [ "$PLATFORM" != 'ios' ]; then
if [ "$PLATFORM" != 'ios']; then
$ROOT_DIR/scripts/android/fetchRemoteAndroidTarball.sh
fi
if [ "$PLATFORM" != 'android' ]; then
if [ "$PLATFORM" != 'android']; then
$ROOT_DIR/scripts/ios/fetchRemoteIosTarball.sh
fi
fi
+2
View File
@@ -20,6 +20,8 @@ export API_PORT="3000"
export REDIS_URL="noop"
export REDIS_CONFIG_URL="noop"
PLATFORM=android yarn set-workingdir:remote
yarn test:smoke:android
smoke_result=$?
+6 -7
View File
@@ -3,11 +3,11 @@
export NODE_ENV=test
export ENVIRONMENT="development"
export AWS_SQS_ANDROID_QUEUE_URL="https://sqs.us-west-2.amazonaws.com/274251141632/turtle_jobs_local_dominik_android_in.fifo"
export AWS_SQS_ANDROID_PRIORITY_QUEUE_URL="https://sqs.us-west-2.amazonaws.com/274251141632/turtle_jobs_local_dominik_android_in_priority.fifo"
export AWS_SQS_IOS_QUEUE_URL="https://sqs.us-west-2.amazonaws.com/274251141632/turtle_jobs_local_dominik_ios_in.fifo"
export AWS_SQS_IOS_PRIORITY_QUEUE_URL="https://sqs.us-west-2.amazonaws.com/274251141632/turtle_jobs_local_dominik_ios_in_priority.fifo"
export AWS_SQS_OUT_QUEUE_URL="https://sqs.us-west-2.amazonaws.com/274251141632/turtle_jobs_local_dominik_out.fifo"
export AWS_SQS_IOS_QUEUE_URL="https://sqs.us-west-2.amazonaws.com/274251141632/turtle_jobs_local_jakub_ios_in.fifo"
export AWS_SQS_ANDROID_QUEUE_URL="https://sqs.us-west-2.amazonaws.com/274251141632/turtle_jobs_local_jakub_android_in.fifo"
export AWS_SQS_IOS_PRIORITY_QUEUE_URL="https://sqs.us-west-2.amazonaws.com/274251141632/turtle_jobs_local_jakub_ios_in_priority.fifo"
export AWS_SQS_ANDROID_PRIORITY_QUEUE_URL="https://sqs.us-west-2.amazonaws.com/274251141632/turtle_jobs_local_jakub_android_in_priority.fifo"
export AWS_SQS_OUT_QUEUE_URL="https://sqs.us-west-2.amazonaws.com/274251141632/turtle_jobs_local_jakub_out.fifo"
export AWS_SQS_REGION="aws.west2"
export AWS_S3_BUCKET="exp-shell-app-assets"
export AWS_S3_REGION="us-west-1"
@@ -18,8 +18,7 @@ export API_PORT="443"
export REDIS_URL="noop"
export REDIS_CONFIG_URL="noop"
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/.. && pwd )"
$ROOT_DIR/scripts/ios/fetchRemoteIosTarball.sh
PLATFORM=ios yarn set-workingdir:remote
yarn test:smoke:ios
smoke_result=$?
+1 -1
View File
@@ -1 +1 @@
s3://exp-artifacts/android-shell-builder-a4bd3bd26b1b31bdfa66c39b6b4d0d1d138c32fc.tar.gz
s3://exp-artifacts/android-shell-builder-cb03fdc12dc74f699a6d3f22219cbcd30e01ac46.tar.gz
-1
View File
@@ -1 +0,0 @@
s3://exp-artifacts/ios-expo-client-15bb883c22173d5b01df19421580170e776041d0.tar.gz
+1 -1
View File
@@ -1 +1 @@
s3://exp-artifacts/ios-shell-builder-sdk-30-6863276e6b9605e31228c845a047387571959e9b.tar.gz
s3://exp-artifacts/ios-shell-builder-sdk-30-7d017a96d00fbf18ee7e5581ea47528b9cc78afd.tar.gz
+1 -1
View File
@@ -1 +1 @@
s3://exp-artifacts/ios-shell-builder-sdk-latest-e1a8bd0ab2e1eba546792c0ffc282b5b202ccc39.tar.gz
s3://exp-artifacts/ios-shell-builder-sdk-latest-56824ecea6ba10f5a9d8991545a1c47ee3284f5f.tar.gz
+1 -1
View File
@@ -1 +1 @@
s3://exp-artifacts/ios-shell-builder-sdk-latest-d9cabffbcba20e074e91e4d7f8d862c98acfc680.tar.gz
s3://exp-artifacts/ios-shell-builder-sdk-latest-e3855783ed0618f4dcf326dc353c6e2951e05c49.tar.gz
Binary file not shown.
+1 -1
View File
@@ -62,7 +62,7 @@ export async function changeMessageVisibility(priority: string, receiptHandle: s
}
// Every VISIBILITY_TIMEOUT_SEC / 3 seconds we are telling AWS SQS
// that we're still processing the message, so it does not
// that we're still proccessing the message, so it does not
// send the build job to another turtle agent
export function changeMessageVisibilityRecurring(priority: string, receiptHandle: string, jobId: string) {
return setInterval(() => {
+1 -2
View File
@@ -20,8 +20,7 @@ function setCommonCommandOptions(cmd: any) {
.option(
'--release-channel <channel-name>',
'pull from specified release channel (default: default)',
)
.option('-c --config <config-file>', 'specify a path to app.json');
);
}
export default {
+2 -2
View File
@@ -10,7 +10,7 @@ import download from 'turtle/bin/setup/utils/downloader';
import config from 'turtle/config';
import logger from 'turtle/logger';
const ANDROID_SDK_URL = 'https://dl.google.com/android/repository/sdk-tools-linux-4333796.zip';
const ANDROID_SDK_URL = 'https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip';
const LOGGER_FIELDS = { buildPhase: 'setting up environment' };
const l = logger.withFields(LOGGER_FIELDS);
@@ -73,6 +73,6 @@ function _createPaths(androidSdkDir: string) {
path.join(androidSdkDir, 'platform-tools'),
path.join(androidSdkDir, 'tools'),
path.join(androidSdkDir, 'tools/bin'),
path.join(androidSdkDir, 'build-tools/28.0.3'),
path.join(androidSdkDir, 'build-tools/25.0.0'),
];
}
+2 -3
View File
@@ -6,14 +6,13 @@ import { ExponentTools } from 'xdl';
import download from 'turtle/bin/setup/utils/downloader';
import { ensureToolsAreInstalled, IToolDefinition } from 'turtle/bin/setup/utils/toolsDetector';
import { IShellAppDirectoryConfig } from 'turtle/builders/utils/workingdir';
import config from 'turtle/config';
import logger from 'turtle/logger';
const l = logger.withFields({ buildPhase: 'setting up environment' });
interface IShellAppFormaters {
formatShellAppDirectory: (config: IShellAppDirectoryConfig) => string;
formatShellAppDirectory: (sdkVersion: string) => string;
formatShellAppTarballUriPath: (sdkMajorVersion: string) => string;
}
@@ -28,7 +27,7 @@ export async function ensureShellAppIsPresent(
formatters: IShellAppFormaters,
postDownloadAction?: PostDownloadAction,
) {
const workingdir = formatters.formatShellAppDirectory({ sdkVersion });
const workingdir = formatters.formatShellAppDirectory(sdkVersion);
if (await fs.pathExists(workingdir)) {
return;
}
+1 -1
View File
@@ -60,7 +60,7 @@ export function createBuilderAction({
publicUrl: cmd.publicUrl,
};
const appJSON = await ProjectUtils.loadAppJSON(projectDirArg, cmd.config);
const appJSON = await ProjectUtils.loadAppJSON(projectDirArg);
const sdkVersion = _.get(appJSON, 'expo.sdkVersion');
await setup(platform, sdkVersion);
const credentials = await prepareCredentials(cmd);
+4 -9
View File
@@ -1,17 +1,12 @@
import fs from 'fs-extra';
import path from 'path';
export async function loadAppJSON(projectDirArg: string, config: string | null) {
let appJSONPath;
if (config) {
appJSONPath = resolveAbsoluteDir(config);
} else {
const projectDir = resolveAbsoluteDir(projectDirArg);
appJSONPath = path.join(projectDir, 'app.json');
}
export async function loadAppJSON(projectDirArg: string) {
const projectDir = resolveAbsoluteDir(projectDirArg);
const appJSONPath = path.join(projectDir, 'app.json');
const appJSONExists = await fs.pathExists(appJSONPath);
if (!appJSONExists) {
throw new Error(`Couldn't find app.json.`);
throw new Error(`Couldn't find app.json in ${projectDir} directory.`);
} else {
return require(appJSONPath);
}
-17
View File
@@ -1,17 +0,0 @@
class BuildError extends Error {
public reason: BuildErrorReason;
constructor(reason: BuildErrorReason, message: string) {
super(message);
this.name = 'BuildError';
this.reason = reason;
}
}
enum BuildErrorReason {
SESSION_EXPIRED = 'session-expired',
PROVISIONING_PROFILE_MISSING = 'provisioning-profile-missing',
}
export default BuildError;
export { BuildErrorReason };
+5 -8
View File
@@ -10,13 +10,11 @@ import { formatShellAppDirectory } from 'turtle/builders/utils/android/workingdi
import * as commonUtils from 'turtle/builders/utils/common';
import * as imageHelpers from 'turtle/builders/utils/image';
import { uploadBuildToS3 } from 'turtle/builders/utils/uploader';
import { ensureCanBuildSdkVersion } from 'turtle/builders/utils/version';
import config from 'turtle/config';
import { IAndroidCredentials, IJob, IJobResult } from 'turtle/job';
import logger from 'turtle/logger';
export default async function buildAndroid(jobData: IJob): Promise<IJobResult> {
await ensureCanBuildSdkVersion(jobData);
const credentials = await getOrCreateCredentials(jobData);
const apkFilePath = await runShellAppBuilder(jobData, credentials);
const randomHex = uuidv4().replace(/-/g, '');
@@ -62,21 +60,20 @@ async function runShellAppBuilder(
const outputFilePath = path.join(temporaryFilesRoot, `shell-signed-${jobData.id}.apk`);
const { config: jobConfig, manifest, sdkVersion: sdkVersionFromJob } = jobData;
const sdkVersion = _.get(manifest, 'sdkVersion', sdkVersionFromJob);
const workingDir = formatShellAppDirectory({ sdkVersion });
const { manifest: { sdkVersion: sdkVersionFromManifest = null } = {}, sdkVersion: sdkVersionFromJob } = jobData;
const sdkVersion = sdkVersionFromJob || sdkVersionFromManifest;
const workingDir = formatShellAppDirectory(sdkVersion);
try {
await AndroidShellApp.createAndroidShellAppAsync({
url: commonUtils.getExperienceUrl(jobData),
sdkVersion,
sdkVersion: _.get(jobData, 'manifest.sdkVersion') || jobData.sdkVersion,
keystore: tempKeystorePath,
manifest,
alias: credentials.keystoreAlias,
keystorePassword: credentials.keystorePassword,
keyPassword: credentials.keyPassword,
privateConfigFile: tempShellAppConfigPath,
releaseChannel: jobConfig.releaseChannel,
releaseChannel: jobData.config.releaseChannel,
workingDir,
outputFile: outputFilePath,
});
+3 -2
View File
@@ -33,7 +33,7 @@ async function buildAndSignIPA(ctx: IContext, job: IJob, keychainPath: string, m
l.info('building and signing IPA');
const {
credentials: { provisioningProfile, certPassword, teamId },
credentials: { provisioningProfile, certPassword, teamId, password },
config: { bundleIdentifier: bundleIdentifierFromConfig },
} = job;
@@ -51,8 +51,9 @@ async function buildAndSignIPA(ctx: IContext, job: IJob, keychainPath: string, m
certPath: ctx.tempCertPath,
certPassword,
teamID: teamId,
password,
bundleIdentifier,
workspacePath: ctx.workspacePath,
workingDir: ctx.workingDir,
manifest,
});
await ipaBuilder.build();
+15 -56
View File
@@ -22,11 +22,9 @@ export interface IContext {
tempCertPath: string;
uploadPath: string;
workingDir: string;
workspacePath: string;
applicationFilesSrc: string;
}
const { EXPOKIT_APP, EXPONENT_APP } = IosShellApp;
const { DEFAULT_EXPOKIT_WORKSPACE_NAME } = IosShellApp;
const { BUILD_TYPES } = IOS;
export function createBuilderContext(job: IJob): IContext {
@@ -41,7 +39,7 @@ export function createBuilderContext(job: IJob): IContext {
} = job;
const sdkVersion = sdkVersionFromJob || sdkVersionFromManifest;
const workingDir = formatShellAppDirectory({ sdkVersion, buildType: buildType! });
const workingDir = formatShellAppDirectory(sdkVersion);
const context: any = {
appDir: join(config.directories.temporaryFilesRoot, appUUID),
@@ -57,63 +55,24 @@ export function createBuilderContext(job: IJob): IContext {
context.tempCertPath = join(context.appDir, 'cert.p12');
context.baseArchiveDir = join(context.appDir, 'archive');
if (buildType === BUILD_TYPES.CLIENT) {
context.applicationFilesSrc = join(
workingDir,
'expo-client-build',
'**',
'*',
);
} else {
context.applicationFilesSrc = join(
workingDir,
'shellAppBase-builds',
buildType as string,
'**',
'*',
);
}
if (buildType === BUILD_TYPES.ARCHIVE) {
context.outputPath = join(context.appDir, 'archive.xcarchive');
context.uploadPath = join(context.buildDir, 'archive.ipa');
context.archiveDir = join(
context.baseArchiveDir,
'Release',
`${EXPOKIT_APP}.xcarchive`,
'Products',
'Applications',
`${EXPOKIT_APP}.app`,
);
context.workspacePath = path.join(
workingDir,
'shellAppWorkspaces',
'ios',
'default',
`${EXPOKIT_APP}.xcworkspace`,
);
} else if (buildType === BUILD_TYPES.CLIENT) {
context.outputPath = join(context.appDir, 'archive.xcarchive');
context.uploadPath = join(context.buildDir, 'archive.ipa');
context.archiveDir = join(
context.baseArchiveDir,
`${EXPONENT_APP}.xcarchive`,
'Products',
'Applications',
`${EXPONENT_APP}.app`,
);
context.workspacePath = path.join(
workingDir,
'ios',
`${EXPONENT_APP}.xcworkspace`,
);
} else if (buildType === BUILD_TYPES.SIMULATOR) {
if (buildType === BUILD_TYPES.SIMULATOR) {
context.outputPath = join(context.appDir, 'archive.tar.gz');
context.uploadPath = join(context.appDir, 'archive.tar.gz');
context.archiveDir = join(
context.baseArchiveDir,
'Release',
`${EXPOKIT_APP}.app`,
`${DEFAULT_EXPOKIT_WORKSPACE_NAME}.app`,
);
} else if (buildType === BUILD_TYPES.ARCHIVE) {
context.outputPath = join(context.appDir, 'archive.xcarchive');
context.uploadPath = join(context.buildDir, 'archive.ipa');
context.archiveDir = join(
context.baseArchiveDir,
'Release',
`${DEFAULT_EXPOKIT_WORKSPACE_NAME}.xcarchive`,
'Products',
'Applications',
`${DEFAULT_EXPOKIT_WORKSPACE_NAME}.app`,
);
}
+32 -14
View File
@@ -1,23 +1,24 @@
import path from 'path';
import fs from 'fs-extra';
import pick from 'lodash/pick';
import { ExponentTools } from 'xdl';
import buildArchive from 'turtle/builders/ios/archive';
import { createBuilderContext, IContext } from 'turtle/builders/ios/context';
import buildSimulator from 'turtle/builders/ios/simulator';
import { logErrorOnce } from 'turtle/builders/utils/common';
import prepareAdHocBuildCredentials from 'turtle/builders/utils/ios/adhocBuild';
import { uploadBuildToS3 } from 'turtle/builders/utils/uploader';
import { ensureCanBuildSdkVersion } from 'turtle/builders/utils/version';
import config from 'turtle/config';
import { IOS } from 'turtle/constants/index';
import { IOS, PLATFORMS } from 'turtle/constants/index';
import { IJob, IJobResult } from 'turtle/job';
const { BUILD_TYPES } = IOS;
let SUPPORTED_SDK_VERSIONS: number[];
export default async function iosBuilder(job: IJob): Promise<IJobResult> {
if (job.config.buildType !== BUILD_TYPES.CLIENT) {
await ensureCanBuildSdkVersion(job);
}
await ensureCanBuildSdkVersion(job);
const ctx = createBuilderContext(job);
@@ -25,15 +26,10 @@ export default async function iosBuilder(job: IJob): Promise<IJobResult> {
await initBuilder(ctx);
const { buildType } = job.config;
if (buildType === BUILD_TYPES.CLIENT) {
await prepareAdHocBuildCredentials(job);
}
if ([BUILD_TYPES.ARCHIVE, BUILD_TYPES.CLIENT].includes(buildType!)) {
await buildArchive(ctx, job);
} else if (buildType === BUILD_TYPES.SIMULATOR) {
if (buildType === BUILD_TYPES.SIMULATOR) {
await buildSimulator(ctx, job);
} else if (buildType === BUILD_TYPES.ARCHIVE) {
await buildArchive(ctx, job);
} else {
throw new Error(`Unsupported iOS build type: ${buildType}`);
}
@@ -64,3 +60,25 @@ async function cleanup(ctx: IContext) {
const getTemporaryDirs = (ctx: IContext) =>
Object.values(pick(ctx, ['appDir', 'provisioningProfileDir']));
async function ensureCanBuildSdkVersion(job: IJob) {
if (config.builder.useLocalWorkingDir) {
return;
}
if (!SUPPORTED_SDK_VERSIONS) {
SUPPORTED_SDK_VERSIONS = await findSupportedSdkVersions();
}
const targetMajorSdkVersion = ExponentTools.parseSdkMajorVersion(job.sdkVersion || job.manifest.sdkVersion);
if (!SUPPORTED_SDK_VERSIONS.includes(targetMajorSdkVersion)) {
throw new Error(`Unsupported SDK Version!`);
}
}
async function findSupportedSdkVersions(): Promise<number[]> {
const SDK_DIR_PREFIX = 'sdk';
const files = await fs.readdir(path.join(config.directories.workingDir, PLATFORMS.IOS));
const sdks = files.filter((file) => file.startsWith(SDK_DIR_PREFIX));
return sdks.map((sdk) => parseInt(sdk.substr(SDK_DIR_PREFIX.length), 10));
}
+7 -9
View File
@@ -2,7 +2,7 @@ import path from 'path';
import fs from 'fs-extra';
import uuidv4 from 'uuid/v4';
import { Credentials } from 'xdl';
import { AndroidKeystore } from 'xdl';
import * as sqs from 'turtle/aws/sqs';
import { UPDATE_CREDENTIALS } from 'turtle/constants/build';
@@ -21,15 +21,13 @@ async function getOrCreateCredentials(jobData: IJob): Promise<IAndroidCredential
credentials.keystoreAlias = Buffer.from(jobData.experienceName).toString('base64');
const androidPackage = jobData.manifest.android.package;
await Credentials.Android.createKeystore(
{
keystorePath: keystoreFilename,
keystorePassword: credentials.keystorePassword,
keyPassword: credentials.keyPassword,
keyAlias: credentials.keystoreAlias,
},
await AndroidKeystore.createKeystore({
keystorePassword: credentials.keystorePassword,
keyPassword: credentials.keyPassword,
keystoreFilename,
keystoreAlias: credentials.keystoreAlias,
androidPackage,
);
});
credentials.keystore = (await fs.readFile(keystoreFilename)).toString('base64');
l.info('Keystore created successfully');
+1 -2
View File
@@ -2,11 +2,10 @@ import path from 'path';
import { ExponentTools } from 'xdl';
import { IShellAppDirectoryConfig } from 'turtle/builders/utils/workingdir';
import config from 'turtle/config';
import { PLATFORMS } from 'turtle/constants';
export function formatShellAppDirectory({ sdkVersion }: IShellAppDirectoryConfig) {
export function formatShellAppDirectory(sdkVersion: string) {
const majorSdkVersion = ExponentTools.parseSdkMajorVersion(sdkVersion);
return config.builder.useLocalWorkingDir
? path.join(config.directories.workingDir, 'local')
+4 -4
View File
@@ -18,15 +18,15 @@ export async function resizeIconWithSharpAsync(iconSizePx: number, iconFilename:
await fs.writeFile(filename, buffer);
}
export async function getImageDimensionsWithSharpAsync(dirname: string, filename: string) {
const filepath = path.join(dirname, filename);
export async function getImageDimensionsWithSharpAsync(basename: string, dirname: string) {
const filename = path.join(dirname, basename);
// PLEASE DON'T REMOVE THE FOLLOWING LINE (sharp caches files taking path as the cache key)
sharp.cache(false);
try {
const { width, height } = await sharp(filepath).metadata();
return { width, height };
const meta = await sharp(filename).metadata();
return [meta.width, meta.height];
} catch (e) {
return null;
}
-99
View File
@@ -1,99 +0,0 @@
import path from 'path';
import spawnAsync from '@expo/spawn-async';
import fs from 'fs-extra';
import isEmpty from 'lodash/isEmpty';
import { IosCodeSigning } from 'xdl';
import * as sqs from 'turtle/aws/sqs';
import BuildError, { BuildErrorReason } from 'turtle/builders/BuildError';
import { UPDATE_CREDENTIALS } from 'turtle/constants/build';
import { IJob } from 'turtle/job';
import logger from 'turtle/logger';
import { isOffline } from 'turtle/turtleContext';
// tslint:disable-next-line:no-var-requires
const travelingFastlane = process.platform === 'darwin' ? require('@expo/traveling-fastlane-darwin')() : null;
async function prepareAdHocBuildCredentials(job: IJob) {
if (process.platform !== 'darwin') {
throw new Error('This function should be called only on macOS!');
}
const { bundleIdentifier } = job.config;
const { certP12, certPassword, teamId, appleSession, udids } = job.credentials;
const certSerialNumber = IosCodeSigning.findP12CertSerialNumber(certP12, certPassword);
const args = [
teamId,
udids!.join(','),
bundleIdentifier,
certSerialNumber || '__last__',
];
try {
const credentials = await runFastlaneAction(
travelingFastlane.manageAdHocProvisioningProfile,
args,
{ env: { FASTLANE_SESSION: appleSession } },
);
if (isEmpty(credentials)) {
if (!job.credentials.provisioningProfile) {
// a user has generated the provisioning profile for his app, but he probably deleted it from Expo servers, ...
throw new BuildError(
BuildErrorReason.PROVISIONING_PROFILE_MISSING,
`Provisioning profile is missing on Expo servers.`,
);
}
return;
}
logger.info('New ad hoc provisioning profile successfully created');
job.credentials.provisioningProfile = credentials.provisioningProfile;
if (isOffline()) {
const provisioningProfilePath = path.join(job.projectDir, `adhoc.mobileprovision`);
await fs.writeFile(provisioningProfilePath, Buffer.from(credentials.provisioningProfile, 'base64'));
logger.info(`Saved provisioning profile to ${provisioningProfilePath}`);
} else {
await sqs.sendMessage(job.id, UPDATE_CREDENTIALS, {
provisioningProfileId: credentials.provisioningProfileId,
provisioningProfile: credentials.provisioningProfile,
});
logger.info('Ad Hoc provisioning profile sent to storage successfully');
}
} catch (e) {
if (e instanceof BuildError) {
logger.error('Apple Session expired! Please authenticate again using expo-cli.');
}
throw e;
}
}
async function runFastlaneAction(action: string, args: string[], { env }: any) {
const { stderr } = await spawnAsync(
action,
args,
{
stdio: ['inherit', 'pipe', 'pipe'],
env: { ...process.env, ...env },
},
);
const { result, ...rest } = JSON.parse(stderr.trim());
if (result === 'failure') {
const { reason, rawDump, type } = rest;
let errorMsg = `Reason: ${reason}`;
if (rawDump) {
errorMsg += `, raw: ${JSON.stringify(rawDump)}`;
}
if (type === 'session-expired') {
throw new BuildError(BuildErrorReason.SESSION_EXPIRED, errorMsg);
} else {
throw new Error(errorMsg);
}
} else {
return rest;
}
}
export default prepareAdHocBuildCredentials;
+15 -17
View File
@@ -8,7 +8,7 @@ import { ImageUtils, IosShellApp } from 'xdl';
import { IContext } from 'turtle/builders/ios/context';
import * as commonUtils from 'turtle/builders/utils/common';
import * as imageHelpers from 'turtle/builders/utils/image';
import { IOS } from 'turtle/constants/index';
import { PLATFORMS } from 'turtle/constants';
import { IJob } from 'turtle/job';
import logger from 'turtle/logger/index';
@@ -18,8 +18,14 @@ export default async function runShellAppBuilder(ctx: IContext, job: IJob): Prom
const { config: jobConfig, manifest, sdkVersion: sdkVersionFromJob } = job;
const { buildType, releaseChannel } = jobConfig;
const sdkVersion = _.get(manifest, 'sdkVersion', sdkVersionFromJob);
await copyAsync(ctx.applicationFilesSrc, ctx.baseArchiveDir);
const applicationFilesSrc = path.join(
ctx.workingDir,
'shellAppBase-builds',
buildType as string,
'**',
'*',
);
await copyAsync(applicationFilesSrc, ctx.baseArchiveDir);
logger.info(
{ buildPhase: 'icons setup' },
@@ -28,26 +34,18 @@ export default async function runShellAppBuilder(ctx: IContext, job: IJob): Prom
ImageUtils.setResizeImageFunction(imageHelpers.resizeIconWithSharpAsync);
ImageUtils.setGetImageDimensionsFunction(imageHelpers.getImageDimensionsWithSharpAsync);
const shellAppParams = {
url: commonUtils.getExperienceUrl(job),
sdkVersion,
action: 'configure',
type: buildType,
releaseChannel,
archivePath: ctx.archiveDir,
privateConfigData: job.config,
expoSourcePath: path.join(ctx.workingDir, 'ios'),
manifest,
output: ctx.outputPath,
verbose: true,
output: ctx.outputPath,
expoSourcePath: path.join(ctx.workingDir, PLATFORMS.IOS),
manifest,
};
if (buildType === IOS.BUILD_TYPES.CLIENT) {
Object.assign(shellAppParams, {
workspacePath: path.join(ctx.workingDir, 'ios'),
});
} else {
Object.assign(shellAppParams, {
url: commonUtils.getExperienceUrl(job),
releaseChannel,
sdkVersion,
});
}
logger.info({ buildPhase: 'configuring NSBundle' }, 'configuring NSBundle...');
return await IosShellApp.configureAndCopyArchiveAsync(shellAppParams);
+6 -12
View File
@@ -2,18 +2,12 @@ import path from 'path';
import { ExponentTools } from 'xdl';
import { IShellAppDirectoryConfig } from 'turtle/builders/utils/workingdir';
import config from 'turtle/config';
import { IOS, PLATFORMS } from 'turtle/constants';
import { PLATFORMS } from 'turtle/constants';
export function formatShellAppDirectory({ sdkVersion, buildType }: IShellAppDirectoryConfig) {
const { workingDir } = config.directories;
if (buildType === IOS.BUILD_TYPES.CLIENT) {
return path.join(workingDir, PLATFORMS.IOS, 'client');
} else if (config.builder.useLocalWorkingDir) {
return path.join(workingDir, 'local');
} else {
const majorVersion = ExponentTools.parseSdkMajorVersion(sdkVersion);
return path.join(workingDir, PLATFORMS.IOS, `sdk${majorVersion}`);
}
export function formatShellAppDirectory(sdkVersion: string) {
const majorVersion = ExponentTools.parseSdkMajorVersion(sdkVersion);
return config.builder.useLocalWorkingDir
? path.join(config.directories.workingDir, 'local')
: path.join(config.directories.workingDir, PLATFORMS.IOS, `sdk${majorVersion}`);
}
-30
View File
@@ -1,30 +0,0 @@
import fs from 'fs-extra';
import path from 'path';
import { ExponentTools } from 'xdl';
import config from 'turtle/config';
import { IJob } from 'turtle/job';
let SUPPORTED_SDK_VERSIONS: number[];
export async function ensureCanBuildSdkVersion(job: IJob) {
if (config.builder.useLocalWorkingDir) {
return;
}
if (!SUPPORTED_SDK_VERSIONS) {
SUPPORTED_SDK_VERSIONS = await findSupportedSdkVersions(job.platform);
}
const targetMajorSdkVersion = ExponentTools.parseSdkMajorVersion(job.sdkVersion || job.manifest.sdkVersion);
if (!SUPPORTED_SDK_VERSIONS.includes(targetMajorSdkVersion)) {
throw new Error(`Unsupported SDK Version!`);
}
}
async function findSupportedSdkVersions(platform: 'android' | 'ios'): Promise<number[]> {
const SDK_DIR_PREFIX = 'sdk';
const files = await fs.readdir(path.join(config.directories.workingDir, platform));
const sdks = files.filter((file) => file.startsWith(SDK_DIR_PREFIX));
return sdks.map((sdk) => parseInt(sdk.substr(SDK_DIR_PREFIX.length), 10));
}
-6
View File
@@ -1,6 +0,0 @@
import { IOS } from 'turtle/constants';
export interface IShellAppDirectoryConfig {
sdkVersion: string;
buildType?: IOS.BUILD_TYPES;
}
+1 -4
View File
@@ -8,7 +8,7 @@ export default {
env: env('NODE_ENV'),
hostname: env('HOSTNAME', os.hostname()),
deploymentEnv: env('ENVIRONMENT'),
platform: env('PLATFORM', PLATFORMS.IOS) as PLATFORMS,
platform: env('PLATFORM', PLATFORMS.IOS),
aws: {
accessKeyId: env('AWS_ACCESS_KEY_ID'),
secretAccessKey: env('AWS_SECRET_ACCESS_KEY'),
@@ -53,9 +53,6 @@ export default {
buffer: envNum('LOGGLY_BUFFER', 100),
},
},
google: {
credentials: env('GOOGLE_APPLICATION_CREDENTIALS', ''),
},
sentry: {
dsn: env('SENTRY_DSN', ''),
},
+4 -4
View File
@@ -1,9 +1,9 @@
import * as BUILD from './build';
import * as IOS from './ios';
export enum PLATFORMS {
IOS = 'ios',
ANDROID = 'android',
}
export const PLATFORMS = {
IOS: 'ios',
ANDROID: 'android',
};
export { IOS, BUILD };
+4 -5
View File
@@ -1,5 +1,4 @@
export enum BUILD_TYPES {
ARCHIVE = 'archive',
CLIENT = 'client',
SIMULATOR = 'simulator',
}
export const BUILD_TYPES = {
ARCHIVE: 'archive',
SIMULATOR: 'simulator',
};
+3 -6
View File
@@ -1,5 +1,3 @@
import { IOS } from 'turtle/constants';
export interface IJob {
platform: 'android' | 'ios';
experienceName: string;
@@ -10,7 +8,7 @@ export interface IJob {
releaseChannel: string;
publicUrl?: string;
// ios
buildType?: IOS.BUILD_TYPES;
buildType?: string;
bundleIdentifier?: string;
};
credentials: {
@@ -18,14 +16,13 @@ export interface IJob {
keystore?: string;
keystoreAlias?: string;
keystorePassword?: string;
keyPassword?: string;
// ios
keyPassword?: string;
certP12?: string;
certPassword?: string;
provisioningProfile?: string;
password?: string;
teamId?: string;
appleSession?: string;
udids?: string[];
};
projectDir: string;
fakeUploadDir?: string;
+13 -26
View File
@@ -1,19 +1,23 @@
import path from 'path';
import fs from 'fs-extra';
import _ from 'lodash';
import * as sqs from 'turtle/aws/sqs';
import builders from 'turtle/builders';
import BuildError from 'turtle/builders/BuildError';
import { logErrorOnce } from 'turtle/builders/utils/common';
import config from 'turtle/config';
import { BUILD } from 'turtle/constants/index';
import logger from 'turtle/logger';
import * as buildDurationMetric from 'turtle/metrics/buildDuration';
import * as buildStatusMetric from 'turtle/metrics/buildStatus';
import { checkShouldExit, setCurrentJobId, turtleVersion } from 'turtle/turtleContext';
import { checkShouldExit, setCurrentJobId } from 'turtle/turtleContext';
import { getPriorities } from 'turtle/utils/priorities';
import * as redis from 'turtle/utils/redis';
import { sanitizeJob } from 'turtle/validator';
const { version: turtleVersion } = JSON.parse(fs.readFileSync(path.join(__dirname, '../package.json'), 'utf-8'));
function _maybeExit() {
if (checkShouldExit()) {
logger.warn('Exiting due to previously received termination signal.');
@@ -71,21 +75,20 @@ async function processJob(jobData: any) {
logger.info('The job has been cancelled');
} else {
redis.registerListener(job.id, () => deleteMessage(priority, receiptHandle));
const startTimestamp = Date.now();
const startTimestamp = +new Date();
let buildFailed = false;
const buildType = _.get(job, 'config.buildType', 'default');
try {
const status = await build(job);
buildStatusMetric.add(buildType, status);
buildFailed = !status;
const success = await build(job);
buildStatusMetric.add(buildType, success);
buildFailed = !success;
} catch (err) {
buildStatusMetric.add(buildType, false);
buildFailed = true;
throw err;
} finally {
const endTimestamp = Date.now();
const endTimestamp = +new Date();
const turtleBuildDurationSecs = Math.ceil((endTimestamp - startTimestamp) / 1000);
logger.info(`BuildID=${job.id} Build duration=${turtleBuildDurationSecs}`);
buildDurationMetric.addTurtleDuration(buildType, turtleBuildDurationSecs, !buildFailed);
if (job.messageCreatedTimestamp) {
const totalBuildDurationSecs = Math.ceil(
@@ -120,9 +123,7 @@ function failAfterMaxJobTime(priority: string, receiptHandle: string, job: any)
}
async function build(job: any) {
const startTimestamp = Date.now();
const s3Url = await logger.init(job);
const calculateBuildDuration = () => Math.ceil((Date.now() - startTimestamp) / 1000);
try {
await sqs.sendMessage(job.id, BUILD.JOB_STATES.IN_PROGRESS, {
@@ -130,25 +131,11 @@ async function build(job: any) {
logFormat: 'json',
});
const result = await (builders as any)[job.platform](job);
const buildDuration = calculateBuildDuration();
sqs.sendMessage(job.id, BUILD.JOB_STATES.FINISHED, {
...result,
turtleVersion,
buildDuration,
});
sqs.sendMessage(job.id, BUILD.JOB_STATES.FINISHED, { ...result, turtleVersion });
return true;
} catch (err) {
logErrorOnce(err);
const buildDuration = calculateBuildDuration();
let reason;
if (err instanceof BuildError) {
reason = err.reason;
}
sqs.sendMessage(job.id, BUILD.JOB_STATES.ERRORED, {
turtleVersion,
buildDuration,
...reason && { reason },
});
sqs.sendMessage(job.id, BUILD.JOB_STATES.ERRORED, { turtleVersion });
return false;
} finally {
await logger.cleanup(job);
+4 -6
View File
@@ -12,13 +12,11 @@ export default baseJobSchema.concat(
}),
credentials: Joi.object()
.keys({
certP12: Joi.string().required(),
certPassword: Joi.string().required(),
teamId: Joi.string().required(),
// it's not required for adhoc Expo Client builds
certP12: Joi.string(),
certPassword: Joi.string(),
teamId: Joi.string(),
provisioningProfile: Joi.string(),
appleSession: Joi.string(),
udids: Joi.array().items(Joi.string()),
password: Joi.string(),
})
.when('config.buildType', {
is: IOS.BUILD_TYPES.SIMULATOR,
+2 -19
View File
@@ -10,11 +10,6 @@ import HackyLogglyStream from 'turtle/logger/hackyLogglyStream';
import S3Stream from 'turtle/logger/s3Stream';
import { isOffline } from 'turtle/turtleContext';
// type error when using import
// https://github.com/googleapis/nodejs-logging-bunyan/issues/241
// tslint:disable-next-line:no-var-requires
const { LoggingBunyan } = require('@google-cloud/logging-bunyan');
interface IStream {
stream: any;
type?: string;
@@ -59,6 +54,8 @@ if (config.logger.loggly.token) {
// prettier-ignore
tags: [
'app-shell-apps',
`platform.${config.platform}`,
`environment.${config.deploymentEnv}`,
],
};
logglyStream = new HackyLogglyStream(logglyConfig);
@@ -68,23 +65,9 @@ if (config.logger.loggly.token) {
});
}
if (config.google.credentials) {
const resource = {
type: 'generic_node',
labels: {
node_id: config.hostname,
location: '', // default value
namespace: '', // default value
},
};
streams.push(new LoggingBunyan({ name: 'turtle', resource }).stream('info'));
}
const logger = bunyan.createLogger({
name: 'turtle',
level: config.logger.level,
platform: config.platform,
environment: config.deploymentEnv,
streams,
});
+1 -13
View File
@@ -4,10 +4,7 @@ import config from 'turtle/config';
import { doJob } from 'turtle/jobManager';
import logger from 'turtle/logger';
import setup from 'turtle/setup';
import { checkShouldExit, setShouldExit, turtleVersion } from 'turtle/turtleContext';
import { getRedisClient, RedisClient } from 'turtle/utils/redis';
const REDIS_TURTLE_VERSION_KEY = 'turtle:version';
import { checkShouldExit, setShouldExit } from 'turtle/turtleContext';
process.on('unhandledRejection', (err) => logger.error('Unhandled promise rejection:', err));
@@ -33,15 +30,6 @@ async function main() {
if (setup[config.platform]) {
await setup[config.platform]();
}
try {
const redis = await getRedisClient(RedisClient.Configuration);
await redis.set(REDIS_TURTLE_VERSION_KEY, turtleVersion);
logger.info(`Register Turtle version ${turtleVersion} in Redis`);
} catch (err) {
logger.error('Failed to register Turtle version in Redis', err);
}
while (true) {
try {
await doJob();
-5
View File
@@ -1,10 +1,5 @@
import fs from 'fs-extra';
import path from 'path';
import config from 'turtle/config';
const { version: turtleVersion } = JSON.parse(fs.readFileSync(path.join(__dirname, '../package.json'), 'utf-8'));
export { turtleVersion };
let shouldExit = false;
let currentJobId: string | null = null;
-4
View File
@@ -41,10 +41,6 @@ export function createDefaultConfigurationKey(platform = config.platform) {
}
export async function getPriorities() {
if (config.env === 'test') {
return NORMAL_CONFIGURATION;
}
try {
const redis = await getRedisClient(RedisClient.Configuration);
if (redis.getConfig === undefined) {
+576 -3772
View File
File diff suppressed because it is too large. Load diff