mirror of
https://github.com/expo/turtle.git
synced 2026-11-14 19:12:55 -10:00
Compare commits
53
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
abfd7ea0f0 | ||
|
|
62478de14a | ||
|
|
6594089779 | ||
|
|
11c5d3ee02 | ||
|
|
99b7ac6660 | ||
|
|
46fe34ed9c | ||
|
|
423fc8bbf5 | ||
|
|
4c8408a46b | ||
|
|
032d7c8b1f | ||
|
|
b2a0b3ce14 | ||
|
|
1ee922763e | ||
|
|
c31cd379c1 | ||
|
|
67754eba2a | ||
|
|
351fed00df | ||
|
|
487032b11d | ||
|
|
042dd2ccab | ||
|
|
99ae0d1cea | ||
|
|
ad2c87163b | ||
|
|
b4b9cf362e | ||
|
|
7ea4dac986 | ||
|
|
cd8da71711 | ||
|
|
2a2a0f39e0 | ||
|
|
fbabcdf521 | ||
|
|
0803811226 | ||
|
|
0976a642e1 | ||
|
|
16bd4fe7b6 | ||
|
|
3ccd705943 | ||
|
|
11cc4421dd | ||
|
|
32f5a0bb37 | ||
|
|
61a1906e01 | ||
|
|
19a17231b3 | ||
|
|
98c03bc8a2 | ||
|
|
83ab2539c1 | ||
|
|
064619e1ae | ||
|
|
b7fe01b758 | ||
|
|
6583b1a1db | ||
|
|
f24081cb91 | ||
|
|
4e719a200b | ||
|
|
0b13494402 | ||
|
|
0ca26a40aa | ||
|
|
f171913bac | ||
|
|
b47ee91117 | ||
|
|
77cb28ce66 | ||
|
|
7a2453cf53 | ||
|
|
924908905f | ||
|
|
798b4acca6 | ||
|
|
2303b44dd2 | ||
|
|
c204e0bef2 | ||
|
|
0918d8299e | ||
|
|
3543acfb26 | ||
|
|
42b6ff634c | ||
|
|
fcd42b272f | ||
|
|
ecaef3a91d |
No files matched your search
@@ -9,7 +9,7 @@ executors:
|
||||
working_directory: ~/turtle
|
||||
mac:
|
||||
macos: # https://circleci.com/docs/2.0/testing-ios/#supported-xcode-versions
|
||||
xcode: '11.1.0'
|
||||
xcode: "11.1.0"
|
||||
working_directory: /Users/distiller/project
|
||||
shell: /bin/bash -leo pipefail
|
||||
android:
|
||||
@@ -57,8 +57,8 @@ commands:
|
||||
- run:
|
||||
name: Configure aws-cli
|
||||
command: |
|
||||
aws configure set aws_access_key_id $AWS_ACCESS_KEY_ID
|
||||
aws configure set aws_secret_access_key $AWS_SECRET_ACCESS_KEY
|
||||
aws configure set aws_access_key_id $AWS_ACCESS_KEY_ID
|
||||
aws configure set aws_secret_access_key $AWS_SECRET_ACCESS_KEY
|
||||
|
||||
setup_nix:
|
||||
steps:
|
||||
@@ -141,7 +141,7 @@ commands:
|
||||
default: linux
|
||||
steps:
|
||||
- restore_cache:
|
||||
key: yarn-v2-<< parameters.platform >>-{{ checksum "<< parameters.workingdir >>/yarn.lock" }}
|
||||
key: yarn-v3-<< parameters.platform >>-{{ checksum "<< parameters.workingdir >>/yarn.lock" }}
|
||||
|
||||
save_yarn_cache:
|
||||
parameters:
|
||||
@@ -153,7 +153,7 @@ commands:
|
||||
default: linux
|
||||
steps:
|
||||
- save_cache:
|
||||
key: yarn-v2-<< parameters.platform >>-{{ checksum "<< parameters.workingdir >>/yarn.lock" }}
|
||||
key: yarn-v3-<< parameters.platform >>-{{ checksum "<< parameters.workingdir >>/yarn.lock" }}
|
||||
paths:
|
||||
- ~/.cache/yarn # `yarn cache dir`
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ google-cloud-credentials.json
|
||||
/workingdir/*
|
||||
/artifacts/*
|
||||
.history
|
||||
.vscode/
|
||||
|
||||
shell.apk
|
||||
.secrets*
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
"release": true
|
||||
},
|
||||
"hooks": {
|
||||
"before:init": [
|
||||
"yarn"
|
||||
],
|
||||
"after:release": "yarn release:update:turtle-cli-example"
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,95 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Added
|
||||
|
||||
- Added Android shell app for SDK 39.
|
||||
|
||||
## [0.17.3] - 2020-09-14
|
||||
|
||||
### Added
|
||||
|
||||
- Added gradle 6.2 to `turtle-android-base`
|
||||
- Added `ANDROID_NDK_HOME` in `turtle-android-base`
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgraded XDL so it processes root `build.gradle` of Android shell apps too
|
||||
|
||||
## [0.17.2] - 2020-08-06
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated iOS shell app for SDK 38 with fixed integer tagging in expo-gl for iOS 14. ([#245](https://github.com/expo/turtle/pull/245))
|
||||
|
||||
## [0.17.1] - 2020-08-05
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated Android shell app for SDK 38 with `targetSdkVersion` bumped to 29. ([#244](https://github.com/expo/turtle/pull/244))
|
||||
|
||||
## [0.17.0] - 2020-07-16
|
||||
|
||||
### Added
|
||||
|
||||
- `--gradle-args` option for `turtle build:android` which makes it possible to specify custom Gradle arguments.
|
||||
|
||||
### Changed
|
||||
|
||||
- Gradle Wrapper doesn't print when dots when the appropriate version of Gradle is being downloaded.
|
||||
|
||||
## [0.16.2] - 2020-07-01
|
||||
|
||||
### Added
|
||||
|
||||
- Added `--allow-non-https-public-url` to allow bypass of protocol validation on `--public-url`.
|
||||
- Added support for dynamic configs (`app.config.ts`, `app.config.js`).
|
||||
|
||||
## [0.16.0] - 2020-06-25
|
||||
|
||||
### Added
|
||||
|
||||
- Added iOS shell app for Expo SDK38.
|
||||
- Added Android shell app for SDK 38.
|
||||
|
||||
### Removed
|
||||
|
||||
- Dropped support for SDK 34.
|
||||
|
||||
## [0.15.1] - 2020-06-22
|
||||
|
||||
### Changed
|
||||
|
||||
- Configure Turtle to use the Redis CA certificate.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix announcing supported SDK versions.
|
||||
|
||||
## [0.15.0] - 2020-06-02
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated `@expo/xdl` to 57.9.13 (added \*.bak files clean-up when building .ipa).
|
||||
|
||||
## [0.14.12] - 2020-05-14
|
||||
|
||||
### Changed
|
||||
|
||||
- Update iOS custom client shell app with various fixes.
|
||||
|
||||
## [0.14.11] - 2020-05-04
|
||||
|
||||
### Changed
|
||||
|
||||
- Update SDK 37 iOS shell app with various fixes.
|
||||
|
||||
## [0.14.10] - 2020-05-01
|
||||
|
||||
### Added
|
||||
|
||||
- support for "android.enableDangerousExperimentalLeanBuilds" in app.json.
|
||||
|
||||
## [0.14.9] - 2020-04-21
|
||||
|
||||
### Changed
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
## 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 `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_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
|
||||
|
||||
+12
-11
@@ -1,5 +1,5 @@
|
||||
# see docker-base/Dockerfile to learn what's installed in the turtle-android-base image
|
||||
FROM gcr.io/exponentjs/turtle-android-base:0.4.0
|
||||
FROM gcr.io/exponentjs/turtle-android-base:0.5.0
|
||||
|
||||
ADD . /app/turtle
|
||||
|
||||
@@ -8,20 +8,21 @@ WORKDIR /app/turtle
|
||||
RUN ./scripts/fetchRemoteTarballs.sh android
|
||||
|
||||
RUN ln -s /app/turtle/workingdir /app/workingdir && \
|
||||
for SDK_VERSION in `ls /app/workingdir/android/`; do \
|
||||
echo "preparing $SDK_VERSION shell app" && \
|
||||
cd /app/workingdir/android/$SDK_VERSION && \
|
||||
mv packages non-workspace-packages && \
|
||||
# Keep in sync with src/bin/setup/android/index.ts#_installNodeModules
|
||||
# --prod requires --ignore-scripts (otherwise
|
||||
# expo-yarn-workspaces errors as missing)
|
||||
yarn install --ignore-scripts --prod && \
|
||||
mv non-workspace-packages packages ; \
|
||||
done
|
||||
for SDK_VERSION in `ls /app/workingdir/android/`; do \
|
||||
echo "preparing $SDK_VERSION shell app" && \
|
||||
cd /app/workingdir/android/$SDK_VERSION && \
|
||||
mv packages non-workspace-packages && \
|
||||
# Keep in sync with src/bin/setup/android/index.ts#_installNodeModules
|
||||
# --prod requires --ignore-scripts (otherwise
|
||||
# expo-yarn-workspaces errors as missing)
|
||||
yarn install --ignore-scripts --prod && \
|
||||
mv non-workspace-packages packages ; \
|
||||
done
|
||||
|
||||
ENV NODE_ENV "production"
|
||||
ENV TURTLE_WORKING_DIR_PATH /app/turtle/workingdir/
|
||||
|
||||
ADD supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||
ADD redislabs_ca.pem /var/run/config/redislabs-tls/redislabs_ca.pem
|
||||
|
||||
CMD ["/usr/bin/supervisord"]
|
||||
@@ -57,10 +57,23 @@ ENV PATH ${ANDROID_HOME}/build-tools/28.0.3/:${PATH}
|
||||
|
||||
ADD configureAndroidSdk.sh /tmp/configureAndroidSdk.sh
|
||||
RUN /tmp/configureAndroidSdk.sh --install-all-platforms
|
||||
ENV ANDROID_NDK_HOME /usr/local/android-sdk-linux/ndk/17.2.4988734
|
||||
|
||||
# Support Gradle
|
||||
ENV TERM dumb
|
||||
|
||||
# Install gradle 6.2
|
||||
RUN wget https://services.gradle.org/distributions/gradle-6.2-all.zip
|
||||
RUN unzip -qq gradle-6.2-all.zip
|
||||
RUN cp -r gradle-6.2 /usr/local
|
||||
|
||||
RUN mkdir -p /root/.gradle/wrapper/dists/gradle-6.2-all/dvufqs6kielxeao781pmk5huj
|
||||
RUN mv gradle-6.2-all.zip /root/.gradle/wrapper/dists/gradle-6.2-all/dvufqs6kielxeao781pmk5huj
|
||||
RUN mv gradle-6.2 /root/.gradle/wrapper/dists/gradle-6.2-all/dvufqs6kielxeao781pmk5huj
|
||||
RUN touch /root/.gradle/wrapper/dists/gradle-6.2-all/dvufqs6kielxeao781pmk5huj/gradle-6.2-all.zip.ok
|
||||
RUN touch /root/.gradle/wrapper/dists/gradle-6.2-all/dvufqs6kielxeao781pmk5huj/gradle-6.2-all.zip.lck
|
||||
RUN chmod 755 /root/.gradle/wrapper/dists/gradle-6.2-all/dvufqs6kielxeao781pmk5huj/gradle-6.2/bin/gradle
|
||||
|
||||
# Install gradle 5.6.3
|
||||
RUN wget https://services.gradle.org/distributions/gradle-5.6.3-all.zip
|
||||
RUN unzip -qq gradle-5.6.3-all.zip
|
||||
|
||||
@@ -88,11 +88,6 @@ spec:
|
||||
secretKeyRef:
|
||||
name: turtle-js-config
|
||||
key: aws_sqs_android_priority_queue_url
|
||||
- name: AWS_SQS_OUT_QUEUE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: turtle-js-config
|
||||
key: aws_sqs_out_queue_url
|
||||
- name: AWS_CLOUDWATCH_REGION
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
@@ -149,9 +144,11 @@ spec:
|
||||
- name: DISABLE_DEX_MAX_HEAP
|
||||
value: "true"
|
||||
- name: JAVA_OPTS
|
||||
value: '-Xms2048m -XX:+HeapDumpOnOutOfMemoryError -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:+UseG1GC'
|
||||
value: '-Xms2048m -Xmx8192m -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC'
|
||||
- name: GRADLE_OPTS
|
||||
value: '-Dorg.gradle.parallel=true -Dorg.gradle.configureondemand=true -Dorg.gradle.daemon=false -Dorg.gradle.jvmargs="-Xms2048m -XX:+HeapDumpOnOutOfMemoryError -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:+UseG1GC"'
|
||||
value: '-Dorg.gradle.parallel=true -Dorg.gradle.configureondemand=true -Dorg.gradle.daemon=false -Dorg.gradle.jvmargs="-Xms2048m -Xmx8192m -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC"'
|
||||
- name: REDIS_CA_CERTIFICATE
|
||||
value: '/var/run/config/redislabs-tls/redislabs_ca.pem'
|
||||
resources:
|
||||
requests:
|
||||
memory: "8192Mi"
|
||||
|
||||
+9
-7
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "turtle-cli",
|
||||
"version": "0.14.9",
|
||||
"version": "0.17.3",
|
||||
"description": "The command-line tool for building standalone Expo apps",
|
||||
"preferGlobal": true,
|
||||
"scripts": {
|
||||
@@ -70,9 +70,11 @@
|
||||
"@expo/babel-preset-cli": "^0.1.3",
|
||||
"@types/decompress": "^4.2.3",
|
||||
"@types/fs-extra": "^5.0.4",
|
||||
"@types/ioredis": "^4.16.6",
|
||||
"@types/jest": "^23.3.9",
|
||||
"@types/joi": "^13.4.3",
|
||||
"@types/lodash": "^4.14.129",
|
||||
"@types/node-forge": "^0.8.6",
|
||||
"@types/npm-package-arg": "^6.1.0",
|
||||
"@types/progress": "^2.0.1",
|
||||
"@types/raven": "^2.5.1",
|
||||
@@ -86,25 +88,25 @@
|
||||
"@types/webpack-dev-server": "^3.1.7",
|
||||
"@types/which": "^1.3.1",
|
||||
"husky": "^1.3.1",
|
||||
"jest": "^25.1.0",
|
||||
"jest": "^26.1.0",
|
||||
"lint-staged": "^8.1.5",
|
||||
"nock": "^10.0.1",
|
||||
"nodemon": "^2.0.2",
|
||||
"release-it": "^12.3.4",
|
||||
"rimraf": "^2.6.2",
|
||||
"ts-jest": "^25.2.1",
|
||||
"ts-jest": "^26.1.2",
|
||||
"ts-node": "^8.0.3",
|
||||
"ts-transformer-imports": "^0.4.1",
|
||||
"tsconfig-paths": "^3.8.0",
|
||||
"tslint": "^5.10.0",
|
||||
"tslint-eslint-rules": "^5.4.0",
|
||||
"ttypescript": "^1.5.6",
|
||||
"typescript": "^3.4.2"
|
||||
"typescript": "^3.9.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@expo/config": "^3.0.5",
|
||||
"@expo/config": "^3.2.14",
|
||||
"@expo/spawn-async": "^1.4.2",
|
||||
"@expo/xdl": "57.8.30",
|
||||
"@expo/xdl": "57.9.35",
|
||||
"@google-cloud/logging-bunyan": "^2.0.3",
|
||||
"async-retry": "^1.2.1",
|
||||
"aws-sdk": "^2.226.1",
|
||||
@@ -116,7 +118,7 @@
|
||||
"decompress": "^4.2.0",
|
||||
"dogapi": "^2.8.3",
|
||||
"fs-extra": "^6.0.0",
|
||||
"ioredis": "^3.2.2",
|
||||
"ioredis": "^4.17.3",
|
||||
"is-semver": "^1.0.8",
|
||||
"joi": "^13.2.0",
|
||||
"lodash": "^4.17.11",
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
this is just a placeholder to simplify deployments
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ -z "$EXPO_UNIVERSE_DIR" ]; then
|
||||
echo "You need to specify EXPO_UNIVERSE_DIR to use this script. Alternatively you can create .secrets.local-queue file yourself with AWS_SQS_ANDROID_QUEUE_URL, AWS_SQS_IOS_QUEUE_URL and AWS_SQS_OUT_QUEUE_URL variables."
|
||||
echo "You need to specify EXPO_UNIVERSE_DIR to use this script. Alternatively you can create .secrets.local-queue file yourself with AWS_SQS_ANDROID_QUEUE_URL and AWS_SQS_IOS_QUEUE_URL variables."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -17,13 +17,11 @@ ANDROID_NORMAL=`cd $TERRAFORM_DIR; terraform state show module.turtle_queues_loc
|
||||
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`
|
||||
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_OUT_QUEUE_URL="$OUT"
|
||||
EOF
|
||||
|
||||
@@ -7,7 +7,7 @@ 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."
|
||||
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, and AWS_SQS_IOS_PRIORITY_QUEUE_URL variables."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ export AWS_SQS_ANDROID_QUEUE_URL="https://sqs.us-west-2.amazonaws.com/2742511416
|
||||
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_REGION="aws.west2"
|
||||
export AWS_S3_BUCKET="exp-shell-app-assets"
|
||||
export AWS_S3_REGION="us-west-1"
|
||||
|
||||
@@ -9,7 +9,6 @@ export AWS_SQS_ANDROID_QUEUE_URL="https://sqs.us-west-2.amazonaws.com/2742511416
|
||||
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_REGION="aws.west2"
|
||||
export AWS_S3_BUCKET="exp-shell-app-assets"
|
||||
export AWS_S3_REGION="us-west-1"
|
||||
|
||||
@@ -9,7 +9,6 @@ export AWS_SQS_IOS_QUEUE_URL="noop"
|
||||
export AWS_SQS_ANDROID_QUEUE_URL="noop"
|
||||
export AWS_SQS_IOS_PRIORITY_QUEUE_URL="noop"
|
||||
export AWS_SQS_ANDROID_PRIORITY_QUEUE_URL="noop"
|
||||
export AWS_SQS_OUT_QUEUE_URL="noop"
|
||||
export AWS_ACCESS_KEY_ID="noop"
|
||||
export AWS_SECRET_ACCESS_KEY="noop"
|
||||
export AWS_SQS_REGION="noop"
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/android-shell-builder-a8e204610e5712391336b378f47962bbb0c04164.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
s3://exp-artifacts/android-shell-builder-6cde8e00cd7bdf7a933cd8aad7f8e86981ea68a2.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
s3://exp-artifacts/android-shell-builder-29a8a376760deecc41efffc0d8ae420a63559654.tar.gz
|
||||
@@ -1 +1 @@
|
||||
s3://exp-artifacts/ios-expo-client-aadfc350d8e4ebf8dce9ce08723bb7e07d563846.tar.gz
|
||||
s3://exp-artifacts/ios-expo-client-18a58afe742e63f1d2ac71ba21404d8b84e6563e.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-651588ff3445a5d87b3a5b81ec2977c02b22f3a2.tar.gz
|
||||
@@ -1 +1 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-549b9da7f764c6b75741aad3cd29a53aba809516.tar.gz
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-30eb0558ff6a77acf56bb045e98b84f6a5e1478a.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-6cde8e00cd7bdf7a933cd8aad7f8e86981ea68a2.tar.gz
|
||||
@@ -1 +1 @@
|
||||
[{"scope":"https://sqs.us-west-2.amazonaws.com:443","method":"POST","path":"/","body":"Action=ReceiveMessage&MaxNumberOfMessages=1&QueueUrl=https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F274251141632%2Fturtle_jobs_local_dominik_android_in.fifo&Version=2012-11-05&VisibilityTimeout=30","status":200,"response":"<?xml version=\"1.0\"?><ReceiveMessageResponse xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\"><ReceiveMessageResult/><ResponseMetadata><RequestId>2f9926f3-9db4-588e-a00a-71f445522996</RequestId></ResponseMetadata></ReceiveMessageResponse>","rawHeaders":["x-amzn-RequestId","2f9926f3-9db4-588e-a00a-71f445522996","Date","Wed, 08 Apr 2020 13:50:35 GMT","Content-Type","text/xml","Content-Length","240"]},{"scope":"https://sqs.us-west-2.amazonaws.com:443","method":"POST","path":"/","body":"Action=ReceiveMessage&MaxNumberOfMessages=1&QueueUrl=https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F274251141632%2Fturtle_jobs_local_dominik_android_in_priority.fifo&Version=2012-11-05&VisibilityTimeout=30","status":200,"response":"<?xml version=\"1.0\"?><ReceiveMessageResponse xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\"><ReceiveMessageResult/><ResponseMetadata><RequestId>e42b6179-9846-5d83-9209-367e40aa9c02</RequestId></ResponseMetadata></ReceiveMessageResponse>","rawHeaders":["x-amzn-RequestId","e42b6179-9846-5d83-9209-367e40aa9c02","Date","Wed, 08 Apr 2020 13:50:41 GMT","Content-Type","text/xml","Content-Length","240"]},{"scope":"https://sqs.us-west-2.amazonaws.com:443","method":"POST","path":"/","body":"Action=ReceiveMessage&MaxNumberOfMessages=1&QueueUrl=https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F274251141632%2Fturtle_jobs_local_dominik_android_in.fifo&Version=2012-11-05&VisibilityTimeout=30","status":200,"response":"<?xml version=\"1.0\"?><ReceiveMessageResponse xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\"><ReceiveMessageResult><Message><MessageId>093d5a52-932c-4141-958a-4ee8146dadab</MessageId><ReceiptHandle>AQEBq2BDKWkc+YFuyL+qBVQ6RCqne9ndyzDri6BeHTv+HhCU3kOlINEzzqbgrGJXh49AB6lVInGNsI+uc5uMhC61UscDKfFeqgfhDDUftovz6RXwiIj+xRalgP5fPZn94LbY4KmUoCuGCpXu9UlGxOoorYTkLft9AVY6kabCRlXA8SJzzYjUb1s+rtBoWS3Trj/AOIxOy0EqxeEWpBsNKc1yWc9RNbZ8/qABFLMjOzdmr5gaLEDoRJTUZZUEu9TVOxrC54ES+UaCmgVY17Ubmwo884GbHLoyUA+xqSD0Cvify5GCv3xzB+wjB4gGdGUFdOjj</ReceiptHandle><MD5OfBody>f0cb57fa399d2c8e81f8423e93127bdc</MD5OfBody><Body>{"id":"1b148a0a-4a5e-4572-b28a-c31aa018351a","experienceId":"0128bca1-78cf-4cb8-ac00-c07600500254","experienceName":"@dsokal-local/turtle-cli-example","platform":"android","config":{"releaseChannel":"default","buildType":"apk"},"status":"sent-to-queue","sdkVersion":"37.0.0","accountId":"9b473c78-6d0e-4b69-88a8-1c0960287b2f","priority":"normal","credentials":{"keystore":"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 truncated
|
||||
[{"scope":"https://sqs.us-west-2.amazonaws.com:443","method":"POST","path":"/","body":"Action=ReceiveMessage&MaxNumberOfMessages=1&QueueUrl=https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F274251141632%2Fturtle_jobs_local_dominik_android_in.fifo&Version=2012-11-05&VisibilityTimeout=30","status":200,"response":"<?xml version=\"1.0\"?><ReceiveMessageResponse xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\"><ReceiveMessageResult><Message><MessageId>f5017f35-ce75-4a6c-acaf-4ccc3d73899f</MessageId><ReceiptHandle>AQEBQjEPeX13Rkr+iSNEuh9J+WKCinb45vRFxWMojfZlD8f5gXi1fncRIotDjji9Q5lkhEK6hjXnALwGXZTstFj3/EPMVV2MKPNN/6NA3cQ7wSd5/+EqP8ZFOC+wBBK46KdS82t46NJ3c0DqkXPImlUE7O2n1WnFiRrjJ+I/G7yYhf+rnxLoNWD8ZPFzzInr6K0Q4Fae8Wqowyc9N8dw2kksnzW3qto+W/Ped1MyF4/Ia6KBqPLQswHRI5WRrqxxaVKdi37XxHW1J71xxEskicTlSBqQmre+3gaCja6cDpXkBtQSNp1LC7nvt/OXZTmXvwtM</ReceiptHandle><MD5OfBody>792da27a1e1bc549ed89f35a5f66e38c</MD5OfBody><Body>{"id":"cd9ff227-575b-4eec-874f-d2b9f6187f05","experienceId":"da491dac-c6bf-4d54-b67a-ba7890e22fb2","experienceName":"@dsokal-local/turtle-cli-example","platform":"android","config":{"releaseChannel":"default","buildType":"apk"},"status":"sent-to-queue","sdkVersion":"37.0.0","accountId":"fbd6360b-e85d-485e-bf20-ab66adfeea16","priority":"normal","credentials":{"keystore":"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","keystorePassword":"28eeeda02db44ed9afc1c1d4a0f2caa6","keystoreAlias":"QGV4cG8tdHVydGxlL3R1cnRsZS1jbGktZXhhbXBsZQ==","keyPassword":"a6a53453c5534673900dac983e40a693"},"manifest":{"ios":{"buildNumber":"13","supportsTablet":true,"bundleIdentifier":"com.expo.turtle.cli.example"},"icon":"./assets/icon.png","namLine truncated
|
||||
@@ -1 +1 @@
|
||||
[{"scope":"https://sqs.us-west-2.amazonaws.com:443","method":"POST","path":"/","body":"Action=ReceiveMessage&MaxNumberOfMessages=1&QueueUrl=https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F274251141632%2Fturtle_jobs_local_dominik_ios_in.fifo&Version=2012-11-05&VisibilityTimeout=30","status":200,"response":"<?xml version=\"1.0\"?><ReceiveMessageResponse xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\"><ReceiveMessageResult/><ResponseMetadata><RequestId>8bea4e96-2dc5-572c-9898-1991f406b911</RequestId></ResponseMetadata></ReceiveMessageResponse>","rawHeaders":["x-amzn-RequestId","8bea4e96-2dc5-572c-9898-1991f406b911","Date","Wed, 08 Apr 2020 13:54:16 GMT","Content-Type","text/xml","Content-Length","240"]},{"scope":"https://sqs.us-west-2.amazonaws.com:443","method":"POST","path":"/","body":"Action=ReceiveMessage&MaxNumberOfMessages=1&QueueUrl=https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F274251141632%2Fturtle_jobs_local_dominik_ios_in_priority.fifo&Version=2012-11-05&VisibilityTimeout=30","status":200,"response":"<?xml version=\"1.0\"?><ReceiveMessageResponse xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\"><ReceiveMessageResult/><ResponseMetadata><RequestId>a995b5e8-7f64-5567-baf9-e2efa6add8fe</RequestId></ResponseMetadata></ReceiveMessageResponse>","rawHeaders":["x-amzn-RequestId","a995b5e8-7f64-5567-baf9-e2efa6add8fe","Date","Wed, 08 Apr 2020 13:54:22 GMT","Content-Type","text/xml","Content-Length","240"]},{"scope":"https://sqs.us-west-2.amazonaws.com:443","method":"POST","path":"/","body":"Action=ReceiveMessage&MaxNumberOfMessages=1&QueueUrl=https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F274251141632%2Fturtle_jobs_local_dominik_ios_in.fifo&Version=2012-11-05&VisibilityTimeout=30","status":200,"response":"<?xml version=\"1.0\"?><ReceiveMessageResponse xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\"><ReceiveMessageResult/><ResponseMetadata><RequestId>8871c5eb-cb40-5a57-a611-92ec128fccd4</RequestId></ResponseMetadata></ReceiveMessageResponse>","rawHeaders":["x-amzn-RequestId","8871c5eb-cb40-5a57-a611-92ec128fccd4","Date","Wed, 08 Apr 2020 13:54:28 GMT","Content-Type","text/xml","Content-Length","240"]},{"scope":"https://sqs.us-west-2.amazonaws.com:443","method":"POST","path":"/","body":"Action=ReceiveMessage&MaxNumberOfMessages=1&QueueUrl=https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F274251141632%2Fturtle_jobs_local_dominik_ios_in_priority.fifo&Version=2012-11-05&VisibilityTimeout=30","status":200,"response":"<?xml version=\"1.0\"?><ReceiveMessageResponse xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\"><ReceiveMessageResult/><ResponseMetadata><RequestId>5c49f623-617a-531c-bbf8-a124b8af2bfd</RequestId></ResponseMetadata></ReceiveMessageResponse>","rawHeaders":["x-amzn-RequestId","5c49f623-617a-531c-bbf8-a124b8af2bfd","Date","Wed, 08 Apr 2020 13:54:34 GMT","Content-Type","text/xml","Content-Length","240"]},{"scope":"https://sqs.us-west-2.amazonaws.com:443","method":"POST","path":"/","body":"Action=ReceiveMessage&MaxNumberOfMessages=1&QueueUrl=https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F274251141632%2Fturtle_jobs_local_dominik_ios_in.fifo&Version=2012-11-05&VisibilityTimeout=30","status":200,"response":"<?xml version=\"1.0\"?><ReceiveMessageResponse xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\"><ReceiveMessageResult/><ResponseMetadata><RequestId>68b706ef-2dce-505b-a0d6-51e8f412e6f9</RequestId></ResponseMetadata></ReceiveMessageResponse>","rawHeaders":["x-amzn-RequestId","68b706ef-2dce-505b-a0d6-51e8f412e6f9","Date","Wed, 08 Apr 2020 13:54:41 GMT","Content-Type","text/xml","Content-Length","240"]},{"scope":"https://sqs.us-west-2.amazonaws.com:443","method":"POST","path":"/","body":"Action=ReceiveMessage&MaxNumberOfMessages=1&QueueUrl=https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F274251141632%2Fturtle_jobs_local_dominik_ios_in_priority.fifo&Version=2012-11-05&VisibilityTimeout=30","status":200,"response":"<?xml version=\"1.0\"?><ReceiveMessageResponse xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\"><ReceiveMessageResult/><ResponseMetadata><RequestId>c1e6a3e3-8d97-57cd-884c-f4e454757fcd</RequestId></ResponseMetadata></ReceiveMessageResponse>","rawHeaders":["x-amzn-RequestId","c1e6a3e3-8d97-57cd-884c-f4e454757fcd","Date","Wed, 08 Apr 2020 13:54:47 GMT","Content-Type","text/xml","Content-Length","240"]},{"scope":"https://sqs.us-west-2.amazonaws.com:443","method":"POST","path":"/","body":"Action=ReceiveMessage&MaxNumberOfMessages=1&QueueUrl=https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F274251141632%2Fturtle_jobs_local_dominik_ios_in.fifo&Version=2012-11-05&VisibilityTimeout=30","status":200,"response":"<?xml version=\"1.0\"?><ReceiveMessageResponse xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\"><ReceiveMessageResult/><ResponseMetadata><RequestId>a68dea4b-2de4-5000-b718-bd4cf40ca8fa</RequestId></ResponseMetadata></ReceiveMessageResponse>","rawHeaders":["x-amzn-RequestId","a68dea4b-2de4-5000-b718-bd4cf40ca8fa","Date","Wed, 08 Apr 2020 13:54:53 GMT","Content-Type","text/xml","Content-Length","240"]},{Line truncated
|
||||
[{"scope":"https://sqs.us-west-2.amazonaws.com:443","method":"POST","path":"/","body":"Action=ReceiveMessage&MaxNumberOfMessages=1&QueueUrl=https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F274251141632%2Fturtle_jobs_local_dominik_ios_in.fifo&Version=2012-11-05&VisibilityTimeout=30","status":200,"response":"<?xml version=\"1.0\"?><ReceiveMessageResponse xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\"><ReceiveMessageResult><Message><MessageId>05cbd74e-0c64-486f-a7e4-607abc3aaf2a</MessageId><ReceiptHandle>AQEB+bslyZTn6YlgvfhEznBALIRLejznK2LRiyoEVQNtRiglGEQ1f8KWtEykEqCC49N3J2A9yQD2vPIsPz+2Ad2QuEqsQVnkrx3STeoqu6icQesfdDDtq89ma76A6qbTy74sp23yVb8J0N8acUCW5M9oHaqqeNjbC/OoyO7P3zDHXXkydub5Kn72NAzNtfFOwnxfNCwKuKR4MKlsSC96P2GSHfR7S0wcUtcLpwtLMrbprMxgzN00qVudMRFLzpG4AC1gpGHHjzWuyQ41eL0AQ73T82Gga5ZiPqZ/QD4n8MQ5El7gz/mMNUL+JiKM2KCU3Jx2</ReceiptHandle><MD5OfBody>c136cec4c14d07668b5975e69bcc3330</MD5OfBody><Body>{"id":"ffb51e07-7cde-4b8e-a293-a2232feab913","experienceId":"dfddc5d4-1d2a-4106-bd45-cb476ffce76e","experienceName":"@dsokal-local/turtle-cli-example","platform":"ios","config":{"releaseChannel":"default","usesNonExemptEncryption":false,"buildType":"archive","bundleIdentifier":"com.expo.turtle.cli.example"},"status":"sent-to-queue","sdkVersion":"37.0.0","accountId":"fbd6360b-e85d-485e-bf20-ab66adfeea16","priority":"normal","credentials":{"teamId":"QL76XYH73P","teamName":"Alicja Warchał (Individual)","apnsKeyId":"Z2J59NHNCT","apnsKeyP8":"-----BEGIN PRIVATE KEY-----\\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQguLC/A0xR+9Wl0iZu\\n3gI7vY7WdK43Gi/AmxaNd+ClqD+gCgYIKoZIzj0DAQehRANCAATo7Wnhxs2gr6mn\\nRUhOthWykpMudxrcVdfHmPDZBiP/W9gzhMso9vDJf8S7fJrYRV2V+DsZWL/hVll3\\net4AYU+X\\n-----END PRIVATE KEY-----","certP12":"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 truncated
|
||||
@@ -17,8 +17,7 @@ jest.mock('../builders/utils/uploader.ts', () => ({
|
||||
async function performSmokeTest(recording: string) {
|
||||
jest.setTimeout(60 * 60 * 1000);
|
||||
|
||||
// @ts-ignore
|
||||
const fixtureExists = await fs.exists(recording);
|
||||
const fixtureExists = await fs.pathExists(recording);
|
||||
if (fixtureExists) {
|
||||
logger.info('Fixture exists, test will use existing one.');
|
||||
|
||||
|
||||
@@ -136,7 +136,7 @@ function _addEmptyMetrics(metrics: IMetric[]) {
|
||||
acc.add(i.MetricName);
|
||||
}
|
||||
return acc;
|
||||
}, new Set());
|
||||
}, new Set<string>());
|
||||
|
||||
const nonEmptyMetrics = _.omitBy(state.registeredMetrics, ({ addEmpty }) => !addEmpty);
|
||||
const toAdd = _.difference(Object.keys(nonEmptyMetrics), Array.from(seenMetrics));
|
||||
|
||||
@@ -19,10 +19,10 @@ export default function calculateStatistics(metrics: IMetric[]) {
|
||||
});
|
||||
}
|
||||
|
||||
result.StatisticValues.Maximum = Math.max(result.StatisticValues.Maximum, i.Value);
|
||||
result.StatisticValues.Minimum = Math.min(result.StatisticValues.Minimum, i.Value);
|
||||
result.StatisticValues.SampleCount += 1;
|
||||
result.StatisticValues.Sum += i.Value;
|
||||
result!.StatisticValues.Maximum = Math.max(result!.StatisticValues.Maximum, i.Value);
|
||||
result!.StatisticValues.Minimum = Math.min(result!.StatisticValues.Minimum, i.Value);
|
||||
result!.StatisticValues.SampleCount += 1;
|
||||
result!.StatisticValues.Sum += i.Value;
|
||||
return result;
|
||||
}, null);
|
||||
return [reduced];
|
||||
|
||||
+1
-18
@@ -2,9 +2,8 @@ import retry from 'async-retry';
|
||||
import AWS from 'aws-sdk';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { OUTPUT_QUEUE_URL, QUEUE_URL } from 'turtle/aws/utils';
|
||||
import { QUEUE_URL } from 'turtle/aws/utils';
|
||||
import config from 'turtle/config';
|
||||
import { JOB_UPDATE_TYPE } from 'turtle/constants/build';
|
||||
import logger from 'turtle/logger';
|
||||
import { getCurrentJobId } from 'turtle/turtleContext';
|
||||
|
||||
@@ -73,19 +72,3 @@ export function changeMessageVisibilityRecurring(priority: string, receiptHandle
|
||||
}
|
||||
}, (VISIBILITY_TIMEOUT_SEC * 1000) / 3);
|
||||
}
|
||||
|
||||
export async function sendMessage(jobId: string, status: JOB_UPDATE_TYPE, data = {}) {
|
||||
const params = {
|
||||
MessageBody: JSON.stringify({ jobId, status, ...data }),
|
||||
QueueUrl: OUTPUT_QUEUE_URL(),
|
||||
DelaySeconds: 0,
|
||||
MessageGroupId: jobId,
|
||||
};
|
||||
try {
|
||||
return await retry(async () => {
|
||||
return await sqs.sendMessage(params).promise();
|
||||
});
|
||||
} catch (err) {
|
||||
logger.error({ err }, `Error sending SQS message: ${JSON.stringify(params)}}`);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
import config from 'turtle/config';
|
||||
|
||||
export const QUEUE_URL = (priority: string) => (config.sqs.queues as any)[priority][config.platform];
|
||||
export const OUTPUT_QUEUE_URL = () => config.sqs.queues.out;
|
||||
@@ -29,6 +29,11 @@ export default (program: any, setCommonCommandOptions: any) => {
|
||||
/^(debug|release)$/i,
|
||||
'release',
|
||||
)
|
||||
.option(
|
||||
'--gradle-args <gradle-args>',
|
||||
'optional arguments passed to gradle, make sure to surround them with double quotes'
|
||||
+ ' (e.g.: --gradle-args "--stacktrace --debug")',
|
||||
)
|
||||
.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.',
|
||||
|
||||
@@ -15,7 +15,12 @@ function setCommonCommandOptions(cmd: any) {
|
||||
.option('-o --output <output-file-path>', 'output file path')
|
||||
.option(
|
||||
'--public-url <url>',
|
||||
'the URL of an externally hosted manifest (for self-hosted apps), only HTTPS URLs are supported!',
|
||||
'the URL of an externally hosted manifest (for self-hosted apps), only HTTPS URLs are supported unless '
|
||||
+ '--allow-non-https-public-url is also set!',
|
||||
)
|
||||
.option(
|
||||
'--allow-non-https-public-url',
|
||||
'allows non-HTTPS URLs in --public-url; this should only be used when building an unpublished application',
|
||||
)
|
||||
.option(
|
||||
'--release-channel <channel-name>',
|
||||
|
||||
+16
-13
@@ -1,6 +1,6 @@
|
||||
import _url from 'url';
|
||||
|
||||
import { ConfigError, getExpoSDKVersion } from '@expo/config';
|
||||
import { ConfigError, getExpoSDKVersion, ProjectConfig } from '@expo/config';
|
||||
import { ExponentTools } from '@expo/xdl';
|
||||
import _ from 'lodash';
|
||||
import uuid from 'uuid';
|
||||
@@ -57,7 +57,7 @@ export function createBuilderAction({
|
||||
);
|
||||
}
|
||||
|
||||
if (cmd.publicUrl) {
|
||||
if (cmd.publicUrl && !cmd.allowNonHttpsPublicUrl) {
|
||||
const parsedPublicUrl = _url.parse(cmd.publicUrl);
|
||||
if (parsedPublicUrl.protocol !== 'https:') {
|
||||
throw new ErrorWithCommandHelp('--public-url is invalid - only HTTPS urls are supported');
|
||||
@@ -74,12 +74,12 @@ export function createBuilderAction({
|
||||
publicUrl: cmd.publicUrl,
|
||||
};
|
||||
|
||||
const appJSON = await ProjectUtils.loadAppJSON(projectDirArg, cmd.config);
|
||||
const sdkVersion = getExpoSDKVersionSafely(projectAbsoluteDir, appJSON);
|
||||
const projectConfig = await ProjectUtils.getConfig(projectDirArg, cmd.config);
|
||||
const sdkVersion = getExpoSDKVersionSafely(projectAbsoluteDir, projectConfig);
|
||||
await setup(platform, sdkVersion);
|
||||
const credentials = await prepareCredentials(cmd);
|
||||
const rawJob = {
|
||||
...await buildJobObject(platform, appJSON, args, credentials, sdkVersion),
|
||||
...await buildJobObject(cmd, platform, projectConfig, args, credentials, sdkVersion),
|
||||
...cmd.buildDir && { fakeUploadDir: ProjectUtils.resolveAbsoluteDir(cmd.buildDir) },
|
||||
...cmd.output && { fakeUploadBuildPath: ProjectUtils.resolveAbsoluteDir(cmd.output) },
|
||||
};
|
||||
@@ -97,9 +97,9 @@ export function createBuilderAction({
|
||||
};
|
||||
}
|
||||
|
||||
function getExpoSDKVersionSafely(projectDir: string, appJSON?: any) {
|
||||
function getExpoSDKVersionSafely(projectDir: string, projectConfig: ProjectConfig) {
|
||||
try {
|
||||
return getExpoSDKVersion(projectDir, appJSON && appJSON.expo);
|
||||
return getExpoSDKVersion(projectDir, projectConfig.exp);
|
||||
} catch (err) {
|
||||
if (err instanceof ConfigError) {
|
||||
throw new Error(
|
||||
@@ -113,22 +113,25 @@ function getExpoSDKVersionSafely(projectDir: string, appJSON?: any) {
|
||||
}
|
||||
|
||||
const buildJobObject = async (
|
||||
cmd: any,
|
||||
platform: 'android' | 'ios',
|
||||
appJSON: any,
|
||||
projectConfig: ProjectConfig,
|
||||
{ releaseChannel, buildType, buildMode, username, publicUrl, projectDir }: any,
|
||||
credentials: any,
|
||||
sdkVersion: string,
|
||||
) => {
|
||||
const experienceName = `@${_.get(appJSON, 'expo.owner', username)}/${_.get(appJSON, 'expo.slug')}`;
|
||||
const owner = projectConfig.exp.owner || username;
|
||||
const experienceName = `@${owner}/${projectConfig.exp.slug}`;
|
||||
const job = {
|
||||
config: {
|
||||
..._.get(appJSON, `expo.${platform}.config`, {}),
|
||||
...(projectConfig.exp?.[platform]?.config || {}),
|
||||
buildType,
|
||||
...(platform === 'android' ? { buildMode } : {}),
|
||||
releaseChannel,
|
||||
...(platform === 'ios' ? { bundleIdentifier: _.get(appJSON, 'expo.ios.bundleIdentifier') } : {}),
|
||||
...(platform === 'android' ? { androidPackage: _.get(appJSON, 'expo.android.package') } : {}),
|
||||
publicUrl,
|
||||
...(platform === 'android' && cmd.gradleArgs ? { gradleArgs: cmd.gradleArgs.split(' ') } : {}),
|
||||
...(platform === 'android' ? { buildMode } : {}),
|
||||
...(platform === 'android' ? { androidPackage: projectConfig.exp?.android?.package } : {}),
|
||||
...(platform === 'ios' ? { bundleIdentifier: projectConfig.exp?.ios?.bundleIdentifier } : {}),
|
||||
},
|
||||
id: uuid.v4(),
|
||||
platform,
|
||||
|
||||
+11
-13
@@ -1,20 +1,18 @@
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
|
||||
export async function loadAppJSON(projectDirArg: string, config: string | null) {
|
||||
let appJSONPath;
|
||||
import { getConfig as getProjectConfig, setCustomConfigPath } from '@expo/config';
|
||||
import fs from 'fs-extra';
|
||||
|
||||
export async function getConfig(projectDir: string, config: string | null) {
|
||||
projectDir = resolveAbsoluteDir(projectDir);
|
||||
if (config) {
|
||||
appJSONPath = resolveAbsoluteDir(config);
|
||||
} else {
|
||||
const projectDir = resolveAbsoluteDir(projectDirArg);
|
||||
appJSONPath = path.join(projectDir, 'app.json');
|
||||
}
|
||||
const appJSONExists = await fs.pathExists(appJSONPath);
|
||||
if (!appJSONExists) {
|
||||
throw new Error(`Couldn't find app.json.`);
|
||||
} else {
|
||||
return require(appJSONPath);
|
||||
const pathToConfig = path.resolve(process.cwd(), config);
|
||||
if (!await fs.pathExists(pathToConfig)) {
|
||||
throw new Error(`File at provided config path does not exist: ${pathToConfig}`);
|
||||
}
|
||||
setCustomConfigPath(projectDir, pathToConfig);
|
||||
}
|
||||
return await getProjectConfig(projectDir, {});
|
||||
}
|
||||
|
||||
export const resolveAbsoluteDir = (dir: string) => {
|
||||
|
||||
@@ -34,8 +34,8 @@ export default async function buildAndroid(jobData: IJob): Promise<IJobResult> {
|
||||
...config.builder.fakeUpload && {
|
||||
fakeUploadBuildPath:
|
||||
jobData.fakeUploadBuildPath
|
||||
? jobData.fakeUploadBuildPath
|
||||
: path.join(jobData.fakeUploadDir || config.directories.fakeUploadDir, fakeUploadFilename),
|
||||
? jobData.fakeUploadBuildPath
|
||||
: path.join(jobData.fakeUploadDir || config.directories.fakeUploadDir, fakeUploadFilename),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -103,6 +103,7 @@ async function runShellAppBuilder(
|
||||
modules: enabledModules,
|
||||
buildType: jobData.config.buildType,
|
||||
buildMode: jobData.config.buildMode,
|
||||
gradleArgs: jobData.config.gradleArgs,
|
||||
});
|
||||
} catch (err) {
|
||||
commonUtils.logErrorOnce(err);
|
||||
|
||||
@@ -5,11 +5,10 @@ import fs from 'fs-extra';
|
||||
import get from 'lodash/get';
|
||||
import uuidv4 from 'uuid/v4';
|
||||
|
||||
import * as sqs from 'turtle/aws/sqs';
|
||||
import { UPDATE_CREDENTIALS } from 'turtle/constants/build';
|
||||
import { IAndroidCredentials, IJob } from 'turtle/job';
|
||||
import logger from 'turtle/logger';
|
||||
import { isOffline } from 'turtle/turtleContext';
|
||||
import { sendCredentialsUpdate } from 'turtle/utils/www';
|
||||
|
||||
async function getOrCreateCredentials(jobData: IJob): Promise<IAndroidCredentials> {
|
||||
if (!jobData.credentials) {
|
||||
@@ -50,9 +49,7 @@ async function getOrCreateCredentials(jobData: IJob): Promise<IAndroidCredential
|
||||
l.info(`Key password: ${credentials.keyPassword}`);
|
||||
l.info(`Please keep these credentials safe`);
|
||||
} else {
|
||||
await sqs.sendMessage(jobData.id, UPDATE_CREDENTIALS, {
|
||||
...credentials,
|
||||
});
|
||||
await sendCredentialsUpdate(jobData.id, 'android', credentials);
|
||||
l.info('Keystore sent to storage successfully');
|
||||
}
|
||||
await fs.unlink(keystoreFilename);
|
||||
|
||||
@@ -4,12 +4,11 @@ import spawnAsync from '@expo/spawn-async';
|
||||
import { IosCodeSigning } from '@expo/xdl';
|
||||
import fs from 'fs-extra';
|
||||
|
||||
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';
|
||||
import { sendCredentialsUpdate } from 'turtle/utils/www';
|
||||
|
||||
// tslint:disable-next-line:no-var-requires
|
||||
const travelingFastlane = process.platform === 'darwin' ? require('@expo/traveling-fastlane-darwin')() : null;
|
||||
@@ -64,7 +63,7 @@ async function prepareAdHocBuildCredentials(job: IJob) {
|
||||
await fs.writeFile(provisioningProfilePath, Buffer.from(credentials.provisioningProfile, 'base64'));
|
||||
logger.info(`Saved provisioning profile to ${provisioningProfilePath}`);
|
||||
} else {
|
||||
await sqs.sendMessage(job.id, UPDATE_CREDENTIALS, {
|
||||
await sendCredentialsUpdate(job.id, 'ios', {
|
||||
provisioningProfileId: credentials.provisioningProfileId,
|
||||
provisioningProfile: credentials.provisioningProfile,
|
||||
});
|
||||
|
||||
+18
-5
@@ -1,3 +1,4 @@
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
@@ -28,7 +29,6 @@ export default {
|
||||
ios: env('AWS_SQS_IOS_PRIORITY_QUEUE_URL'),
|
||||
android: env('AWS_SQS_ANDROID_PRIORITY_QUEUE_URL'),
|
||||
},
|
||||
out: env('AWS_SQS_OUT_QUEUE_URL'),
|
||||
},
|
||||
},
|
||||
cloudwatch: {
|
||||
@@ -44,8 +44,17 @@ export default {
|
||||
intervalMs: env('DATADOG_INTERVAL_MS', 5 * 60 * 1000),
|
||||
},
|
||||
redis: {
|
||||
url: env('REDIS_URL'),
|
||||
configUrl: env('REDIS_CONFIG_URL'),
|
||||
main: {
|
||||
url: env('REDIS_URL'),
|
||||
caCertificate: envTransform(
|
||||
'REDIS_CA_CERTIFICATE',
|
||||
null,
|
||||
(caCertificate: string) => caCertificate && fs.readFileSync(caCertificate),
|
||||
),
|
||||
},
|
||||
turtle: {
|
||||
url: env('REDIS_CONFIG_URL'),
|
||||
},
|
||||
},
|
||||
logger: {
|
||||
level: env('LOGGER_LEVEL', 'info'),
|
||||
@@ -81,7 +90,7 @@ export default {
|
||||
androidDependenciesDir: env(
|
||||
'TURTLE_ANDROID_DEPENDENCIES_DIR',
|
||||
path.join(os.homedir(), '.turtle/androidDependencies'),
|
||||
),
|
||||
),
|
||||
tempS3LogsDir: env('TURTLE_TEMP_S3_LOGS_DIR', '/tmp/logs'),
|
||||
fakeUploadDir: envOptional('TURTLE_FAKE_UPLOAD_DIR'),
|
||||
temporaryFilesRoot: env(
|
||||
@@ -90,6 +99,10 @@ export default {
|
||||
),
|
||||
},
|
||||
www: {
|
||||
sdkVersionsSecretToken: env('TURTLE_SDK_VERSIONS_SECRET_TOKEN'),
|
||||
secretToken: env('TURTLE_SDK_VERSIONS_SECRET_TOKEN'),
|
||||
},
|
||||
leader: {
|
||||
redisKey: env('LEADER_REDIS_KEY', 'turtle-v1:leader'),
|
||||
redisKeyTTLSec: envNum('LEADER_REDIS_KEY_TTL', 30),
|
||||
},
|
||||
};
|
||||
@@ -15,6 +15,7 @@ export interface IJob {
|
||||
// android
|
||||
androidPackage?: string;
|
||||
buildMode?: ANDROID_BUILD_MODES;
|
||||
gradleArgs?: string[];
|
||||
};
|
||||
credentials: {
|
||||
// android
|
||||
|
||||
+26
-10
@@ -12,6 +12,7 @@ import * as buildStatusMetric from 'turtle/metrics/buildStatus';
|
||||
import { checkShouldExit, setCurrentJobId, turtleVersion } from 'turtle/turtleContext';
|
||||
import { getPriorities, labelConfiguration, TurtleMode } from 'turtle/utils/priorities';
|
||||
import * as redis from 'turtle/utils/redis';
|
||||
import { sendBuildStatusUpdate } from 'turtle/utils/www';
|
||||
import { sanitizeJob } from 'turtle/validator';
|
||||
|
||||
function _maybeExit() {
|
||||
@@ -73,7 +74,8 @@ async function processJob(jobData: any, turtleMode: TurtleMode) {
|
||||
logger.error({ err, ...rawJob && { buildJobId: rawJob.id } }, 'The build job is invalid');
|
||||
// send message only if we've managed to parse the job json
|
||||
if (rawJob) {
|
||||
await sqs.sendMessage(rawJob.id, BUILD.JOB_STATES.ERRORED, {
|
||||
await sendBuildStatusUpdate(rawJob.id, {
|
||||
status: BUILD.JOB_STATES.ERRORED,
|
||||
turtleVersion,
|
||||
buildDuration: 0,
|
||||
reason: 'The build job is invalid',
|
||||
@@ -128,7 +130,7 @@ async function processJob(jobData: any, turtleMode: TurtleMode) {
|
||||
function failAfterMaxJobTime(priority: string, receiptHandle: string, job: any) {
|
||||
return setTimeout(async () => {
|
||||
try {
|
||||
sqs.sendMessage(job.id, BUILD.JOB_STATES.ERRORED, { turtleVersion });
|
||||
sendBuildStatusUpdate(job.id, { status: BUILD.JOB_STATES.ERRORED, turtleVersion });
|
||||
await deleteMessage(priority, receiptHandle);
|
||||
} finally {
|
||||
logger.error('Build timed out. Going to terminate turtle agent.');
|
||||
@@ -143,16 +145,28 @@ async function build(job: any, turtleMode: TurtleMode) {
|
||||
const s3Url = await logger.initForJob(job);
|
||||
const calculateBuildDuration = () => Math.ceil((Date.now() - startTimestamp) / 1000);
|
||||
|
||||
try {
|
||||
await sqs.sendMessage(job.id, BUILD.JOB_STATES.IN_PROGRESS, {
|
||||
logUrl: s3Url,
|
||||
logFormat: 'json',
|
||||
const commonPayload = {
|
||||
logs: {
|
||||
url: s3Url,
|
||||
format: 'json',
|
||||
},
|
||||
extraData: {
|
||||
turtleMode,
|
||||
},
|
||||
};
|
||||
try {
|
||||
await sendBuildStatusUpdate(job.id, {
|
||||
...commonPayload,
|
||||
status: BUILD.JOB_STATES.IN_PROGRESS,
|
||||
});
|
||||
const result = await (builders as any)[job.platform](job);
|
||||
const { artifactUrl } = await (builders as any)[job.platform](job);
|
||||
const buildDuration = calculateBuildDuration();
|
||||
sqs.sendMessage(job.id, BUILD.JOB_STATES.FINISHED, {
|
||||
...result,
|
||||
sendBuildStatusUpdate(job.id, {
|
||||
...commonPayload,
|
||||
artifacts: {
|
||||
url: artifactUrl,
|
||||
},
|
||||
status: BUILD.JOB_STATES.FINISHED,
|
||||
turtleVersion,
|
||||
buildDuration,
|
||||
});
|
||||
@@ -164,7 +178,9 @@ async function build(job: any, turtleMode: TurtleMode) {
|
||||
if (err instanceof BuildError) {
|
||||
reason = err.reason;
|
||||
}
|
||||
sqs.sendMessage(job.id, BUILD.JOB_STATES.ERRORED, {
|
||||
sendBuildStatusUpdate(job.id, {
|
||||
...commonPayload,
|
||||
status: BUILD.JOB_STATES.ERRORED,
|
||||
turtleVersion,
|
||||
buildDuration,
|
||||
...reason && { reason },
|
||||
|
||||
@@ -15,6 +15,7 @@ export default baseJobSchema.concat(
|
||||
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),
|
||||
gradleArgs: Joi.array().items(Joi.string()),
|
||||
}),
|
||||
}),
|
||||
);
|
||||
@@ -6,6 +6,8 @@ import { doJob } from 'turtle/jobManager';
|
||||
import logger from 'turtle/logger';
|
||||
import setup from 'turtle/setup';
|
||||
import { checkShouldExit, setShouldExit, turtleVersion } from 'turtle/turtleContext';
|
||||
import { synchronizeFailedUpdates } from 'turtle/updatesManager';
|
||||
import Leader, { LeaderEvent } from 'turtle/utils/leader';
|
||||
import { setSupportedSdkVersions, setTurtleVersion } from 'turtle/utils/versions';
|
||||
|
||||
process.on('unhandledRejection', (err) => logger.error({ err }, 'Unhandled promise rejection'));
|
||||
@@ -33,6 +35,8 @@ async function main() {
|
||||
await setup[config.platform]();
|
||||
}
|
||||
|
||||
await electLeaderAndSynchronize();
|
||||
|
||||
try {
|
||||
await setTurtleVersion(turtleVersion);
|
||||
logger.info(`Registered Turtle version (${turtleVersion}) in www`);
|
||||
@@ -52,6 +56,28 @@ async function main() {
|
||||
}
|
||||
}
|
||||
|
||||
async function electLeaderAndSynchronize() {
|
||||
if (config.env === 'test') {
|
||||
return;
|
||||
|
||||
}
|
||||
const l = new Leader({
|
||||
key: config.leader.redisKey,
|
||||
id: config.hostname,
|
||||
ttl: config.leader.redisKeyTTLSec,
|
||||
});
|
||||
let intervalId: NodeJS.Timeout;
|
||||
l.on(LeaderEvent.elected, async () => {
|
||||
intervalId = await synchronizeFailedUpdates();
|
||||
});
|
||||
l.on(LeaderEvent.revoked, () => {
|
||||
if (intervalId) {
|
||||
clearInterval(intervalId);
|
||||
}
|
||||
});
|
||||
await l.elect();
|
||||
}
|
||||
|
||||
main()
|
||||
.then(() => logger.error('This should never happen...'))
|
||||
.catch((err) => logger.error({ err }, 'Something went terribly wrong'))
|
||||
|
||||
Vendored
-1
@@ -4,7 +4,6 @@ declare module 'bunyan-sentry-stream';
|
||||
declare module 'bunyan-debug-stream';
|
||||
declare module 'copy';
|
||||
declare module 'dogapi';
|
||||
declare module 'ioredis';
|
||||
declare module 'is-semver';
|
||||
declare module 'request-progress';
|
||||
declare module '@expo/xdl';
|
||||
@@ -0,0 +1,83 @@
|
||||
import Redis from 'ioredis';
|
||||
import chunk from 'lodash/chunk';
|
||||
|
||||
import config from 'turtle/config';
|
||||
import { getRedisClient, RedisClient } from 'turtle/utils/redis';
|
||||
import { sendBuildStatusUpdate, sendCredentialsUpdate } from 'turtle/utils/www';
|
||||
|
||||
const RETRY_COUNT = 5;
|
||||
|
||||
type UpdateType = 'build' | 'credentials';
|
||||
interface IUpdate {
|
||||
type: UpdateType;
|
||||
buildId: string;
|
||||
updateBody: any;
|
||||
retried: number;
|
||||
}
|
||||
|
||||
export async function saveUpdateFailure(buildId: string, type: UpdateType, updateBody: object): Promise<void> {
|
||||
if (config.env === 'test') {
|
||||
return;
|
||||
}
|
||||
const redis = await getRedisClient(RedisClient.Configuration) as Redis.Redis;
|
||||
const update: IUpdate = {
|
||||
type,
|
||||
buildId,
|
||||
updateBody,
|
||||
retried: 0,
|
||||
};
|
||||
await redis.set(getFailedUpdateKey(buildId), JSON.stringify(update));
|
||||
}
|
||||
|
||||
export async function synchronizeFailedUpdates(intervalMs = 3 * 60 * 1000): Promise<NodeJS.Timeout> {
|
||||
try {
|
||||
await _synchronizeFailedUpdates();
|
||||
} catch (err) {
|
||||
// don't do anything
|
||||
}
|
||||
return setInterval(() => _synchronizeFailedUpdates(), intervalMs);
|
||||
}
|
||||
|
||||
async function _synchronizeFailedUpdates(): Promise<void> {
|
||||
const redis = await getRedisClient(RedisClient.Configuration) as Redis.Redis;
|
||||
const keys = await redis.keys(getFailedUpdateKey('*'));
|
||||
const keyChunks = chunk(keys, 20);
|
||||
for (const keyChunk of keyChunks) {
|
||||
await Promise.all(keyChunk.map((key: string) => resendUpdateForKey(key)));
|
||||
}
|
||||
}
|
||||
|
||||
async function resendUpdateForKey(key: string): Promise<void> {
|
||||
try {
|
||||
const redis = await getRedisClient(RedisClient.Configuration) as Redis.Redis;
|
||||
const updateRaw = await redis.get(key);
|
||||
if (updateRaw) {
|
||||
const update = JSON.parse(updateRaw) as IUpdate;
|
||||
try {
|
||||
await resendUpdateToWWW(update);
|
||||
await redis.del(key);
|
||||
} catch (err) {
|
||||
update.retried += 1;
|
||||
if (update.retried >= RETRY_COUNT) {
|
||||
await redis.del(key);
|
||||
} else {
|
||||
await redis.set(key, JSON.stringify(update));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
// don't do anything
|
||||
}
|
||||
}
|
||||
|
||||
async function resendUpdateToWWW(update: IUpdate): Promise<void> {
|
||||
const { type, buildId, updateBody } = update;
|
||||
if (type === 'build') {
|
||||
await sendBuildStatusUpdate(buildId, updateBody);
|
||||
} else if (type === 'credentials') {
|
||||
const { platform, ...rest } = updateBody;
|
||||
await sendCredentialsUpdate(buildId, platform, rest);
|
||||
}
|
||||
}
|
||||
|
||||
const getFailedUpdateKey = (buildId: string) => `${config.deploymentEnv}:failed-update:${buildId}`;
|
||||
@@ -0,0 +1,164 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import Redis from 'ioredis';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import { getRedisClient, RedisClient } from 'turtle/utils/redis';
|
||||
|
||||
interface ILeaderParams {
|
||||
key: string;
|
||||
id?: string;
|
||||
ttl?: number;
|
||||
wait?: number;
|
||||
}
|
||||
|
||||
const RENEW_LEADER_SCRIPT = `
|
||||
local leader_key = KEYS[1]
|
||||
local leader_id = KEYS[2]
|
||||
local leader_ttl = KEYS[3]
|
||||
|
||||
local current_leader
|
||||
|
||||
current_leader = redis.call("get", leader_key)
|
||||
if (current_leader == leader_id) then
|
||||
redis.call("pexpire", leader_key, leader_ttl)
|
||||
return "ok"
|
||||
else
|
||||
return "you_are_not_the_leader"
|
||||
end
|
||||
`;
|
||||
|
||||
const STOP_BEING_LEADER_SCRIPT = `
|
||||
local leader_key = KEYS[1]
|
||||
local leader_id = KEYS[2]
|
||||
|
||||
local current_leader
|
||||
|
||||
current_leader = redis.call("get", leader_key)
|
||||
if (current_leader == leader_id) then
|
||||
redis.call("del", leader_key)
|
||||
return "ok"
|
||||
else
|
||||
return "you_are_not_the_leader"
|
||||
end
|
||||
`;
|
||||
|
||||
interface IRedisCustom extends Redis.Redis {
|
||||
renewLeader(key: string, id: string, ttl: number): Promise<string>;
|
||||
stopBeingLeader(key: string, id: string): Promise<string>;
|
||||
}
|
||||
|
||||
enum LeaderEvent {
|
||||
elected = 'elected',
|
||||
revoked = 'revoked',
|
||||
error = 'error',
|
||||
}
|
||||
|
||||
class Leader extends EventEmitter {
|
||||
private key: string;
|
||||
private id: string;
|
||||
private ttl: number;
|
||||
private wait: number;
|
||||
private waitId?: NodeJS.Timeout;
|
||||
private redisClientValue?: IRedisCustom;
|
||||
private renewId?: NodeJS.Timeout;
|
||||
private started = false;
|
||||
|
||||
constructor({ key, id, ttl = 30, wait = 1000 }: ILeaderParams) {
|
||||
super();
|
||||
|
||||
this.key = key;
|
||||
this.id = id || uuid();
|
||||
this.ttl = ttl * 1000;
|
||||
this.wait = wait;
|
||||
}
|
||||
public async elect(): Promise<void> {
|
||||
if (!this.redisClientValue) {
|
||||
await this.init();
|
||||
}
|
||||
|
||||
if (!this.started) {
|
||||
this.started = true;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await this.redisClient.set(this.key, this.id, 'PX', this.ttl, 'NX');
|
||||
if (res === null) {
|
||||
this.waitId = setTimeout(() => {
|
||||
this.elect();
|
||||
}, this.wait);
|
||||
} else {
|
||||
this.emit(LeaderEvent.elected);
|
||||
this.renewId = setInterval(() => {
|
||||
this.renew();
|
||||
}, this.ttl / 2);
|
||||
}
|
||||
} catch (err) {
|
||||
this.emit(LeaderEvent.error, err);
|
||||
}
|
||||
}
|
||||
|
||||
public async stop(): Promise<void> {
|
||||
if (!this.started) {
|
||||
throw new Error('You should start the election first!');
|
||||
}
|
||||
try {
|
||||
const res = await this.redisClient.stopBeingLeader(this.key, this.id);
|
||||
if (res === 'ok') {
|
||||
this.emit(LeaderEvent.revoked);
|
||||
}
|
||||
if (this.renewId) {
|
||||
clearInterval(this.renewId);
|
||||
}
|
||||
if (this.waitId) {
|
||||
clearTimeout(this.waitId);
|
||||
}
|
||||
this.redisClientValue?.disconnect();
|
||||
this.redisClientValue = undefined;
|
||||
} catch (err) {
|
||||
this.emit(LeaderEvent.error, err);
|
||||
}
|
||||
}
|
||||
|
||||
private get redisClient(): IRedisCustom {
|
||||
if (!this.redisClientValue) {
|
||||
throw new Error('Please run the init method first!');
|
||||
}
|
||||
return this.redisClientValue as IRedisCustom;
|
||||
}
|
||||
|
||||
private async init(): Promise<void> {
|
||||
if (this.redisClientValue) {
|
||||
return;
|
||||
}
|
||||
this.redisClientValue = await getRedisClient(RedisClient.Configuration);
|
||||
const redisClient = this.redisClient as IRedisCustom;
|
||||
redisClient.defineCommand('renewLeader', {
|
||||
numberOfKeys: 3,
|
||||
lua: RENEW_LEADER_SCRIPT,
|
||||
});
|
||||
redisClient.defineCommand('stopBeingLeader', {
|
||||
numberOfKeys: 2,
|
||||
lua: STOP_BEING_LEADER_SCRIPT,
|
||||
});
|
||||
}
|
||||
|
||||
private async renew(): Promise<void> {
|
||||
try {
|
||||
const result = await this.redisClient.renewLeader(this.key, this.id, this.ttl);
|
||||
if (result === 'you_are_not_the_leader') {
|
||||
if (this.renewId) {
|
||||
clearInterval(this.renewId);
|
||||
}
|
||||
this.waitId = setTimeout(() => {
|
||||
this.elect();
|
||||
}, this.wait);
|
||||
this.emit(LeaderEvent.revoked);
|
||||
}
|
||||
} catch (err) {
|
||||
this.emit(LeaderEvent.error, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Leader;
|
||||
export { LeaderEvent };
|
||||
+15
-6
@@ -12,18 +12,27 @@ export enum RedisClient {
|
||||
Configuration = 'REDIS_CLIENT_CONFIGURATION',
|
||||
}
|
||||
|
||||
interface IClientConfig { [key: string]: string; }
|
||||
interface IClientConfig {
|
||||
[key: string]: {
|
||||
url: string;
|
||||
caCertificate?: string;
|
||||
};
|
||||
}
|
||||
|
||||
const clientToUrl: IClientConfig = {
|
||||
[RedisClient.Subscriber]: config.redis.url,
|
||||
[RedisClient.Default]: config.redis.url,
|
||||
[RedisClient.Configuration]: config.redis.configUrl,
|
||||
const clientConfigs: IClientConfig = {
|
||||
[RedisClient.Subscriber]: config.redis.main,
|
||||
[RedisClient.Default]: config.redis.main,
|
||||
[RedisClient.Configuration]: config.redis.turtle,
|
||||
};
|
||||
|
||||
export function connect(timeoutMs: number, type: string): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const redisClient = new Redis(clientToUrl[type], {
|
||||
const { url, caCertificate } = clientConfigs[type];
|
||||
const redisClient = new Redis(url, {
|
||||
maxRetriesPerRequest: 2,
|
||||
...caCertificate && {
|
||||
tls: { ca: caCertificate },
|
||||
},
|
||||
});
|
||||
const timer = setTimeout(() => reject(new Error('Timeout at connecting to Redis')), timeoutMs);
|
||||
redisClient.on('ready', () => {
|
||||
|
||||
@@ -10,7 +10,7 @@ async function setSupportedSdkVersions(platform: string, sdkVersions: string[])
|
||||
method: 'POST',
|
||||
uri: href,
|
||||
headers: {
|
||||
'secret-token': config.www.sdkVersionsSecretToken,
|
||||
'secret-token': config.www.secretToken,
|
||||
},
|
||||
body: {
|
||||
platform,
|
||||
@@ -26,7 +26,7 @@ async function setTurtleVersion(version: string) {
|
||||
method: 'POST',
|
||||
uri: href,
|
||||
headers: {
|
||||
'secret-token': config.www.sdkVersionsSecretToken,
|
||||
'secret-token': config.www.secretToken,
|
||||
},
|
||||
body: {
|
||||
version,
|
||||
@@ -38,9 +38,9 @@ async function setTurtleVersion(version: string) {
|
||||
function resolveWWWEndpoint() {
|
||||
const currentEnv = config.deploymentEnv;
|
||||
if (currentEnv === 'production') {
|
||||
return 'https://expo.io';
|
||||
return 'https://exp.host';
|
||||
} else if (currentEnv === 'staging') {
|
||||
return 'https://staging.expo.io';
|
||||
return 'https://staging.exp.host';
|
||||
} else {
|
||||
return 'http://127.0.0.1:3000';
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import { URL } from 'url';
|
||||
|
||||
import request from 'request-promise';
|
||||
|
||||
import config from 'turtle/config';
|
||||
import { saveUpdateFailure } from 'turtle/updatesManager';
|
||||
|
||||
async function sendBuildStatusUpdate(buildId: string, updateParams: object) {
|
||||
const { href } = new URL(`/--/api/v2/turtle-legacy-builds/${buildId}`, resolveWWWEndpoint());
|
||||
try {
|
||||
await request({
|
||||
method: 'PUT',
|
||||
uri: href,
|
||||
headers: {
|
||||
'secret-token': config.www.secretToken,
|
||||
},
|
||||
body: updateParams,
|
||||
json: true,
|
||||
});
|
||||
} catch (err) {
|
||||
await saveUpdateFailure(buildId, 'build', updateParams);
|
||||
}
|
||||
}
|
||||
|
||||
async function sendCredentialsUpdate(buildId: string, platform: 'android' | 'ios', updateParams: object) {
|
||||
const { href } = new URL(`/--/api/v2/turtle-legacy-builds/${buildId}/credentials`, resolveWWWEndpoint());
|
||||
try {
|
||||
await request({
|
||||
method: 'PUT',
|
||||
uri: href,
|
||||
headers: {
|
||||
'secret-token': config.www.secretToken,
|
||||
},
|
||||
body: {
|
||||
platform,
|
||||
...updateParams,
|
||||
},
|
||||
json: true,
|
||||
});
|
||||
} catch (err) {
|
||||
await saveUpdateFailure(buildId, 'credentials', updateParams);
|
||||
}
|
||||
}
|
||||
|
||||
function resolveWWWEndpoint() {
|
||||
const currentEnv = config.deploymentEnv;
|
||||
if (currentEnv === 'production') {
|
||||
return 'https://exp.host';
|
||||
} else if (currentEnv === 'staging') {
|
||||
return 'https://staging.exp.host';
|
||||
} else {
|
||||
return 'http://127.0.0.1:3000';
|
||||
}
|
||||
}
|
||||
|
||||
export { sendBuildStatusUpdate, sendCredentialsUpdate };
|
||||
Reference in new issue
Block a user