mirror of
https://github.com/expo/turtle.git
synced 2026-11-14 19:12:55 -10:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
287d5f88e5 |
No files matched your search
@@ -137,23 +137,6 @@ commands:
|
||||
paths:
|
||||
- "<< parameters.workingdir >>/<< parameters.platform >>/<< parameters.sdk_version >>"
|
||||
|
||||
deploy_turtle:
|
||||
parameters:
|
||||
platform:
|
||||
type: string
|
||||
env:
|
||||
type: string
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Install curl & jq
|
||||
command: nix-env -iA nixpkgs.curl nixpkgs.jq
|
||||
- run:
|
||||
name: Schedule a Turtle deploy
|
||||
command: |
|
||||
echo "We're going to deploy << parameters.platform >> Turtles to << parameters.env >>"
|
||||
./scripts/deploy.sh "<< parameters.platform >>" "<< parameters.env >>"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
executor: nix
|
||||
@@ -220,34 +203,6 @@ jobs:
|
||||
sdk_version: sdk32
|
||||
platform: android
|
||||
|
||||
android_staging_deploy:
|
||||
executor: nix
|
||||
steps:
|
||||
- deploy_turtle:
|
||||
platform: android
|
||||
env: staging
|
||||
|
||||
android_production_deploy:
|
||||
executor: nix
|
||||
steps:
|
||||
- deploy_turtle:
|
||||
platform: android
|
||||
env: production
|
||||
|
||||
ios_staging_deploy:
|
||||
executor: nix
|
||||
steps:
|
||||
- deploy_turtle:
|
||||
platform: ios
|
||||
env: staging
|
||||
|
||||
ios_production_deploy:
|
||||
executor: nix
|
||||
steps:
|
||||
- deploy_turtle:
|
||||
platform: ios
|
||||
env: production
|
||||
|
||||
workflows:
|
||||
checks:
|
||||
jobs:
|
||||
@@ -257,25 +212,3 @@ workflows:
|
||||
- unit_tests
|
||||
- ios_smoke_tests
|
||||
- android_smoke_tests
|
||||
deploy:
|
||||
jobs:
|
||||
- android_staging_approve_deploy:
|
||||
type: approval
|
||||
- android_staging_deploy:
|
||||
requires:
|
||||
- android_staging_approve_deploy
|
||||
- android_production_approve_deploy:
|
||||
type: approval
|
||||
- android_production_deploy:
|
||||
requires:
|
||||
- android_production_approve_deploy
|
||||
- ios_staging_approve_deploy:
|
||||
type: approval
|
||||
- ios_staging_deploy:
|
||||
requires:
|
||||
- ios_staging_approve_deploy
|
||||
- ios_production_approve_deploy:
|
||||
type: approval
|
||||
- ios_production_deploy:
|
||||
requires:
|
||||
- ios_production_approve_deploy
|
||||
@@ -8,13 +8,16 @@ source_local() {
|
||||
watch_file $file
|
||||
}
|
||||
|
||||
source_up || true
|
||||
source_local
|
||||
|
||||
export NODE_ENV=development
|
||||
|
||||
export EXPO_TURTLE_TOOLS_DIR="$(pwd)/tools"
|
||||
|
||||
PATH_add $EXPO_TURTLE_TOOLS_DIR/bin
|
||||
if [ "$CI" = "true" ]; then
|
||||
PATH_add $EXPO_TURTLE_TOOLS_DIR/ci/bin
|
||||
if [ -z "$EXPO_UNIVERSE_DIR" ]; then
|
||||
PATH_add $EXPO_TURTLE_TOOLS_DIR/bin
|
||||
if [ "$CI" = "true" ]; then
|
||||
PATH_add $EXPO_TURTLE_TOOLS_DIR/ci/bin
|
||||
fi
|
||||
fi
|
||||
+1
-17
@@ -6,25 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.8.7] - 2019-07-05
|
||||
### Added
|
||||
- Adhoc Builds: use provisioningProfileId if specified.
|
||||
- Registering supported SDK versions in Redis.
|
||||
- Support for 64 bit builds in SDK33.
|
||||
|
||||
## [0.8.6] - 2019-06-25
|
||||
### Added
|
||||
- Added support for Android build modes: debug or release.
|
||||
### Fixed
|
||||
- Upgrading the shell app for a given SDK version when the previous version is already downloaded (bug in `turtle-cli`).
|
||||
- Updated Android shell app for SDK33 to include `[email protected]` which fixes crashes on Android 9.0 when showing some Lottie animations.
|
||||
- Schema for `buildModes`.
|
||||
- Updated @expo/xdl to 55.0.7 (fixed reading from binary plist).
|
||||
|
||||
## [0.8.4] - 2019-06-13
|
||||
### Changed
|
||||
- Upgraded `sharp` from `0.21.3` to `0.22.1`.
|
||||
- `gulp-cli` is no longer required to build an app with `turtle-cli`.
|
||||
|
||||
## [0.8.3] - 2019-06-13
|
||||
### Added
|
||||
@@ -132,7 +116,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [0.5.10] - 2019-02-19
|
||||
### Added
|
||||
- Registering Turtle version in Redis.
|
||||
- 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.
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@ This repository contains the codebase for the `turtle-cli` NPM package. The same
|
||||
### 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/`.)
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
# Turtle Development
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Working `www` service, see [this README](https://github.com/expo/universe/tree/master/server/www/README.md) for more details.
|
||||
- Own AWS SQS queues. See [this README](https://github.com/expo/universe/tree/master/terraform/turtle-queues/README.md) to learn more.
|
||||
|
||||
## Setup
|
||||
|
||||
- Run `update-local-secrets` to populate the `.secrets*` files. You'll need to run this any time any secret changes (it shouldn't be very often).
|
||||
- Run `EXPO_UNIVERSE_DIR=/path/to/universe/dir yarn secrets:init-private YOUR_SQS_NICKNAME`. Alternatively, you can create `.secrets.local-queue` file with the SQS queues' urls yourself (`AWS_SQS_OUT_QUEUE_URL`, `AWS_SQS_ANDROID_QUEUE_URL`, `AWS_SQS_ANDROID_PRIORITY_QUEUE_URL`, `AWS_SQS_IOS_QUEUE_URL`, `AWS_SQS_IOS_PRIORITY_QUEUE_URL`)
|
||||
- Run `yarn set-workingdir:local` or `yarn set-workingdir:remote`:
|
||||
- `:local` creates symlinks to the shell apps in `expo` repository (_unfortunately this is currently broken_)
|
||||
- `:remote` downloads precompiled shell apps
|
||||
- Run `yarn` to install node modules.
|
||||
- Run `yarn start:ios` or `yarn start:android` to run Turtle.
|
||||
|
||||
## Updating shell apps
|
||||
|
||||
_TODO_
|
||||
|
||||
## Generating recording files for smoke tests
|
||||
|
||||
Smoke tests are powered by [Nock](https://www.npmjs.com/package/nock) which uses JSON files containing responses to the HTTP requests fired by the build process.
|
||||
|
||||
To record new responses remove old `recording.json` and run tests and then manually schedule a build with `expo-cli` tool.
|
||||
|
||||
As a precaution, the file with HTTP requests/responses contains, among other things, iOS certificates used for the test build, is
|
||||
encrypted with `git-crypt`. Remember not to revoke them, because then the tests will fail.
|
||||
|
||||
## Other notes
|
||||
|
||||
Turtle uses Redis to get notifications (from www) about builds cancellations. To make this feature working, you have to use the same Redis instance as www. Therefore, you need to remember about starting www before starting Turtle. If you forget about it, don't worry, Turtle will remind you to run `yarn start-docker` in `server/www` directory.
|
||||
|
||||
Turtle uploads build artifacts to S3. This could take some time if you have a poor internet connection. To facilitate local development, there is a feature which allows Turtle to fake artifacts upload. `secrets:init-private` script, which you should have run while setting up Turtle, sets fake upload directory to your user's default `Downloads` directory (we're assuming you're using Mac). If you need to test uploading artifacts to S3, you have to edit `.secrets.local` file and comment or remove `TURTLE_FAKE_UPLOAD` and `TURTLE_FAKE_UPLOAD_DIR` environment variables.
|
||||
@@ -15,20 +15,21 @@ 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](CONTRIBUTING.md)
|
||||
- [Development](DEVELOPMENT.md)
|
||||
- [Contributing to Turtle CLI](CONTRIBUTING.md)
|
||||
- [Code of Conduct](CODE_OF_CONDUCT.md)
|
||||
|
||||
## Installation
|
||||
## 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.
|
||||
@@ -38,6 +39,5 @@ See the [expo/turtle-cli-example](https://github.com/expo/turtle-cli-example) re
|
||||
* 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.
|
||||
+21
-5
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "turtle-cli",
|
||||
"version": "0.8.7",
|
||||
"version": "0.8.4",
|
||||
"description": "The command-line tool for building standalone Expo apps",
|
||||
"preferGlobal": true,
|
||||
"scripts": {
|
||||
@@ -13,10 +13,14 @@
|
||||
"prepare": "rimraf ./build && yarn build",
|
||||
"build": "ttsc",
|
||||
"build:production": "./scripts/build.sh",
|
||||
"watch": "ttsc --watch",
|
||||
"secrets:init-private": "./scripts/initPrivateSecrets.sh",
|
||||
"set-workingdir:remote": "./scripts/setWorkingdirMode.sh remote",
|
||||
"set-workingdir:local": "./scripts/setWorkingdirMode.sh local",
|
||||
"docker:pull": "retry5 gcloud docker -- pull gcr.io/exponentjs/turtle-android:latest",
|
||||
"docker:pull:tag": "retry5 gcloud docker -- pull gcr.io/exponentjs/turtle-android:${TAG}",
|
||||
"docker:build": "yarn build:production android && gcloud docker -- build -t gcr.io/exponentjs/turtle-android:latest -t gcr.io/exponentjs/turtle-android:${TAG} .",
|
||||
"docker:push": "retry5 gcloud docker -- push gcr.io/exponentjs/turtle-android:${TAG} && retry5 gcloud docker -- push gcr.io/exponentjs/turtle-android:latest",
|
||||
"deploy:android": "./scripts/android/deploy.sh",
|
||||
"test": "yarn jest",
|
||||
"test:integration": "yarn test --config jest/integration-config.json",
|
||||
"test:unit": "yarn test --config jest/unit-config.json",
|
||||
@@ -24,7 +28,19 @@
|
||||
"test:smoke:android": "PLATFORM=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:beta": "./scripts/releaseBeta.sh",
|
||||
"ssh:android:pods-names": "./scripts/ssh/findAndroidPods.sh",
|
||||
"ssh:android:connect": "./scripts/ssh/connectToAndroidPod.sh",
|
||||
"ssh:ios:ips": "./scripts/ssh/findIosIps.sh",
|
||||
"set-priorities": "yarn set-priorities:local",
|
||||
"set-priorities:default": "expenv ts-node -r tsconfig-paths/register --files src/scripts/setConfigurations.ts",
|
||||
"set-priorities:local": "EXPENV_OVERRIDES=local-common,local,local-queue yarn set-priorities:default",
|
||||
"set-priorities:staging": "yarn set-priorities:default",
|
||||
"set-priorities:production": "EXPENV_OVERRIDES=prod yarn set-priorities:default",
|
||||
"set-replica-count:default": "expenv ts-node -r tsconfig-paths/register --files src/scripts/setReplicaCount.ts | bunyan -o short -l debug",
|
||||
"set-replica-count:local": "EXPENV_OVERRIDES=local-common,local,local-queue yarn set-replica-count:default",
|
||||
"set-replica-count:staging": "yarn set-replica-count:default",
|
||||
"set-replica-count:production": "EXPENV_OVERRIDES=prod yarn set-replica-count:default"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
@@ -94,7 +110,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@expo/spawn-async": "^1.4.2",
|
||||
"@expo/xdl": "55.0.7",
|
||||
"@expo/xdl": "54.1.4",
|
||||
"@google-cloud/logging-bunyan": "^0.9.5",
|
||||
"async-retry": "^1.2.1",
|
||||
"aws-sdk": "^2.226.1",
|
||||
@@ -122,6 +138,6 @@
|
||||
"which": "^1.3.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@expo/traveling-fastlane-darwin": "1.9.9"
|
||||
"@expo/traveling-fastlane-darwin": "1.9.4"
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
SCRIPT_NAME=`basename "$0"`
|
||||
DEPLOY_ENDPOINT_URL="https://circleci.com/api/v1.1/project/github/expo/turtle-deploy/tree/master"
|
||||
|
||||
if [[ -z "$1" || -z "$2" ]]; then
|
||||
echo "usage: ${bold}$SCRIPT_NAME PLATFORM ENVIRONMENT [FORCE]${normal}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PLATFORM="$1"
|
||||
ENVIRONMENT="$2"
|
||||
|
||||
if [[ "$3" = "--force" ]]; then
|
||||
FORCE_DEPLOY="true"
|
||||
fi
|
||||
|
||||
if [[ "$PLATFORM" != "android" && "$PLATFORM" != "ios" ]]; then
|
||||
echo "unsupported PLATFORM passed: ${bold}$PLATFORM${normal}"
|
||||
echo "valid values are: ${bold}android${normal}, ${bold}ios${normal}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$ENVIRONMENT" != "staging" && "$ENVIRONMENT" != "production" ]]; then
|
||||
echo "unsupported ENVIRONMENT passed: ${bold}$ENVIRONMENT${normal}"
|
||||
echo "valid values are: ${bold}staging${normal}, ${bold}production${normal}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -z "$CIRCLE_SHA1" ]]; then
|
||||
TURTLE_COMMIT="$CIRCLE_SHA1"
|
||||
elif [[ -z "$FORCE_DEPLOY" ]]; then
|
||||
read -p "You're about to schedule a deploy, are you sure you want to deploy the current commit? (y/n) " -n 1 -r
|
||||
echo # (optional) move to a new line
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "exiting..."
|
||||
exit 0
|
||||
else
|
||||
TURTLE_COMMIT=`git log --pretty=format:%H -1`
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -z "$TURTLE_BOT_CIRCLE_API_USER_TOKEN" ]]; then
|
||||
echo "Please set the TURTLE_BOT_CIRCLE_API_USER_TOKEN env variable."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $FORCE_DEPLOY = "true" ]]; then
|
||||
curl -X POST \
|
||||
--header "Content-Type: application/json" \
|
||||
-u $TURTLE_BOT_CIRCLE_API_USER_TOKEN: \
|
||||
-d '
|
||||
{
|
||||
"build_parameters": {
|
||||
"CIRCLE_JOB": "deploy_'$PLATFORM'",
|
||||
"TURTLE_ENV": "'$ENVIRONMENT'",
|
||||
"TURTLE_FORCE_DEPLOY": "true"
|
||||
}
|
||||
}' \
|
||||
$DEPLOY_ENDPOINT_URL | jq -r .build_url
|
||||
else
|
||||
curl -X POST \
|
||||
--header "Content-Type: application/json" \
|
||||
-u $TURTLE_BOT_CIRCLE_API_USER_TOKEN: \
|
||||
-d '
|
||||
{
|
||||
"build_parameters": {
|
||||
"CIRCLE_JOB": "deploy_'$PLATFORM'",
|
||||
"TURTLE_ENV": "'$ENVIRONMENT'",
|
||||
"TURTLE_COMMIT": "'$TURTLE_COMMIT'"
|
||||
}
|
||||
}' \
|
||||
$DEPLOY_ENDPOINT_URL | jq -r .build_url
|
||||
fi
|
||||
@@ -13,17 +13,13 @@ fi
|
||||
TURTLE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/.. && pwd )"
|
||||
TERRAFORM_DIR="${EXPO_UNIVERSE_DIR}/terraform"
|
||||
|
||||
ANDROID_NORMAL=`cd $TERRAFORM_DIR; terraform state show module.turtle_queues_local_$1.aws_sqs_queue.jobs_android_in | head -1 | cut -d"=" -f2 | xargs`
|
||||
ANDROID_PRIORITY=`cd $TERRAFORM_DIR; terraform state show module.turtle_queues_local_$1.aws_sqs_queue.jobs_android_in_priority | head -1 | cut -d"=" -f2 | xargs`
|
||||
IOS_NORMAL=`cd $TERRAFORM_DIR; terraform state show module.turtle_queues_local_$1.aws_sqs_queue.jobs_ios_in | head -1 | cut -d"=" -f2 | xargs`
|
||||
IOS_PRIORITY=`cd $TERRAFORM_DIR; terraform state show module.turtle_queues_local_$1.aws_sqs_queue.jobs_ios_in_priority | head -1 | cut -d"=" -f2 | xargs`
|
||||
ANDROID=`cd $TERRAFORM_DIR; terraform state show module.turtle_queues_local_$1.aws_sqs_queue.jobs_android_in | head -1 | cut -d"=" -f2 | xargs`
|
||||
IOS=`cd $TERRAFORM_DIR; terraform state show module.turtle_queues_local_$1.aws_sqs_queue.jobs_ios_in | head -1 | cut -d"=" -f2 | xargs`
|
||||
OUT=`cd $TERRAFORM_DIR; terraform state show module.turtle_queues_local_$1.aws_sqs_queue.jobs_out | head -1 | cut -d"=" -f2 | xargs`
|
||||
|
||||
cat << EOF > $TURTLE_DIR/.secrets.local-queue
|
||||
AWS_SQS_ANDROID_QUEUE_URL="$ANDROID_NORMAL"
|
||||
AWS_SQS_ANDROID_PRIORITY_QUEUE_URL="$ANDROID_PRIORITY"
|
||||
AWS_SQS_IOS_QUEUE_URL="$IOS_NORMAL"
|
||||
AWS_SQS_IOS_PRIORITY_QUEUE_URL="$IOS_PRIORITY"
|
||||
AWS_SQS_ANDROID_QUEUE_URL="$ANDROID"
|
||||
AWS_SQS_IOS_QUEUE_URL="$IOS"
|
||||
AWS_SQS_OUT_QUEUE_URL="$OUT"
|
||||
EOF
|
||||
|
||||
@@ -6,44 +6,42 @@ DOWNLOAD_DIR="${EXPO_DOWNLOAD_DIR:-$HOME/Downloads}"
|
||||
|
||||
mkdir -p $DOWNLOAD_DIR
|
||||
|
||||
if [ ! -f "$ROOT_DIR/.secrets.local-queue" ]; then
|
||||
echo "You need to run \"yarn secrets:init-private [SQS_NAME]\" or create the .secrets.local-queue file yourself with AWS_SQS_ANDROID_QUEUE_URL, AWS_SQS_ANDROID_PRIORITY_QUEUE_URL, AWS_SQS_IOS_QUEUE_URL, AWS_SQS_IOS_PRIORITY_QUEUE_URL and AWS_SQS_OUT_QUEUE_URL variables."
|
||||
if [ ! -f "$ROOT_DIR/.secrets.local-queue" ]; then
|
||||
echo "You need to run \"yarn secrets:init-private [SQS_NAME]\" or create .secrets.local-queue file yourself with AWS_SQS_ANDROID_QUEUE_URL, AWS_SQS_IOS_QUEUE_URL and AWS_SQS_OUT_QUEUE_URL variables."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# @dsokal: this is currently broken
|
||||
#
|
||||
# setup_local() {
|
||||
# ensure_link_exists() {
|
||||
# if [ ! -L "$2" ]; then
|
||||
# ln -s $1 $2
|
||||
# echo "$2 link created"
|
||||
# fi
|
||||
# }
|
||||
# WORKINGDIR="$ROOT_DIR/workingdir/local"
|
||||
#
|
||||
# if [[ -d $WORKINGDIR ]]; then
|
||||
# echo "Local workingdir already prepared"
|
||||
# return
|
||||
# fi
|
||||
#
|
||||
# if [[ -z "$EXPO_UNIVERSE_DIR" ]]; then
|
||||
# echo "EXPO_UNIVERSE_DIR needs to be set"
|
||||
# exit -1
|
||||
# fi
|
||||
#
|
||||
# cd $EXPO_UNIVERSE_DIR/exponent && yarn
|
||||
# cd $EXPO_UNIVERSE_DIR/exponent/tools-public && yarn && ./generate-dynamic-macros-android.sh
|
||||
#
|
||||
# mkdir -p $WORKINGDIR
|
||||
# echo "$WORKINGDIR directory created"
|
||||
#
|
||||
# LINKS=("template-files" "package.json" "android" "expokit-npm-package" "packages" "client-builds" "cpp" "exponent-view-template" "ios" "shellAppBase-builds" "shellAppWorkspaces" "node_modules")
|
||||
#
|
||||
# for LINKNAME in ${LINKS[@]}; do
|
||||
# ensure_link_exists "$EXPO_UNIVERSE_DIR/exponent/$LINKNAME" "$WORKINGDIR/$LINKNAME"
|
||||
# done
|
||||
# }
|
||||
setup_local() {
|
||||
ensure_link_exists() {
|
||||
if [ ! -L "$2" ]; then
|
||||
ln -s $1 $2
|
||||
echo "$2 link created"
|
||||
fi
|
||||
}
|
||||
WORKINGDIR="$ROOT_DIR/workingdir/local"
|
||||
|
||||
if [[ -d $WORKINGDIR ]]; then
|
||||
echo "Local workingdir already prepared"
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ -z "$EXPO_UNIVERSE_DIR" ]]; then
|
||||
echo "EXPO_UNIVERSE_DIR needs to be set"
|
||||
exit -1
|
||||
fi
|
||||
|
||||
cd $EXPO_UNIVERSE_DIR/exponent && yarn
|
||||
cd $EXPO_UNIVERSE_DIR/exponent/tools-public && yarn && ./generate-dynamic-macros-android.sh
|
||||
|
||||
mkdir -p $WORKINGDIR
|
||||
echo "$WORKINGDIR directory created"
|
||||
|
||||
LINKS=("template-files" "package.json" "android" "expokit-npm-package" "packages" "client-builds" "cpp" "exponent-view-template" "ios" "shellAppBase-builds" "shellAppWorkspaces" "node_modules")
|
||||
|
||||
for LINKNAME in ${LINKS[@]}; do
|
||||
ensure_link_exists "$EXPO_UNIVERSE_DIR/exponent/$LINKNAME" "$WORKINGDIR/$LINKNAME"
|
||||
done
|
||||
}
|
||||
|
||||
setup_remote() {
|
||||
if [[ -d $ROOT_DIR/workingdir/android && -d $ROOT_DIR/workingdir/ios ]]; then
|
||||
@@ -57,7 +55,7 @@ setup_remote() {
|
||||
$ROOT_DIR/scripts/ios/fetchRemoteIosTarball.sh
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
for sdk in $ROOT_DIR/workingdir/android/* ; do
|
||||
if [[ -f "$sdk/universe-package.json" ]]; then
|
||||
mv $sdk/package.json $sdk/exponent-package.json
|
||||
@@ -89,10 +87,8 @@ EOF
|
||||
}
|
||||
|
||||
if [ "$1" == "local" ]; then
|
||||
# setup_local
|
||||
# switch_local
|
||||
echo "Setting local workingdir is currently broken, sorry :("
|
||||
exit -1
|
||||
setup_local
|
||||
switch_local
|
||||
elif [ "$1" == "remote" ]; then
|
||||
setup_remote
|
||||
switch_remote
|
||||
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "Please provide an environment name as a first argument"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$2" ]; then
|
||||
echo "Please provide a pod name as a second argument"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
kubectl --namespace $1 exec -it $2 -- /bin/bash
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
ENVIRONMENT=${1:-production}
|
||||
|
||||
kubectl get pods --namespace $ENVIRONMENT | grep "turtle-android-" | sed -e "s/ */ /g" | cut -d" " -f1
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
ENVIRONMENT=${1:-production}
|
||||
|
||||
govc vm.ip -wait 5s turtle-js-"${ENVIRONMENT}"-*
|
||||
@@ -1 +1 @@
|
||||
s3://exp-artifacts/android-shell-builder-aebd669d6573b0b3c802871d94cdb8b4116678d2.tar.gz
|
||||
s3://exp-artifacts/android-shell-builder-e244e865ed8cb8e20d29ea00b6373845d1c61068.tar.gz
|
||||
@@ -23,15 +23,9 @@ export default (program: any, setCommonCommandOptions: any) => {
|
||||
/^(app-bundle|apk)$/i,
|
||||
'app-bundle',
|
||||
)
|
||||
.option(
|
||||
'-m --mode <build>',
|
||||
'type of build: debug|release',
|
||||
/^(debug|release)$/i,
|
||||
'release',
|
||||
)
|
||||
.description(
|
||||
'Build a standalone APK or App Bundle for your project, either signed and ready for submission to'
|
||||
+ ' the Google Play Store or in debug mode.',
|
||||
'Build a standalone APK or App Bundle for your project, signed and ready for submission to the Google Play'
|
||||
+ ' Store.',
|
||||
)
|
||||
.asyncAction(
|
||||
createBuilderAction({
|
||||
|
||||
@@ -4,7 +4,7 @@ import path from 'path';
|
||||
import decompress from 'decompress';
|
||||
import fs from 'fs-extra';
|
||||
|
||||
import * as utils from 'turtle/bin/setup/utils/common';
|
||||
import { formatArtifactDownloadPath } from 'turtle/bin/setup/utils/common';
|
||||
import download from 'turtle/bin/setup/utils/downloader';
|
||||
import config from 'turtle/config';
|
||||
import logger from 'turtle/logger';
|
||||
@@ -16,10 +16,9 @@ const l = logger.child(LOGGER_FIELDS);
|
||||
|
||||
export default async function ensureAndroidNDKIsPresent() {
|
||||
const androidNdkDir = path.join(config.directories.androidDependenciesDir, 'ndk');
|
||||
await utils.removeDirectoryUnlessReady(androidNdkDir);
|
||||
if (!(await fs.pathExists(androidNdkDir))) {
|
||||
await fs.ensureDir(androidNdkDir);
|
||||
const androidNdkDownloadPath = utils.formatArtifactDownloadPath(ANDROID_NDK_URL);
|
||||
const androidNdkDownloadPath = formatArtifactDownloadPath(ANDROID_NDK_URL);
|
||||
|
||||
try {
|
||||
l.info('Downloading Android NDK');
|
||||
@@ -27,7 +26,6 @@ export default async function ensureAndroidNDKIsPresent() {
|
||||
await download(ANDROID_NDK_URL, androidNdkDownloadPath);
|
||||
l.info('Decompressing Android NDK');
|
||||
await decompress(androidNdkDownloadPath, androidNdkDir, { strip: 1 });
|
||||
await utils.markDirectoryAsReady(androidNdkDir);
|
||||
l.info('Android NDK installed successfully');
|
||||
} catch (err) {
|
||||
await fs.remove(androidNdkDir);
|
||||
|
||||
@@ -5,7 +5,7 @@ import { ExponentTools } from '@expo/xdl';
|
||||
import decompress from 'decompress';
|
||||
import fs from 'fs-extra';
|
||||
|
||||
import * as utils from 'turtle/bin/setup/utils/common';
|
||||
import { formatArtifactDownloadPath } from 'turtle/bin/setup/utils/common';
|
||||
import download from 'turtle/bin/setup/utils/downloader';
|
||||
import config from 'turtle/config';
|
||||
import logger from 'turtle/logger';
|
||||
@@ -17,10 +17,9 @@ const l = logger.child(LOGGER_FIELDS);
|
||||
|
||||
export default async function ensureAndroidSDKIsPresent() {
|
||||
const androidSdkDir = path.join(config.directories.androidDependenciesDir, 'sdk');
|
||||
await utils.removeDirectoryUnlessReady(androidSdkDir);
|
||||
if (!(await fs.pathExists(androidSdkDir))) {
|
||||
await fs.ensureDir(androidSdkDir);
|
||||
const androidSdkDownloadPath = utils.formatArtifactDownloadPath(ANDROID_SDK_URL);
|
||||
const androidSdkDownloadPath = formatArtifactDownloadPath(ANDROID_SDK_URL);
|
||||
|
||||
try {
|
||||
l.info('Downloading Android SDK');
|
||||
@@ -32,7 +31,6 @@ export default async function ensureAndroidSDKIsPresent() {
|
||||
await fs.remove(androidSdkDownloadPath);
|
||||
l.info('Configuring Android SDK, this may take a while');
|
||||
await _configureSdk(androidSdkDir);
|
||||
await utils.markDirectoryAsReady(androidSdkDir);
|
||||
l.info('Android SDK installed and configured successfully');
|
||||
} catch (err) {
|
||||
await fs.remove(androidSdkDir);
|
||||
|
||||
@@ -29,8 +29,6 @@ export async function ensureShellAppIsPresent(
|
||||
postDownloadAction?: PostDownloadAction,
|
||||
) {
|
||||
const workingdir = formatters.formatShellAppDirectory({ sdkVersion });
|
||||
const shellAppMetadata = await _readShellAppTarballS3Uri(sdkVersion, formatters);
|
||||
await removeDirectoryUnlessReady(workingdir, shellAppMetadata);
|
||||
if (await fs.pathExists(workingdir)) {
|
||||
return;
|
||||
}
|
||||
@@ -39,7 +37,6 @@ export async function ensureShellAppIsPresent(
|
||||
if (postDownloadAction) {
|
||||
await postDownloadAction(sdkVersion, workingdir);
|
||||
}
|
||||
await markDirectoryAsReady(workingdir, shellAppMetadata);
|
||||
}
|
||||
|
||||
async function _downloadShellApp(sdkVersion: string, targetDirectory: string, formatters: IShellAppFormaters) {
|
||||
@@ -68,31 +65,3 @@ async function _readShellAppTarballS3Uri(sdkVersion: string, formatters: IShellA
|
||||
const data = await fs.readFile(filePath, 'utf8');
|
||||
return data.trim();
|
||||
}
|
||||
|
||||
export async function removeDirectoryUnlessReady(dir: string, metadata?: string) {
|
||||
const readyFilePath = path.join(dir, '.ready');
|
||||
const readyFileExists = await fs.pathExists(readyFilePath);
|
||||
let shouldRemove = false;
|
||||
if (readyFileExists) {
|
||||
if (metadata !== undefined) {
|
||||
const readyFileContents = (await fs.readFile(readyFilePath, 'utf-8')).trim();
|
||||
if (readyFileContents !== metadata) {
|
||||
shouldRemove = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
shouldRemove = true;
|
||||
}
|
||||
if (shouldRemove) {
|
||||
await fs.remove(dir);
|
||||
}
|
||||
}
|
||||
|
||||
export async function markDirectoryAsReady(dir: string, metadata?: string) {
|
||||
const readyFilePath = path.join(dir, '.ready');
|
||||
if (metadata === undefined) {
|
||||
await fs.open(readyFilePath, 'w');
|
||||
} else {
|
||||
await fs.writeFile(readyFilePath, metadata);
|
||||
}
|
||||
}
|
||||
@@ -57,7 +57,6 @@ export function createBuilderAction({
|
||||
const args = {
|
||||
releaseChannel: cmd.releaseChannel || 'default',
|
||||
buildType: cmd.type,
|
||||
buildMode: cmd.mode,
|
||||
username: userData.username || 'anonymous',
|
||||
projectDir: ProjectUtils.resolveAbsoluteDir(projectDirArg),
|
||||
publicUrl: cmd.publicUrl,
|
||||
@@ -89,14 +88,13 @@ export function createBuilderAction({
|
||||
const buildJobObject = async (
|
||||
platform: 'android' | 'ios',
|
||||
appJSON: any,
|
||||
{ releaseChannel, buildType, buildMode, username, publicUrl, projectDir }: any,
|
||||
{ releaseChannel, buildType, username, publicUrl, projectDir }: any,
|
||||
credentials: any,
|
||||
) => {
|
||||
const job = {
|
||||
config: {
|
||||
..._.get(appJSON, 'expo.ios.config', {}),
|
||||
buildType,
|
||||
...(platform === 'android' ? { buildMode } : {}),
|
||||
releaseChannel,
|
||||
...(platform === 'ios' ? { bundleIdentifier: _.get(appJSON, 'expo.ios.bundleIdentifier') } : {}),
|
||||
...(platform === 'android' ? { androidPackage: _.get(appJSON, 'expo.android.package') } : {}),
|
||||
|
||||
@@ -93,7 +93,6 @@ async function runShellAppBuilder(
|
||||
outputFile: outputFilePath,
|
||||
modules: enabledModules,
|
||||
buildType: jobData.config.buildType,
|
||||
buildMode: jobData.config.buildMode,
|
||||
});
|
||||
} catch (err) {
|
||||
commonUtils.logErrorOnce(err);
|
||||
|
||||
@@ -3,6 +3,7 @@ import path from 'path';
|
||||
import spawnAsync from '@expo/spawn-async';
|
||||
import { IosCodeSigning } from '@expo/xdl';
|
||||
import fs from 'fs-extra';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
|
||||
import * as sqs from 'turtle/aws/sqs';
|
||||
import BuildError, { BuildErrorReason } from 'turtle/builders/BuildError';
|
||||
@@ -20,18 +21,10 @@ async function prepareAdHocBuildCredentials(job: IJob) {
|
||||
}
|
||||
|
||||
const { bundleIdentifier } = job.config;
|
||||
const {
|
||||
certP12,
|
||||
certPassword,
|
||||
teamId,
|
||||
appleSession,
|
||||
udids,
|
||||
provisioningProfileId,
|
||||
} = job.credentials;
|
||||
const { certP12, certPassword, teamId, appleSession, udids } = job.credentials;
|
||||
|
||||
const certSerialNumber = IosCodeSigning.findP12CertSerialNumber(certP12, certPassword);
|
||||
const args = [
|
||||
...(provisioningProfileId ? ['--profile-id', provisioningProfileId] : []),
|
||||
teamId,
|
||||
udids!.join(','),
|
||||
bundleIdentifier,
|
||||
@@ -39,26 +32,25 @@ async function prepareAdHocBuildCredentials(job: IJob) {
|
||||
];
|
||||
|
||||
try {
|
||||
if (provisioningProfileId) {
|
||||
logger.info(
|
||||
`Using ad hoc provisioning profile id: ${provisioningProfileId}`,
|
||||
);
|
||||
}
|
||||
|
||||
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 (!credentials.provisioningProfileUpdateTimestamp) {
|
||||
// dont need to persist profile because nothing changed
|
||||
return;
|
||||
}
|
||||
|
||||
if (isOffline()) {
|
||||
const provisioningProfilePath = path.join(job.projectDir, `adhoc.mobileprovision`);
|
||||
await fs.writeFile(provisioningProfilePath, Buffer.from(credentials.provisioningProfile, 'base64'));
|
||||
|
||||
@@ -5,32 +5,26 @@ import path from 'path';
|
||||
import config from 'turtle/config';
|
||||
import { IJob } from 'turtle/job';
|
||||
|
||||
interface IVersionsMap {
|
||||
[platform: string]: number[];
|
||||
}
|
||||
|
||||
const versions: IVersionsMap = {};
|
||||
let SUPPORTED_SDK_VERSIONS: number[];
|
||||
|
||||
export async function ensureCanBuildSdkVersion(job: IJob) {
|
||||
if (config.builder.useLocalWorkingDir) {
|
||||
return;
|
||||
}
|
||||
|
||||
const platformVersions = await findSupportedSdkVersions(job.platform);
|
||||
if (!SUPPORTED_SDK_VERSIONS) {
|
||||
SUPPORTED_SDK_VERSIONS = await findSupportedSdkVersions(job.platform);
|
||||
}
|
||||
|
||||
const targetMajorSdkVersion = ExponentTools.parseSdkMajorVersion(job.sdkVersion || job.manifest.sdkVersion);
|
||||
if (!platformVersions.includes(targetMajorSdkVersion)) {
|
||||
if (!SUPPORTED_SDK_VERSIONS.includes(targetMajorSdkVersion)) {
|
||||
throw new Error(`Unsupported SDK Version!`);
|
||||
}
|
||||
}
|
||||
|
||||
export async function findSupportedSdkVersions(platform: 'android' | 'ios'): Promise<number[]> {
|
||||
if (versions[platform]) {
|
||||
return versions[platform];
|
||||
} else {
|
||||
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));
|
||||
versions[platform] = sdks.map((sdk) => parseInt(sdk.substr(SDK_DIR_PREFIX.length), 10));
|
||||
return versions[platform];
|
||||
}
|
||||
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));
|
||||
}
|
||||
@@ -16,9 +16,4 @@ export enum ANDROID_BUILD_TYPES {
|
||||
APP_BUNDLE = 'app-bundle',
|
||||
}
|
||||
|
||||
export enum ANDROID_BUILD_MODES {
|
||||
DEBUG = 'debug',
|
||||
RELEASE = 'release',
|
||||
}
|
||||
|
||||
export { BUILD };
|
||||
+1
-3
@@ -1,4 +1,4 @@
|
||||
import { ANDROID_BUILD_MODES, ANDROID_BUILD_TYPES, IOS_BUILD_TYPES } from 'turtle/constants';
|
||||
import { ANDROID_BUILD_TYPES, IOS_BUILD_TYPES } from 'turtle/constants';
|
||||
|
||||
export interface IJob {
|
||||
platform: 'android' | 'ios';
|
||||
@@ -14,7 +14,6 @@ export interface IJob {
|
||||
bundleIdentifier?: string;
|
||||
// android
|
||||
androidPackage?: string;
|
||||
buildMode?: ANDROID_BUILD_MODES;
|
||||
};
|
||||
credentials: {
|
||||
// android
|
||||
@@ -26,7 +25,6 @@ export interface IJob {
|
||||
certP12?: string;
|
||||
certPassword?: string;
|
||||
provisioningProfile?: string;
|
||||
provisioningProfileId?: string;
|
||||
teamId?: string;
|
||||
appleSession?: string;
|
||||
udids?: string[];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Joi from 'joi';
|
||||
|
||||
import { ANDROID_BUILD_MODES, ANDROID_BUILD_TYPES, PLATFORMS } from 'turtle/constants';
|
||||
import { PLATFORMS } from 'turtle/constants';
|
||||
import baseJobSchema from 'turtle/jobsSchemas/base';
|
||||
|
||||
export default baseJobSchema.concat(
|
||||
@@ -12,9 +12,5 @@ export default baseJobSchema.concat(
|
||||
keystoreAlias: Joi.string(),
|
||||
keystore: Joi.string(),
|
||||
}),
|
||||
config: Joi.object().keys({
|
||||
buildMode: Joi.string().valid(Object.values(ANDROID_BUILD_MODES)).default(ANDROID_BUILD_MODES.RELEASE),
|
||||
buildType: Joi.string().valid(Object.values(ANDROID_BUILD_TYPES)).default(ANDROID_BUILD_TYPES.APK),
|
||||
}),
|
||||
}),
|
||||
);
|
||||
@@ -17,7 +17,6 @@ export default baseJobSchema.concat(
|
||||
teamId: Joi.string().required(),
|
||||
// it's not required for adhoc Expo Client builds
|
||||
provisioningProfile: Joi.string(),
|
||||
provisioningProfileId: Joi.string(),
|
||||
appleSession: Joi.string(),
|
||||
udids: Joi.array().items(Joi.string()),
|
||||
})
|
||||
|
||||
@@ -17,7 +17,6 @@ class Logger {
|
||||
name: 'turtle',
|
||||
level: config.logger.level,
|
||||
platform: config.platform,
|
||||
serializers: bunyan.stdSerializers,
|
||||
...config.deploymentEnv && { environment: config.deploymentEnv },
|
||||
streams: Object.values(streams),
|
||||
});
|
||||
|
||||
@@ -12,14 +12,7 @@ const createModeMetricName = (mode: TurtleModeLabels) => `${createMetricName()}.
|
||||
const createModeTag = (mode: TurtleModeLabels) => `mode:${mode}`;
|
||||
|
||||
export default async function sendConfigToDatadog() {
|
||||
let configuration;
|
||||
try {
|
||||
configuration = await getLabeledConfiguration();
|
||||
} catch (err) {
|
||||
logger.warn('Failed to send the builders configuration to Datadog because it couldn\'t be fetched from Redis');
|
||||
return;
|
||||
}
|
||||
|
||||
const configuration = await getLabeledConfiguration();
|
||||
const replicaCount = await getReplicaCount();
|
||||
const currentReplicaCount = replicaCount === null ? configuration.length : replicaCount;
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
|
||||
import { PLATFORMS } from 'turtle/constants';
|
||||
import logger from 'turtle/logger';
|
||||
import {
|
||||
createConfigurationsKey,
|
||||
createDefaultConfigurationKey,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_ONLY_CONFIGURATION,
|
||||
} from 'turtle/utils/priorities';
|
||||
import { connect, RedisClient } from 'turtle/utils/redis';
|
||||
|
||||
const TIMEOUT = 3000;
|
||||
|
||||
// Turtle before doing anything (and after every build) checks for the first config
|
||||
// (an element in config table with key=i) that is not taken (config.i is null/outdated)
|
||||
// or is taken by this process itself.
|
||||
// If Turtle dies unexpectedly the configuration will become free after TTL expires,
|
||||
// so the state (number of HP/NP turtles) should come back to normal soon.
|
||||
|
||||
// For example, if a configuration table looks like this:
|
||||
// [ HIGH_CONFIGURATION, NORMAL_CONFIGURATION, HIGH_CONFIGURATION ]
|
||||
// If there is one turtle it runs with High Priority first.
|
||||
// If there are two turtles, one runs with High Priority first, the second one with Normal Priority first.
|
||||
// If the first dies, and the third is started in his place, it gets 3rd config (again HP-first),
|
||||
// but after some time, because of TTL for config reservations,
|
||||
// they should come back to using configurations no. 1 and 2.
|
||||
// If there are no more available configurations from the table, the default configuration is used.
|
||||
|
||||
const AVAILABLE_CONFIGURATIONS_IOS = [
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_ONLY_CONFIGURATION,
|
||||
HIGH_ONLY_CONFIGURATION,
|
||||
HIGH_ONLY_CONFIGURATION,
|
||||
// there are 5 iOS builders at the moment
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
];
|
||||
|
||||
const AVAILABLE_CONFIGURATIONS_ANDROID = [
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
// there are 15 Android builders at the moment
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
];
|
||||
|
||||
const DEFAULT_CONFIGURATION = HIGH_CONFIGURATION;
|
||||
|
||||
async function run() {
|
||||
const redis = await connect(TIMEOUT, RedisClient.Configuration);
|
||||
|
||||
await redis.set(createConfigurationsKey(PLATFORMS.IOS), JSON.stringify(AVAILABLE_CONFIGURATIONS_IOS));
|
||||
await redis.set(createConfigurationsKey(PLATFORMS.ANDROID), JSON.stringify(AVAILABLE_CONFIGURATIONS_ANDROID));
|
||||
await redis.set(createDefaultConfigurationKey(PLATFORMS.IOS), JSON.stringify(DEFAULT_CONFIGURATION));
|
||||
await redis.set(createDefaultConfigurationKey(PLATFORMS.ANDROID), JSON.stringify(DEFAULT_CONFIGURATION));
|
||||
|
||||
redis.disconnect();
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
run()
|
||||
.then(() => logger.info('All done'))
|
||||
.catch((err) => logger.error('Error:', err));
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import isNaN from 'lodash/isNaN';
|
||||
|
||||
import { PLATFORMS } from 'turtle/constants';
|
||||
import logger from 'turtle/logger';
|
||||
import { setReplicaCount } from 'turtle/utils/metadata';
|
||||
import { getRedisClient, RedisClient } from 'turtle/utils/redis';
|
||||
|
||||
async function run() {
|
||||
const platform = process.env.SCRIPT_PLATFORM;
|
||||
const replicaCountRaw = process.env.SCRIPT_REPLICA_COUNT;
|
||||
const replicaCount = Number(replicaCountRaw);
|
||||
|
||||
if (!platform || !replicaCountRaw) {
|
||||
throw new Error('You must set both SCRIPT_PLATFORM and SCRIPT_REPLICA_COUNT env variables.');
|
||||
}
|
||||
|
||||
if (!Object.values(PLATFORMS).includes(platform)) {
|
||||
throw new Error(`Unsupported platform: ${platform}`);
|
||||
}
|
||||
|
||||
if (isNaN(replicaCount)) {
|
||||
throw new Error(`Wrong value for replica count: ${replicaCountRaw}`);
|
||||
}
|
||||
|
||||
const redis = await getRedisClient(RedisClient.Configuration);
|
||||
logger.info(`[${platform}] Setting replica count in redis to ${replicaCount}`);
|
||||
await setReplicaCount(platform as PLATFORMS, replicaCount);
|
||||
redis.disconnect();
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
run()
|
||||
.then(() => logger.info('All done'))
|
||||
.catch((err) => {
|
||||
logger.error('Error:', err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
+5
-14
@@ -1,15 +1,13 @@
|
||||
import { LoggerDetach } from '@expo/xdl';
|
||||
|
||||
import { findSupportedSdkVersions } from 'turtle/builders/utils/version';
|
||||
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 } from 'turtle/utils/redis';
|
||||
import { getRedisClient, RedisClient } from 'turtle/utils/redis';
|
||||
|
||||
const REDIS_TURTLE_VERSION_KEY = 'turtle:version';
|
||||
const REDIS_TURTLE_SUPPORTED_SDK_VERSIONS_KEY = `turtle:${config.platform}:sdkVersions`;
|
||||
|
||||
process.on('unhandledRejection', (err) => logger.error({ err }, 'Unhandled promise rejection'));
|
||||
|
||||
@@ -37,18 +35,11 @@ async function main() {
|
||||
}
|
||||
|
||||
try {
|
||||
const redis = await getRedisClient();
|
||||
if (redis) {
|
||||
await redis.set(REDIS_TURTLE_VERSION_KEY, turtleVersion);
|
||||
logger.info(`Registered Turtle version (${turtleVersion}) in Redis`);
|
||||
const sdkVersions = (await findSupportedSdkVersions(config.platform)).join(',');
|
||||
await redis.set(REDIS_TURTLE_SUPPORTED_SDK_VERSIONS_KEY, sdkVersions);
|
||||
logger.info(`Registered supported SDK versions (${sdkVersions}) in Redis`);
|
||||
} else {
|
||||
logger.warn('Couldn\'t set supported SDK versions in Redis (failed to connect to Redis)');
|
||||
}
|
||||
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({ err }, 'Failed to set versions in Redis');
|
||||
logger.error({ err }, 'Failed to register Turtle version in Redis');
|
||||
}
|
||||
|
||||
while (true) {
|
||||
|
||||
@@ -5,6 +5,14 @@ import { getRedisClient, RedisClient } from 'turtle/utils/redis';
|
||||
const createKeyPrefix = (platform: PLATFORMS) => `${config.deploymentEnv}:${platform}`;
|
||||
const createReplicaCountKey = (platform: PLATFORMS) => `${createKeyPrefix(platform)}:replicaCount`;
|
||||
|
||||
export async function setReplicaCount(platform: PLATFORMS, replicaCount: number) {
|
||||
const redis = await getRedisClient(RedisClient.Configuration);
|
||||
await redis.set(
|
||||
createReplicaCountKey(platform),
|
||||
replicaCount,
|
||||
);
|
||||
}
|
||||
|
||||
export async function getReplicaCount(maybePlatform?: PLATFORMS) {
|
||||
const platform = maybePlatform || config.platform;
|
||||
const redis = await getRedisClient(RedisClient.Configuration);
|
||||
|
||||
@@ -49,7 +49,7 @@ export function createDefaultConfigurationKey(platform = config.platform) {
|
||||
}
|
||||
|
||||
export async function getPriorities() {
|
||||
if (config.env === 'test' || config.deploymentEnv === 'development') {
|
||||
if (config.env === 'test') {
|
||||
return NORMAL_CONFIGURATION;
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ export async function getPriorities() {
|
||||
}
|
||||
}
|
||||
|
||||
async function getConfiguration(currentRedisClient: any) {
|
||||
export async function getConfiguration(currentRedisClient: any) {
|
||||
const redis = currentRedisClient || await getRedisClient(RedisClient.Configuration);
|
||||
return JSON.parse(await redis.get(createConfigurationsKey()));
|
||||
}
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@ export async function checkIfCancelled(jobId: string) {
|
||||
return await redis.get(`jobs:cancelled:${jobId}`);
|
||||
} catch (err) {
|
||||
if (config.deploymentEnv === 'development') {
|
||||
logger.warn('Did you turn on redis server? Run `yarn start-docker` in $EXPO_UNIVERSE_DIR/server/www');
|
||||
logger.warn('Did you turn on redis server? Run `yarn start-docker` in server/www');
|
||||
}
|
||||
logger.error({ err });
|
||||
return false;
|
||||
|
||||
@@ -7,10 +7,6 @@ command=node ./build/server.js
|
||||
autorestart=true
|
||||
startretries=5
|
||||
startsecs=600
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
|
||||
[eventlistener:turtle_failure]
|
||||
events=PROCESS_STATE_FATAL
|
||||
|
||||
Reference in new issue
Block a user