mirror of
https://github.com/expo/turtle.git
synced 2026-11-14 19:12:55 -10:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee50169c4a |
No files matched your search
+17
-69
@@ -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: '10.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:
|
||||
@@ -77,49 +77,6 @@ commands:
|
||||
EOF
|
||||
chmod +x /bin/rm
|
||||
|
||||
install_nodejs_mac:
|
||||
parameters:
|
||||
nodejs_version:
|
||||
type: string
|
||||
default: 12.16.1
|
||||
yarn_version:
|
||||
type: string
|
||||
default: 1.22.0
|
||||
steps:
|
||||
- restore_cache:
|
||||
key: "node-js-v1-darwin-archive-<< parameters.nodejs_version >>"
|
||||
- run:
|
||||
name: Uninstall yarn with brew
|
||||
command: brew uninstall --force yarn
|
||||
- install_node_and_yarn:
|
||||
platform: darwin
|
||||
nodejs_version: "<< parameters.nodejs_version >>"
|
||||
yarn_version: "<< parameters.yarn_version >>"
|
||||
- save_cache:
|
||||
key: "node-js-v1-darwin-archive-<< parameters.nodejs_version >>"
|
||||
paths:
|
||||
- /private/tmp/nodejs.tar.xz
|
||||
|
||||
install_node_and_yarn:
|
||||
parameters:
|
||||
platform:
|
||||
type: string
|
||||
nodejs_version:
|
||||
type: string
|
||||
yarn_version:
|
||||
type: string
|
||||
steps:
|
||||
- run:
|
||||
name: Install node & yarn
|
||||
command: |
|
||||
NODEJS_ARCHIVE="/tmp/nodejs.tar.xz"
|
||||
if [ ! -f "$NODEJS_ARCHIVE" ]; then
|
||||
curl -o $NODEJS_ARCHIVE -SL "https://nodejs.org/dist/v<< parameters.nodejs_version >>/node-v<< parameters.nodejs_version >>-<< parameters.platform >>-x64.tar.xz"
|
||||
fi
|
||||
tar -xJf $NODEJS_ARCHIVE -C /usr/local --strip-components=1 --exclude CHANGELOG.md --exclude README.md --exclude LICENSE
|
||||
ln -s /usr/local/bin/node /usr/local/bin/nodejs
|
||||
npm install --global yarn@<< parameters.yarn_version >>
|
||||
|
||||
decrypt_secrets_if_possible:
|
||||
steps:
|
||||
- run:
|
||||
@@ -136,24 +93,18 @@ commands:
|
||||
workingdir:
|
||||
type: string
|
||||
default: .
|
||||
platform:
|
||||
type: string
|
||||
default: linux
|
||||
steps:
|
||||
- restore_cache:
|
||||
key: yarn-v3-<< parameters.platform >>-{{ checksum "<< parameters.workingdir >>/yarn.lock" }}
|
||||
key: yarn-v1-{{ checksum "<< parameters.workingdir >>/yarn.lock" }}
|
||||
|
||||
save_yarn_cache:
|
||||
parameters:
|
||||
workingdir:
|
||||
type: string
|
||||
default: .
|
||||
platform:
|
||||
type: string
|
||||
default: linux
|
||||
steps:
|
||||
- save_cache:
|
||||
key: yarn-v3-<< parameters.platform >>-{{ checksum "<< parameters.workingdir >>/yarn.lock" }}
|
||||
key: yarn-v1-{{ checksum "<< parameters.workingdir >>/yarn.lock" }}
|
||||
paths:
|
||||
- ~/.cache/yarn # `yarn cache dir`
|
||||
|
||||
@@ -164,10 +115,10 @@ commands:
|
||||
default: ios
|
||||
sdk_version:
|
||||
type: string
|
||||
default: sdk39
|
||||
default: sdk32
|
||||
steps:
|
||||
- restore_cache:
|
||||
key: "workingdir-v2-<< parameters.platform >>-<< parameters.sdk_version >>"
|
||||
key: "workingdir-v1-<< parameters.platform >>-<< parameters.sdk_version >>"
|
||||
|
||||
save_workingdir_cache:
|
||||
parameters:
|
||||
@@ -179,10 +130,10 @@ commands:
|
||||
default: ios
|
||||
sdk_version:
|
||||
type: string
|
||||
default: sdk39
|
||||
default: sdk32
|
||||
steps:
|
||||
- save_cache:
|
||||
key: "workingdir-v2-<< parameters.platform >>-<< parameters.sdk_version >>"
|
||||
key: "workingdir-v1-<< parameters.platform >>-<< parameters.sdk_version >>"
|
||||
paths:
|
||||
- "<< parameters.workingdir >>/<< parameters.platform >>/<< parameters.sdk_version >>"
|
||||
|
||||
@@ -229,23 +180,20 @@ jobs:
|
||||
executor: mac
|
||||
steps:
|
||||
- install_nix
|
||||
- install_nodejs_mac
|
||||
- setup
|
||||
- decrypt_secrets_if_possible
|
||||
- restore_yarn_cache:
|
||||
platform: darwin
|
||||
- restore_yarn_cache
|
||||
- run: yarn
|
||||
- save_yarn_cache:
|
||||
platform: darwin
|
||||
- save_yarn_cache
|
||||
- restore_workingdir_cache:
|
||||
sdk_version: sdk39
|
||||
sdk_version: sdk32
|
||||
platform: ios
|
||||
- run:
|
||||
name: Run iOS smoke tests
|
||||
command: SDK_VERSION=sdk39 ./scripts/tests/runIOSSmokeTestsCI.sh
|
||||
command: ./scripts/tests/runIOSSmokeTestsCI.sh
|
||||
- save_workingdir_cache:
|
||||
workingdir: /Users/distiller/project/workingdir
|
||||
sdk_version: sdk39
|
||||
sdk_version: sdk32
|
||||
platform: ios
|
||||
|
||||
android_smoke_tests:
|
||||
@@ -257,11 +205,11 @@ jobs:
|
||||
- run: yarn
|
||||
- save_yarn_cache
|
||||
- restore_workingdir_cache:
|
||||
sdk_version: sdk39
|
||||
sdk_version: sdk32
|
||||
platform: android
|
||||
- run:
|
||||
name: Fetch Android shell app
|
||||
command: SDK_VERSION=sdk39 ./scripts/android/fetchRemoteAndroidTarball.sh
|
||||
command: SDK_VERSION=sdk32 ./scripts/android/fetchRemoteAndroidTarball.sh
|
||||
- run:
|
||||
name: Run Android smoke tests
|
||||
command: |
|
||||
@@ -269,7 +217,7 @@ jobs:
|
||||
--run "./scripts/tests/runAndroidSmokeTestsCI.sh"
|
||||
- save_workingdir_cache:
|
||||
workingdir: ~/turtle/workingdir
|
||||
sdk_version: sdk39
|
||||
sdk_version: sdk32
|
||||
platform: android
|
||||
|
||||
android_staging_deploy:
|
||||
|
||||
@@ -22,6 +22,6 @@ export NODE_ENV=development
|
||||
export EXPO_TURTLE_TOOLS_DIR="$(pwd)/tools"
|
||||
|
||||
PATH_add $EXPO_TURTLE_TOOLS_DIR/bin
|
||||
if [ "$CI" = "true" ] && [[ ! $OSTYPE =~ darwin.* ]]; then
|
||||
if [ "$CI" = "true" ]; then
|
||||
PATH_add $EXPO_TURTLE_TOOLS_DIR/ci/bin
|
||||
fi
|
||||
+2
-3
@@ -1,3 +1,5 @@
|
||||
!/src/node_modules
|
||||
|
||||
node_modules
|
||||
yarn-error.log
|
||||
google-cloud-credentials.json
|
||||
@@ -5,9 +7,6 @@ google-cloud-credentials.json
|
||||
/build/
|
||||
/workingdir/*
|
||||
/artifacts/*
|
||||
.history
|
||||
.vscode/
|
||||
|
||||
shell.apk
|
||||
.secrets*
|
||||
|
||||
|
||||
@@ -10,9 +10,6 @@
|
||||
"release": true
|
||||
},
|
||||
"hooks": {
|
||||
"before:init": [
|
||||
"yarn"
|
||||
],
|
||||
"after:release": "yarn release:update:turtle-cli-example"
|
||||
}
|
||||
}
|
||||
@@ -6,4 +6,3 @@ SENTRY_DSN=""
|
||||
ENVIRONMENT="development"
|
||||
REDIS_URL="redis://localhost:6379/0"
|
||||
REDIS_CONFIG_URL="redis://localhost:6379/0"
|
||||
TURTLE_SDK_VERSIONS_SECRET_TOKEN="xeiw7yigha<a_r5aich!oW9Ik2eish8the9Na6Jae-ghoo5ua/t8nu5AeheiTew4"
|
||||
+3
-604
@@ -1,5 +1,4 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
@@ -7,852 +6,252 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## Unreleased
|
||||
|
||||
- Update Android tarball for SDK 42.
|
||||
|
||||
# [0.22.2] - 2021-06-29
|
||||
|
||||
- Update iOS tarball for SDK 42.
|
||||
|
||||
# [0.22.1] - 2021-06-29
|
||||
|
||||
- Update iOS and Android beta tarballs for SDK 42.
|
||||
|
||||
# [0.22.0] - 2021-06-22
|
||||
|
||||
- Add iOS and Android beta tarballs for SDK 42.
|
||||
|
||||
# [0.21.9] - 2021-06-15
|
||||
|
||||
- Update `sharp` package, fixes support for M1 macs.
|
||||
|
||||
# [0.21.8] - 2021-05-25
|
||||
|
||||
- Update Android SDK41 tarball.
|
||||
|
||||
# [0.21.7] - 2021-05-21
|
||||
|
||||
- Update iOS SDK41 tarball.
|
||||
- Update Android SDK41 tarball.
|
||||
|
||||
# [0.21.6] - 2021-04-22
|
||||
|
||||
- Update iOS SDK41 tarball.
|
||||
- Update Android SDK41 tarball.
|
||||
|
||||
# [0.21.5] - 2021-04-15
|
||||
|
||||
- Revert iOS client tarball for SDK 41, use the SDK 40 tarball. No longer supporting this feature in SDK 41+.
|
||||
- Update Android SDK 41 tarball.
|
||||
|
||||
# [0.21.4] - 2021-04-13
|
||||
|
||||
- Update iOS client tarball for SDK 41.
|
||||
|
||||
# [0.21.3] - 2021-04-13
|
||||
|
||||
- Update SDK 41 tarball for iOS and Android.
|
||||
|
||||
# [0.21.2] - 2021-04-07
|
||||
|
||||
- Update SDK 41 beta tarball for Android.
|
||||
|
||||
# [0.21.1] - 2021-04-01
|
||||
|
||||
- Update SDK 41 beta tarball for iOS.
|
||||
|
||||
# [0.21.0] - 2021-03-29
|
||||
|
||||
- Add SDK 41 beta tarballs.
|
||||
- Bump @expo/xdl to 59.1.0.
|
||||
|
||||
# [0.20.7] - 2021-01-26
|
||||
|
||||
- Remove Go suffix from android app name
|
||||
|
||||
# [0.20.6] - 2021-01-25
|
||||
|
||||
- Update tarballs for SDK 40 patch release (3e345dd)
|
||||
|
||||
# [0.20.5] - 2020-12-23
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated SDK 40 Android tarball to fix `expo-location` background permissions on Android <9.
|
||||
|
||||
# [0.20.4] - 2020-12-17
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated SDK 40 iOS tarball to fix `expo-notifications` not emitting initial notification response.
|
||||
|
||||
# [0.20.3] - 2020-12-10
|
||||
|
||||
### Fixed
|
||||
|
||||
- Verify jq installation before proceeding with release ([#281](https://github.com/expo/turtle/pull/281)).
|
||||
- Fixed the iOS build when running offline and user lacks elevated permissions.
|
||||
|
||||
# [0.20.2] - 2020-12-09
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated SDK 40 Android tarball to fix `expo-notifications` installation identifier changing as a bug.
|
||||
|
||||
# [0.20.1] - 2020-12-08
|
||||
|
||||
### Changed
|
||||
|
||||
- Update SDK 40 iOS and Android tarballs for release
|
||||
|
||||
# [0.20.0] - 2020-11-30
|
||||
|
||||
- Add SDK 40 tarballs in preparation for SDK 40 beta
|
||||
|
||||
# [0.19.1] - 2020-11-19
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed the iOS build using Xcode 12.1 by runnig `xcrun simctl list` before the build phase.
|
||||
- Rebuild iOS tarballs (SDK 36, 37, 38, 39, Ad-Hoc Client) with Xcode 12.1 containing iOS 14 image fix.
|
||||
|
||||
# [0.19.0] - 2020-11-13
|
||||
|
||||
### Changed
|
||||
|
||||
- Rebuild iOS tarballs (SDK 36, 37, 38, 39, Ad-Hoc Client) with Xcode 12.1.
|
||||
|
||||
# [0.18.9] - 2020-11-09
|
||||
|
||||
### Fixed
|
||||
|
||||
- Updated xdl to 58.0.20 to fix an issue with updates.checkAutomatically not being applied properly to SDK 39 Android apps.
|
||||
|
||||
# [0.18.8] - 2020-10-27
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix issues with Reanimated v2 in Android SDK 39 tarball.
|
||||
|
||||
# [0.18.7] - 2020-10-23
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix issue with updates in self-hosted Android apps ([#10746](https://github.com/expo/expo/issues/10746)) in the SDK 39 tarball
|
||||
|
||||
# [0.18.6] - 2020-10-22
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix issues with notifications ([10624](https://github.com/expo/expo/pull/10624) and [10608](https://github.com/expo/expo/pull/10608)) in the Android SDK 39 tarball.
|
||||
|
||||
# [0.18.5] - 2020-10-07
|
||||
|
||||
### Fixed
|
||||
|
||||
- Always add expo-notifications for SDK >= 39 projects with android.enableDangerousExperimentalLeanBuilds enabled.
|
||||
|
||||
# [0.18.4] - 2020-10-06
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed an issue with notifications ([expo/expo#10562](https://github.com/expo/expo/issues/10562)) in the Android SDK 39 tarball.
|
||||
|
||||
# [0.18.3] - 2020-10-03
|
||||
|
||||
### Fixed
|
||||
|
||||
- Update @expo/xdl to fix regression in SDK <= 39 splash
|
||||
|
||||
# [0.18.2] - 2020-10-03
|
||||
|
||||
### Fixed
|
||||
|
||||
- Updated SDK 39 Android tarball.
|
||||
- Updated SDK 39 iOS tarball.
|
||||
- Updated iOS client tarball.
|
||||
- Update @expo/config and @expo/xdl. Temporarily bring in type definitions for color-string and xcode.
|
||||
|
||||
## [0.18.1] - 2020-09-22
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix building apps using SDK 39 for Android.
|
||||
|
||||
## [0.18.0] - 2020-09-21
|
||||
|
||||
### Added
|
||||
|
||||
- Added iOS and Android shell apps for SDK 39.
|
||||
|
||||
### Removed
|
||||
|
||||
- Dropped support for SDK 35.
|
||||
|
||||
## [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
|
||||
|
||||
- Updated `@expo/xdl` to 57.8.30 (scoped the build command so it only builds the `:app` Android sub-project and not all the sub-projects available, [PR](https://github.com/expo/expo-cli/pull/1937)).
|
||||
|
||||
## [0.14.8] - 2020-04-20
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated `@expo/xdl` to 57.8.29 (removed call to `check-dynamic-macros-android.sh`, [PR](https://github.com/expo/expo-cli/pull/1933)).
|
||||
|
||||
## [0.14.7] - 2020-04-20
|
||||
|
||||
### Changed
|
||||
|
||||
- Turtle no longer installs all dependencies of shell apps projects — only the production dependencies are installed now.
|
||||
- Updated `@expo/xdl` to 57.8.25 (fixed unintuitive `google-services.json` handling for SDK37+, [PR](https://github.com/expo/expo-cli/pull/1897)).
|
||||
|
||||
## [0.14.6] - 2020-04-09
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated @expo/xdl to 57.8.17 (fixed downloading assets smaller than 10 bytes).
|
||||
|
||||
## [0.14.5] - 2020-04-06
|
||||
|
||||
### Changed
|
||||
|
||||
- Made @expo/config error more meaningful.
|
||||
|
||||
## [0.14.4] - 2020-04-06
|
||||
|
||||
### Fixed
|
||||
|
||||
- Determining SDK version for Expo apps using SDK >=37.
|
||||
|
||||
## [0.14.3] - 2020-04-03
|
||||
|
||||
### Fixed
|
||||
|
||||
- A fix for Android SDK 37 - `check-dynamic-macros-android.sh` doesn't use `jq` anymore.
|
||||
|
||||
## [0.14.1] - 2020-04-01
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated iOS shell app for SDK 37 to remove unnecessary unimodules.
|
||||
|
||||
## [0.14.0] - 2020-03-31
|
||||
|
||||
### Added
|
||||
|
||||
- Added iOS shell app for SDK 37.
|
||||
- Added Android shell app for SDK 37.
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated iOS client shell app to support SDK 37.
|
||||
- Replace `/` with `__` in the artifact filename to fix a strange bug with selecting APK file in Android Studio.
|
||||
- Print currently using Java version if it's not 8.
|
||||
|
||||
### Removed
|
||||
|
||||
- Dropped support for SDK 33.
|
||||
|
||||
## [0.13.10] - 2020-03-09
|
||||
|
||||
### Added
|
||||
|
||||
- Added validation for `--public-url`.
|
||||
|
||||
### Changed
|
||||
|
||||
- Changed the way of installing NDK - it's installed with `sdkmanager` now.
|
||||
- Upgraded NDK to 17.2.4988734.
|
||||
- Upgraded Node.js version to 12.16.1.
|
||||
|
||||
### Fixed
|
||||
|
||||
- A bug where the `platform` field in logs wasn't set correctly when using a shortcut command.
|
||||
- Removed all remaining instances of `UIWebView` in iOS app builds.
|
||||
|
||||
### Removed
|
||||
|
||||
- Dropped support for Node.js versions older than 10.
|
||||
- Dropped support for building Expo SDK 31 and 32 apps.
|
||||
|
||||
## [0.13.9] - 2020-02-13
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed Notifications.getDevicePushTokenAsync() erroring occasionally on iOS SDK 36.
|
||||
|
||||
## [0.13.8] - 2020-01-27
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed `react-native-maps` native module not being properly initialized (https://github.com/expo/expo/pull/6844)
|
||||
- Fixed Android standalone apps crashing on startup (https://github.com/expo/expo/pull/6825)
|
||||
|
||||
## [0.13.7] - 2020-01-15
|
||||
|
||||
### Added
|
||||
|
||||
- Bumped `traveling-fastlane` to 1.11.4 to update CA certs
|
||||
|
||||
## [0.13.6] - 2019-12-17
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed issue with missing request handler for assets-library urls.
|
||||
|
||||
## [0.13.4] - 2019-12-13
|
||||
|
||||
### Added
|
||||
|
||||
- Support for building iOS apps with a wildcard provisioning profile.
|
||||
|
||||
## [0.13.3] - 2019-12-12
|
||||
|
||||
### Fixed
|
||||
|
||||
- Removed private API usage from iOS SDK 36 tarball
|
||||
|
||||
## [0.13.2] - 2019-12-10
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed Android App Bundle builds
|
||||
- Fixed issue with Root View Background Color and AppLoading on Android SDK 36 builds
|
||||
|
||||
## [0.13.1] - 2019-12-09
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed Android shell app for SDK 36
|
||||
|
||||
## [0.13.0] - 2019-12-09
|
||||
|
||||
### Added
|
||||
|
||||
- Added iOS and Android shell apps for SDK 36
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated iOS client shell app to support SDK 36
|
||||
|
||||
## [0.12.12] - 2019-11-22
|
||||
|
||||
### Fixed
|
||||
|
||||
- A bug that caused `expo.owner` value not to be used if defined.
|
||||
|
||||
## [0.12.11] - 2019-11-20
|
||||
|
||||
### Added
|
||||
|
||||
- Bumped `traveling-fastlane` to 1.11.0
|
||||
|
||||
## [0.12.10] - 2019-11-15
|
||||
|
||||
### Added
|
||||
|
||||
- Add `shellAppSdkVersion` param to `IOSShellAppBuilder` so entitlement keys get properly added in (https://github.com/expo/turtle/pull/162)
|
||||
|
||||
## [0.12.9] - 2019-11-14
|
||||
|
||||
### Added
|
||||
|
||||
- Support for customizing Facebook SDK behavior at buildtime (autoinitialization, logging app events, logging Advertiser ID) (https://github.com/expo/expo/pull/5924)
|
||||
|
||||
## [0.12.8] - 2019-10-29
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated Android shell app for SDK 35 to fix `Linking.openUrl` not opening app if it's already foregrounded (https://github.com/expo/expo/issues/6058)
|
||||
- Enforce Java 8 when using turtle-cli.
|
||||
|
||||
## [0.12.7] - 2019-10-25
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated Android shell app for SDK 35 to fix occasional crash in background due to GCM registration service (https://github.com/expo/expo/issues/4207)
|
||||
|
||||
## [0.12.5] - 2019-10-18
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated iOS shell app for SDK 35 to fix crash when calling `WebBrowser.dismissBrowser` on iOS 13 (https://github.com/expo/expo/issues/5742)
|
||||
|
||||
## [0.12.4] - 2019-10-11
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated Android shell app for SDK 35 to fix occasional crash on launch (https://github.com/expo/expo/issues/5917)
|
||||
|
||||
## [0.12.3] - 2019-10-09
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated iOS client shell app for SDK 35 to fix it from crashing on startup due to having an incomplete GoogleService-Info.plist file.
|
||||
|
||||
## [0.12.2] - 2019-09-27
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated Android shell app for SDK 35 to fix crash on Android <=7 due to battery module
|
||||
|
||||
## [0.12.1] - 2019-09-20
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated iOS shell apps for SDK 33 and 34 to fix iOS 13 issues with fishhook, notification tokens, and ShareSheet
|
||||
- Updated iOS shell app for SDK 35 with a minor fix
|
||||
|
||||
## [0.12.0] - 2019-09-19
|
||||
|
||||
### Added
|
||||
|
||||
- Support for SDK 35 iOS and Android builds.
|
||||
|
||||
### Removed
|
||||
|
||||
- Support for SDK 27-30 iOS and Android builds.
|
||||
|
||||
## [0.11.3] - 2019-09-19
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated SDK34 Android shell app with `expo-branch` fixes.
|
||||
|
||||
## [0.11.2] - 2019-08-21
|
||||
|
||||
### Added
|
||||
|
||||
- Support for GoogleService-Info.plist (>=34.0.0).
|
||||
|
||||
## [0.11.1] - 2019-08-08
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated iOS client shell app with the latest fixes (up to 2.12.3).
|
||||
|
||||
## [0.11.0] - 2019-08-07
|
||||
|
||||
### Changed
|
||||
|
||||
- Enabled back optional modules support, but only for specific unimodules.
|
||||
- Updated SDK34 Android shell app with the latest fixes (up to 2.12.2).
|
||||
- Updated SDK34 iOS shell app with the latest fixes (up to 2.12.3).
|
||||
|
||||
## [0.10.0] - 2019-08-01
|
||||
|
||||
### Changed
|
||||
|
||||
- Fully disabled optional modules on Android for now.
|
||||
- Updated iOS shell apps for SDK 33 and 34 to fix scoped permissions issue.
|
||||
- Updated Android shell app for SDK 34 to work after disabling optional modules.
|
||||
|
||||
## [0.9.1] - 2019-07-29
|
||||
|
||||
### Changed
|
||||
|
||||
- `release-it` version to `12.3.4`.
|
||||
|
||||
## [0.9.0] - 2019-07-29
|
||||
|
||||
### Added
|
||||
|
||||
- Android, iOS standalone shell apps and iOS Expo client shell app for SDK34.
|
||||
- Xcode license check for iOS builds.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Setting `Constants.nativeAppVersion` for Android standalone builds (actually fixed in [expo/expo-cli#878](https://github.com/expo/expo-cli/pull/878)).
|
||||
- Passing `expo.android.config` object from `app.json` to the Android builder.
|
||||
- Fixed crash on launch for iOS standalone apps on iOS 13 (all SDK versions).
|
||||
- Fixed occasional issue on iOS (SDK 33) where the JS bundle cannot be found ("No cache exists for this resource: shell-app.bundle") and a reload would be required.
|
||||
|
||||
## [0.8.11] - 2019-07-16
|
||||
|
||||
### Fixed
|
||||
|
||||
- Android debug builds.
|
||||
|
||||
## [0.8.10] - 2019-07-16
|
||||
|
||||
### Fixed
|
||||
|
||||
- iOS simulator builds.
|
||||
|
||||
## [0.8.9] - 2019-07-15
|
||||
|
||||
### Fixed
|
||||
|
||||
- User authentication.
|
||||
|
||||
## [0.8.8] - 2019-07-11
|
||||
|
||||
### Fixed
|
||||
|
||||
- LocalAuthentication module on iOS (fixes [expo/expo#663](https://github.com/expo/expo/issues/663)).
|
||||
|
||||
## [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
|
||||
|
||||
- Running Android Turtle process with `supervisor` (pod is restarted if there were 5 failures in the last 10 minutes).
|
||||
|
||||
### Changed
|
||||
|
||||
- `turtle-cli` is now fetching the app manifest before running the build.
|
||||
|
||||
## [0.8.2] - 2019-06-11
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated Android shell app for SDK33 to remove `expo-face-detector` and `expo-payments-stripe` from standalone builds.
|
||||
- Updated Android shell app for SDK33 to get rid of `node_modules` for `tools-public`.
|
||||
- From now on, `turtle-cli` installs dependencies for `tools-public` in shell apps for SDK versions < 33.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Android builds with turtle-cli by installing all unmodules if `dependencies` is empty.
|
||||
|
||||
## [0.8.1] - 2019-06-10
|
||||
|
||||
### Changed
|
||||
|
||||
- Add expo dependencies when resolving unimodules.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Support for Android tarballs without `universe-package.json`.
|
||||
|
||||
## [0.8.0] - 2019-06-07
|
||||
|
||||
### Added
|
||||
|
||||
- Turtle CLI logo to the project (created by [@zularizal](https://github.com/zularizal))!
|
||||
- Shell apps for SDK 33.
|
||||
- Support for Android App Bundles (App bundles are built by default, use `-t apk` to build apk).
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated Android shell app for SDK 32 to fix AppAuth issue (https://github.com/expo/expo/pull/4115) and to fix a newer than expected JSC version.
|
||||
- Default value for build timeout to 15 minutes.
|
||||
- Added filtering of logs (strips out download progress) when downloading SDK tools.
|
||||
- `xdl` -> `@expo/xdl`, updated `@expo/xdl`.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Generating Android keystore in turtle when one is not passed to turtle-cli (https://github.com/expo/turtle/pull/65).
|
||||
- Upload logs to s3 if build has been canceled or timed out.
|
||||
- Unhandled exception on asset download (xdl).
|
||||
|
||||
## [0.7.2] - 2019-05-09
|
||||
|
||||
### Added
|
||||
|
||||
- Support for Android tarballs without `universe-package.json`.
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgraded `@expo/traveling-fastlane-darwin` to 1.9.4 (fixes issues with generating provisioning profiles for ad-hoc builds).
|
||||
|
||||
### Removed
|
||||
|
||||
- Support for `CLIENT_LOGGER_LEVEL` env variable.
|
||||
|
||||
## [0.7.1] - 2019-05-06
|
||||
|
||||
### Fixed
|
||||
|
||||
- Resolving `fastlane` version when `LC_ALL` is not set.
|
||||
|
||||
## [0.7.0] - 2019-05-06
|
||||
|
||||
### Added
|
||||
|
||||
- Support for custom Android builds.
|
||||
|
||||
### Changed
|
||||
|
||||
- Refactored logger.
|
||||
|
||||
### Fixed
|
||||
|
||||
- `platform` log field wrongly set to `ios` for Android builds (when using `turtle-cli`).
|
||||
- Brought back `jobID` and `experienceName` fields to Android logs.
|
||||
|
||||
## [0.6.1] - 2019-04-23
|
||||
|
||||
### Added
|
||||
|
||||
- Checking fastlane version before running build (turtle-cli).
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated iOS shell app for SDK 32 to fix AppAuth issue.
|
||||
- Babel replaced by ttypescript.
|
||||
- Updated xdl to 53.5.3 and @expo/spawn-async to 1.4.2, so that error stack traces should be more informative now.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Brought back `jobID` and `experienceName` fields to GCloud logs.
|
||||
|
||||
### Removed
|
||||
|
||||
- `buidAndroidTarballLocally.sh` script (it has been moved to expo repository - [expo/expo#4022](https://github.com/expo/expo/pull/4022)).
|
||||
|
||||
## [0.6.0] - 2019-04-09
|
||||
|
||||
### Changed
|
||||
|
||||
- Removed Branch module from Android shell apps for all SDK versions.
|
||||
|
||||
## [0.5.15] - 2019-04-03
|
||||
|
||||
### Added
|
||||
|
||||
- Turtle smoke tests are now being executed on CircleCI from the context of this repository.
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated iOS shell app for SDK 32 (fixes [this loading issue for slow connections](https://github.com/expo/expo/issues/3574)).
|
||||
- Minor infra changes (doesn't affect users).
|
||||
- Error logs format - error objects are now passed in an object being passed as the first argument to logger function.
|
||||
|
||||
### Removed
|
||||
|
||||
- Sending logs to loggly.
|
||||
|
||||
## [0.5.14] - 2019-03-22
|
||||
|
||||
### Added
|
||||
|
||||
- `--config` parameter for turtle-cli commands, which allows to specify a custom path to app.json file
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated iOS shell app for SDK 32 (fixes [this notifications issue](https://github.com/expo/expo/issues/3663)).
|
||||
|
||||
## [0.5.13] - 2019-03-12
|
||||
|
||||
### Added
|
||||
|
||||
- Android SDK version support validation.
|
||||
|
||||
### Changed
|
||||
|
||||
- iOS Enterprise builds don't compile bitcode now.
|
||||
|
||||
## [0.5.12] - 2019-02-26
|
||||
|
||||
### Added
|
||||
|
||||
- Google Cloud logger (as a bunyan stream).
|
||||
|
||||
### Changed
|
||||
|
||||
- Android builder passes the manifest from a build job message if it's available.
|
||||
|
||||
## [0.5.11] - 2019-02-22
|
||||
|
||||
### Added
|
||||
|
||||
- Builder for iOS client apps.
|
||||
|
||||
## [0.5.10] - 2019-02-19
|
||||
|
||||
### Added
|
||||
|
||||
- Registering Turtle version in Redis.
|
||||
|
||||
### Changed
|
||||
|
||||
- Update Android shell app for SDK 32 to fix [update](https://github.com/expo/expo/issues/3504) and [back button](https://github.com/expo/expo/issues/1786) issues.
|
||||
|
||||
## [0.5.9] - 2019-02-06
|
||||
|
||||
- Update iOS shell app for SDK 32 (fixes bare notifications [issue](https://github.com/expo/expo/issues/3223)).
|
||||
|
||||
## [0.5.7] - 2019-01-31
|
||||
|
||||
- Update Android shell app for SDK 32 to fix bundled assets issue.
|
||||
|
||||
## [0.5.6] - 2019-01-25
|
||||
|
||||
- Update iOS shell app for SDK 30, 31 and 32 (built with xcode 10.1).
|
||||
|
||||
## [0.5.5] - 2019-01-24
|
||||
|
||||
### Added
|
||||
|
||||
- Sending build duration in AWS SQS messages (of `FINISHED` and `ERRORED` types).
|
||||
|
||||
## [0.5.4] - 2019-01-22
|
||||
|
||||
### Changed
|
||||
|
||||
- Update iOS shell app for SDK32 to [`expo/expo#0847c10`](https://github.com/expo/expo/commit/0847c1073d38c366866f3d9279ddd662da47dc9b), i.e. v2.10.3 with fixed WebView navigation scheme and upgraded Facebook SDK.
|
||||
|
||||
## [0.5.3] - 2019-01-21
|
||||
|
||||
### Fixed
|
||||
|
||||
- Building Android standalone apps ([not accepted license issue](https://github.com/expo/expo/issues/3266)) - updated Android build tools (`build-tools;28.0.3`, `platforms;android-28`).
|
||||
|
||||
## [0.5.2] - 2019-01-18
|
||||
|
||||
### Added
|
||||
|
||||
- The link (in README) to the repository containing `turtle-cli` usage example.
|
||||
- [Contributing guide](CONTRIBUTING.md).
|
||||
- [Code of Conduct](CODE_OF_CONDUCT.md).
|
||||
|
||||
### Removed
|
||||
|
||||
- `eslint`
|
||||
|
||||
### Changed
|
||||
|
||||
- Fix all `tslint` errors.
|
||||
|
||||
## [0.5.1] - 2019-01-16
|
||||
|
||||
### Changed
|
||||
|
||||
- Update Android shell app for SDK32 that includes `[email protected]`.
|
||||
|
||||
## [0.5.0] - 2019-01-16
|
||||
|
||||
### Added
|
||||
|
||||
- Turtle version is added to the `onFinish` and `onError` build messages.
|
||||
|
||||
### Changed
|
||||
|
||||
- A version property value being sent to the queue. It's now the version number
|
||||
from `package.json` instead of `new`/`old` indicator.
|
||||
|
||||
from `package.json` instead of `new`/`old` indicator.
|
||||
### Removed
|
||||
|
||||
- `--push-p12-path` parameter for `turtle build:ios` command,
|
||||
a Push Notifications Certificate is no longer required to perform a successful
|
||||
iOS standalone app build.
|
||||
a Push Notifications Certificate is no longer required to perform a successful
|
||||
iOS standalone app build.
|
||||
|
||||
## [0.4.3] - 2019-01-09
|
||||
|
||||
### Changed
|
||||
|
||||
- Update iOS shell app for SDK32.
|
||||
- Update Android shell app for SDK32.
|
||||
+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_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_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
|
||||
|
||||
+18
-17
@@ -1,28 +1,29 @@
|
||||
# see docker-base/Dockerfile to learn what's installed in the turtle-android-base image
|
||||
FROM gcr.io/exponentjs/turtle-android-base:0.5.0
|
||||
FROM gcr.io/exponentjs/turtle-android-base:0.1.0
|
||||
|
||||
ADD . /app/turtle
|
||||
|
||||
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
|
||||
RUN mv /app/turtle/workingdir /app && \
|
||||
for SDK_VERSION in `ls /app/workingdir/android/`; do \
|
||||
echo "preparing $SDK_VERSION shell app" && \
|
||||
cd /app/workingdir/android/$SDK_VERSION && \
|
||||
if [ -f universe-package.json ]; then \
|
||||
mv package.json exponent-package.json && \
|
||||
mv universe-package.json package.json && \
|
||||
yarn install && \
|
||||
mv package.json universe-package.json && \
|
||||
mv exponent-package.json package.json; \
|
||||
else \
|
||||
yarn install; \
|
||||
fi \
|
||||
; done && \
|
||||
mv /app/workingdir /app/turtle
|
||||
|
||||
ENV NODE_ENV "production"
|
||||
ENV TURTLE_WORKING_DIR_PATH /app/turtle/workingdir/
|
||||
|
||||
WORKDIR /app/turtle
|
||||
|
||||
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"]
|
||||
@@ -21,7 +21,7 @@ You can use it both on your CI and your private computer.
|
||||
|
||||
## Installation
|
||||
|
||||
[Installation instructions and documentation here.](https://docs.expo.io/distribution/turtle-cli/)
|
||||
[Installation instructions and documentation here.](https://docs.expo.io/versions/latest/distribution/turtle-cli)
|
||||
|
||||
## Usage example
|
||||
|
||||
|
||||
+1
-12
@@ -3,18 +3,7 @@
|
||||
|
||||
const subcommand = process.argv[2];
|
||||
if (subcommand) {
|
||||
let platform;
|
||||
if (subcommand.length === 2) {
|
||||
const letter = subcommand[1];
|
||||
if (letter === 'a') {
|
||||
platform = 'android';
|
||||
} else if (letter === 'i') {
|
||||
platform = 'ios';
|
||||
}
|
||||
} else {
|
||||
const [, maybePlatform] = subcommand.split(':');
|
||||
platform = maybePlatform;
|
||||
}
|
||||
const [, platform] = subcommand.split(':');
|
||||
if (platform === 'ios' || platform === 'android') {
|
||||
// so that logs have correct platform set
|
||||
process.env.PLATFORM = platform;
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
configureAndroidSdk.sh
|
||||
+31
-39
@@ -17,7 +17,6 @@ RUN dpkg --add-architecture i386 && \
|
||||
build-essential\
|
||||
bzip2:i386\
|
||||
file\
|
||||
jq\
|
||||
lib32ncurses5\
|
||||
lib32z1\
|
||||
libc6:i386\
|
||||
@@ -32,7 +31,7 @@ RUN dpkg --add-architecture i386 && \
|
||||
apt-get clean
|
||||
|
||||
ENV NPM_CONFIG_LOGLEVEL warn
|
||||
ENV NODE_VERSION 12.16.1
|
||||
ENV NODE_VERSION 8.12.0
|
||||
|
||||
RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
|
||||
&& tar -xJf "node-v$NODE_VERSION-linux-x64.tar.xz" -C /usr/local --strip-components=1 \
|
||||
@@ -55,46 +54,39 @@ ENV PATH ${ANDROID_HOME}/tools:${PATH}
|
||||
ENV PATH ${ANDROID_HOME}/tools/bin:${PATH}
|
||||
ENV PATH ${ANDROID_HOME}/build-tools/28.0.3/:${PATH}
|
||||
|
||||
ADD configureAndroidSdk.sh /tmp/configureAndroidSdk.sh
|
||||
ADD scripts/android/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
|
||||
|
||||
# Install Android NDK
|
||||
ENV ANDROID_NDK_VERSION android-ndk-r10e
|
||||
ENV ANDROID_NDK_FILE ${ANDROID_NDK_VERSION}-linux-x86_64.bin
|
||||
ENV ANDROID_NDK_URL https://dl.google.com/android/ndk/${ANDROID_NDK_FILE}
|
||||
ENV ANDROID_NDK /opt/${ANDROID_NDK_VERSION}
|
||||
ENV PATH $ANDROID_NDK:$PATH
|
||||
|
||||
# i have no clue why some of this is here, but it's working elsewhere
|
||||
# it appears to install the NDK version expo needs, so that's cool
|
||||
RUN mkdir /ndk_setup && cd /ndk_setup && \
|
||||
curl -L ${ANDROID_NDK_URL} > ${ANDROID_NDK_FILE} && \
|
||||
chmod +x ${ANDROID_NDK_FILE} && \
|
||||
sync && \
|
||||
./${ANDROID_NDK_FILE} && \
|
||||
mv ./${ANDROID_NDK_VERSION} ${ANDROID_NDK} && \
|
||||
cp -R \
|
||||
${ANDROID_NDK}/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64 \
|
||||
${ANDROID_NDK}/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86 && \
|
||||
cp -R \
|
||||
${ANDROID_NDK}/toolchains/x86-4.8/prebuilt/linux-x86_64 \
|
||||
${ANDROID_NDK}/toolchains/x86-4.8/prebuilt/linux-x86 && \
|
||||
cd && rm -rf /ndk_setup
|
||||
|
||||
# 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
|
||||
RUN cp -r gradle-5.6.3 /usr/local
|
||||
|
||||
RUN mkdir -p /root/.gradle/wrapper/dists/gradle-5.6.3-all/7wpcz6s7ut7bllr9k6e1hazxc
|
||||
RUN mv gradle-5.6.3-all.zip /root/.gradle/wrapper/dists/gradle-5.6.3-all/7wpcz6s7ut7bllr9k6e1hazxc
|
||||
RUN mv gradle-5.6.3 /root/.gradle/wrapper/dists/gradle-5.6.3-all/7wpcz6s7ut7bllr9k6e1hazxc
|
||||
RUN touch /root/.gradle/wrapper/dists/gradle-5.6.3-all/7wpcz6s7ut7bllr9k6e1hazxc/gradle-5.6.3-all.zip.ok
|
||||
RUN touch /root/.gradle/wrapper/dists/gradle-5.6.3-all/7wpcz6s7ut7bllr9k6e1hazxc/gradle-5.6.3-all.zip.lck
|
||||
RUN chmod 755 /root/.gradle/wrapper/dists/gradle-5.6.3-all/7wpcz6s7ut7bllr9k6e1hazxc/gradle-5.6.3/bin/gradle
|
||||
|
||||
ENV GRADLE_HOME /usr/local/gradle-5.6.3
|
||||
# Install gradle
|
||||
RUN wget https://services.gradle.org/distributions/gradle-4.4-all.zip
|
||||
RUN unzip -qq gradle-4.4-all.zip
|
||||
RUN mv gradle-4.4 /usr/local
|
||||
RUN rm gradle-4.4-all.zip
|
||||
ENV GRADLE_HOME /usr/local/gradle-4.4
|
||||
ENV PATH ${GRADLE_HOME}/bin:$PATH
|
||||
|
||||
# Install gradle 4.10.2
|
||||
RUN wget https://services.gradle.org/distributions/gradle-4.10.2-all.zip
|
||||
RUN mkdir -p /root/.gradle/wrapper/dists/gradle-4.10.2-all/9fahxiiecdb76a5g3aw9oi8rv
|
||||
RUN unzip -qq gradle-4.10.2-all.zip
|
||||
RUN mv gradle-4.10.2-all.zip /root/.gradle/wrapper/dists/gradle-4.10.2-all/9fahxiiecdb76a5g3aw9oi8rv
|
||||
RUN mv gradle-4.10.2 /root/.gradle/wrapper/dists/gradle-4.10.2-all/9fahxiiecdb76a5g3aw9oi8rv
|
||||
RUN touch /root/.gradle/wrapper/dists/gradle-4.10.2-all/9fahxiiecdb76a5g3aw9oi8rv/gradle-4.10.2-all.zip.ok
|
||||
RUN touch /root/.gradle/wrapper/dists/gradle-4.10.2-all/9fahxiiecdb76a5g3aw9oi8rv/gradle-4.10.2-all.zip.lck
|
||||
RUN chmod 755 /root/.gradle/wrapper/dists/gradle-4.10.2-all/9fahxiiecdb76a5g3aw9oi8rv/gradle-4.10.2/bin/gradle
|
||||
@@ -88,6 +88,11 @@ 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:
|
||||
@@ -133,26 +138,19 @@ spec:
|
||||
secretKeyRef:
|
||||
name: turtle-js-config
|
||||
key: datadog_app_key
|
||||
- name: TURTLE_SDK_VERSIONS_SECRET_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: turtle-js-config
|
||||
key: turtle_sdk_versions_secret_token
|
||||
# other vars
|
||||
- name: GRADLE_DAEMON_DISABLED
|
||||
value: "1"
|
||||
- name: DISABLE_DEX_MAX_HEAP
|
||||
value: "true"
|
||||
- name: JAVA_OPTS
|
||||
value: '-Xms2048m -Xmx12g -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC'
|
||||
value: '-Xms2048m -XX:+HeapDumpOnOutOfMemoryError -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:+UseG1GC'
|
||||
- name: GRADLE_OPTS
|
||||
value: '-Dorg.gradle.parallel=true -Dorg.gradle.configureondemand=true -Dorg.gradle.daemon=false -Dorg.gradle.jvmargs="-Xms2048m -Xmx12g -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC"'
|
||||
- name: REDIS_CA_CERTIFICATE
|
||||
value: '/var/run/config/redislabs-tls/redislabs_ca.pem'
|
||||
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"'
|
||||
resources:
|
||||
requests:
|
||||
memory: "12Gi"
|
||||
cpu: "3000m"
|
||||
memory: "8192Mi"
|
||||
cpu: "2000m"
|
||||
limits:
|
||||
memory: "12Gi"
|
||||
cpu: "3500m"
|
||||
memory: "8192Mi"
|
||||
cpu: "2000m"
|
||||
@@ -1,5 +1,5 @@
|
||||
self: super:
|
||||
|
||||
{
|
||||
nodejs = super.nodejs-12_x;
|
||||
nodejs = super.nodejs-8_x;
|
||||
}
|
||||
+21
-87
@@ -2,78 +2,11 @@ with (import ./default.nix {});
|
||||
|
||||
let
|
||||
|
||||
# These expressions can be deleted when react native depends on version of
|
||||
# ndk present in nixpkgs.
|
||||
os = if stdenv.system == "x86_64-linux" then "linux"
|
||||
else if stdenv.system == "x86_64-darwin" then "macosx" else throw "unsupported system architecture: ${stdenv.system}";
|
||||
ndk_17c_src = if stdenv.isDarwin then fetchurl {
|
||||
url = http://dl.google.com/android/repository/android-ndk-r17c-darwin-x86_64.zip;
|
||||
sha256 = "11iyxgqp017fchn54kkns9mrax73m73xm5wgis266dsq2g36dn73";
|
||||
} else fetchurl {
|
||||
url = https://dl.google.com/android/repository/android-ndk-r17c-linux-x86_64.zip;
|
||||
sha256 = "12b5h5p8b2ia38825dnnacn7b47c0inpys8jp82r42iks3dilm1z";
|
||||
};
|
||||
ndk_runtime_paths = lib.makeBinPath [ coreutils file findutils gawk gnugrep gnused jdk python3 which ]; #+ ":${platform-tools}/platform-tools";
|
||||
ndk = stdenv.mkDerivation {
|
||||
name = "ndk-17c";
|
||||
src = ndk_17c_src;
|
||||
buildInputs = [ unzip autoPatchelfHook makeWrapper python2 ] ++ lib.optional (os == "linux") [ glibc stdenv.cc.cc ncurses5 zlib libcxx.out ];
|
||||
unpackPhase = ''
|
||||
mkdir extractedzip
|
||||
cd extractedzip
|
||||
unpackFile "$src"
|
||||
if [ "$(find . -mindepth 1 -maxdepth 1 -type d | wc -l)" -eq 1 ]
|
||||
then
|
||||
cd "$(find . -mindepth 1 -maxdepth 1 -type d)"
|
||||
fi
|
||||
sourceRoot="$PWD"
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
packageBaseDir=$out/libexec/android-sdk/ndk-bundle
|
||||
mkdir -p $packageBaseDir
|
||||
cd $packageBaseDir
|
||||
cp -av $sourceRoot/* .
|
||||
'' + lib.optionalString (os == "linux") ''
|
||||
patchShebangs .
|
||||
wrapProgram $(pwd)/build/tools/make_standalone_toolchain.py --prefix PATH : "${ndk_runtime_paths}"
|
||||
rm -rf docs tests
|
||||
# Patch the executables of the toolchains, but not the libraries -- they are needed for crosscompiling
|
||||
addAutoPatchelfSearchPath $out/libexec/android-sdk/ndk-bundle/toolchains/renderscript/prebuilt/linux-x86_64/lib64
|
||||
find toolchains -type d -name bin | while read dir
|
||||
do
|
||||
autoPatchelf "$dir"
|
||||
done
|
||||
# fix ineffective PROGDIR / MYNDKDIR determination
|
||||
for i in ndk-build
|
||||
do
|
||||
sed -i -e 's|^PROGDIR=`dirname $0`|PROGDIR=`dirname $(readlink -f $(which $0))`|' $i
|
||||
done
|
||||
# Patch executables
|
||||
autoPatchelf prebuilt/linux-x86_64
|
||||
# wrap
|
||||
for i in ndk-build
|
||||
do
|
||||
wrapProgram "$(pwd)/$i" --prefix PATH : "${ndk_runtime_paths}"
|
||||
done
|
||||
# make some executables available in PATH
|
||||
mkdir -p $out/bin
|
||||
for i in ndk-build
|
||||
do
|
||||
ln -sf ../../libexec/android-sdk/ndk-bundle/$i $out/bin/$i
|
||||
done
|
||||
'';
|
||||
dontStrip = true;
|
||||
dontPatchELF = true;
|
||||
dontAutoPatchelf = true;
|
||||
noAuditTmpdir = true;
|
||||
};
|
||||
ndkRoot = "${ndk}/libexec/android-sdk/ndk-bundle";
|
||||
|
||||
sdk = androidenv.androidPkgs_9_0.androidsdk;
|
||||
sdk_path = if stdenv.isDarwin
|
||||
then "/Library/Android/sdk"
|
||||
else "/Android/Sdk"; # intentional Capital S
|
||||
ndk = androidenv.androidndk_17c.override { fullNDK = true; };
|
||||
ndk_root = "${ndk}/libexec/${ndk.name}";
|
||||
sdk_path = if stdenv.isDarwin
|
||||
then "/Library/Android/sdk"
|
||||
else "/Android/Sdk"; # intentional Capital S
|
||||
|
||||
in
|
||||
|
||||
@@ -90,27 +23,28 @@ mkShell rec {
|
||||
nativeBuildInputs = [
|
||||
awscli
|
||||
curl
|
||||
fastlane
|
||||
git
|
||||
nodejs
|
||||
nodejs-8_x
|
||||
openjdk8
|
||||
yarn
|
||||
];
|
||||
|
||||
passthru = { inherit ndk ndkRoot; };
|
||||
passthru = { inherit ndk; };
|
||||
|
||||
shellHook = ''
|
||||
${./install-ndk-17c.sh} ${ndk} ${ndkRoot}
|
||||
# grep -v = should clean up build logs, see https://stackoverflow.com/a/52464819/1123156
|
||||
yes | ${sdk}/bin/sdkmanager --sdk_root="$ANDROID_SDK_ROOT" "build-tools;28.0.3" | grep -v =
|
||||
'' + lib.optionalString stdenv.isLinux ''
|
||||
for dep in lib lib64; do
|
||||
if [ -L /$dep ] || [ ! -e /$dep ]; then
|
||||
echo "Creating /$dep"
|
||||
ln -s ${stdenv.cc.libc}/$dep /$dep
|
||||
else
|
||||
echo "Using existing /$dep"
|
||||
fi
|
||||
done
|
||||
${./install-ndk-17c.sh} ${ndk} ${ndk_root}
|
||||
yes | ${androidenv.androidsdk_9_0}/bin/sdkmanager --licenses --sdk_root="$ANDROID_SDK_ROOT"
|
||||
yes | ${androidenv.androidsdk_9_0}/bin/sdkmanager --sdk_root="$ANDROID_SDK_ROOT" "platforms;android-28" | grep -v =
|
||||
yes | ${androidenv.androidsdk_9_0}/bin/sdkmanager --sdk_root="$ANDROID_SDK_ROOT" "build-tools;28.0.3" | grep -v =
|
||||
${lib.optionalString stdenv.isLinux ''
|
||||
for dep in lib lib64; do
|
||||
if [ -L /$dep ] || [ ! -e /$dep ]; then
|
||||
echo "Creating /$dep"
|
||||
ln -s ${stdenv.cc.libc}/$dep /$dep
|
||||
else
|
||||
echo "Using existing /$dep"
|
||||
fi
|
||||
done
|
||||
''}
|
||||
'';
|
||||
}
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"url": "https://github.com/NixOS/nixpkgs-channels.git",
|
||||
"rev": "42f0be81ae05a8fe6d6e8e7f1c28652e7746e046",
|
||||
"date": "2020-03-01T07:21:40-03:00",
|
||||
"sha256": "1rxb5kmghkzazqcv4d8yczdiv2srs4r7apx4idc276lcikm0hdmf",
|
||||
"rev": "80738ed9dc0ce48d7796baed5364eef8072c794d",
|
||||
"date": "2018-11-17T11:18:10+01:00",
|
||||
"sha256": "0anmvr6b47gbbyl9v2fn86mfkcwgpbd5lf0yf3drgm8pbv57c1dc",
|
||||
"fetchSubmodules": false
|
||||
}
|
||||
+12
-24
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "turtle-cli",
|
||||
"version": "0.22.3",
|
||||
"version": "0.12.2",
|
||||
"description": "The command-line tool for building standalone Expo apps",
|
||||
"preferGlobal": true,
|
||||
"scripts": {
|
||||
@@ -22,9 +22,7 @@
|
||||
"test:unit": "yarn test --config jest/unit-config.json",
|
||||
"test:smoke": "yarn test --config jest/smoke-config.json --forceExit",
|
||||
"test:smoke:android": "PLATFORM=android yarn test:smoke --testNamePattern=android",
|
||||
"test:smoke:android:record": "PLATFORM=android EXPENV_OVERRIDES=local-common,local,local-queue expenv yarn test:smoke --testNamePattern=android",
|
||||
"test:smoke:ios": "PLATFORM=ios yarn test:smoke --testNamePattern=iOS",
|
||||
"test:smoke:ios:record": "PLATFORM=ios EXPENV_OVERRIDES=local-common,local,local-queue expenv yarn test:smoke --testNamePattern=iOS",
|
||||
"release": "./scripts/release.sh",
|
||||
"release:beta": "./scripts/releaseBeta.sh",
|
||||
"release:update:turtle-cli-example": "./scripts/updateTurtleCliExampleRepo.sh",
|
||||
@@ -55,7 +53,7 @@
|
||||
"react-native"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
"node": ">=8"
|
||||
},
|
||||
"author": "Expo <[email protected]>",
|
||||
"license": "MIT",
|
||||
@@ -68,47 +66,42 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@expo/babel-preset-cli": "^0.1.3",
|
||||
"@types/color-string": "^1.5.0",
|
||||
"@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.9.7",
|
||||
"@types/npm-package-arg": "^6.1.0",
|
||||
"@types/progress": "^2.0.1",
|
||||
"@types/raven": "^2.5.1",
|
||||
"@types/request": "^2.47.1",
|
||||
"@types/request-promise": "^4.1.44",
|
||||
"@types/semver": "^6.0.0",
|
||||
"@types/sharp": "0.28.3",
|
||||
"@types/sharp": "^0.17.8",
|
||||
"@types/tar": "^4.0.0",
|
||||
"@types/uuid": "^3.4.3",
|
||||
"@types/webpack": "^4.32.1",
|
||||
"@types/webpack-dev-server": "^3.1.7",
|
||||
"@types/which": "^1.3.1",
|
||||
"husky": "^1.3.1",
|
||||
"jest": "^26.1.0",
|
||||
"jest": "^23.6.0",
|
||||
"lint-staged": "^8.1.5",
|
||||
"nock": "^10.0.1",
|
||||
"nodemon": "^2.0.2",
|
||||
"nodemon": "^1.18.11",
|
||||
"release-it": "^12.3.4",
|
||||
"rimraf": "^2.6.2",
|
||||
"ts-jest": "^26.1.2",
|
||||
"ts-jest": "^23.10.4",
|
||||
"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.9.5"
|
||||
"typescript": "^3.4.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@expo/config": "~3.3.9",
|
||||
"@expo/spawn-async": "^1.4.2",
|
||||
"@expo/xdl": "59.1.0",
|
||||
"@google-cloud/logging-bunyan": "^2.0.3",
|
||||
"@expo/xdl": "56.2.2-alpha.2",
|
||||
"@google-cloud/logging-bunyan": "^0.9.5",
|
||||
"async-retry": "^1.2.1",
|
||||
"aws-sdk": "^2.226.1",
|
||||
"bunyan": "^1.8.12",
|
||||
@@ -119,7 +112,7 @@
|
||||
"decompress": "^4.2.0",
|
||||
"dogapi": "^2.8.3",
|
||||
"fs-extra": "^6.0.0",
|
||||
"ioredis": "^4.17.3",
|
||||
"ioredis": "^3.2.2",
|
||||
"is-semver": "^1.0.8",
|
||||
"joi": "^13.2.0",
|
||||
"lodash": "^4.17.11",
|
||||
@@ -127,19 +120,14 @@
|
||||
"raven": "^2.6.2",
|
||||
"request": "^2.88.0",
|
||||
"request-progress": "^3.0.0",
|
||||
"request-promise": "^4.2.5",
|
||||
"semver": "^6.0.0",
|
||||
"sharp": "0.28.3",
|
||||
"sharp": "0.22.1",
|
||||
"source-map-support": "^0.5.6",
|
||||
"tar": "^4.4.6",
|
||||
"uuid": "^3.2.1",
|
||||
"which": "^1.3.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@expo/traveling-fastlane-darwin": "1.11.4"
|
||||
},
|
||||
"volta": {
|
||||
"node": "12.16.1",
|
||||
"yarn": "1.22.0"
|
||||
"@expo/traveling-fastlane-darwin": "1.9.9"
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
this is just a placeholder to simplify deployments
|
||||
@@ -3,8 +3,6 @@
|
||||
set -eo pipefail
|
||||
|
||||
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/../.. && pwd )"
|
||||
CONFIGURE_ANDROID_SDK_PATH="$ROOT_DIR/scripts/android/configureAndroidSdk.sh"
|
||||
DOCKER_BASE_DIR="$ROOT_DIR/docker-base"
|
||||
|
||||
IMAGE_TAG="$1"
|
||||
if [[ -z "$IMAGE_TAG" ]]; then
|
||||
@@ -15,12 +13,10 @@ fi
|
||||
IMAGE_VERSION_FULL_NAME="gcr.io/exponentjs/turtle-android-base:$IMAGE_TAG"
|
||||
IMAGE_LATEST_FULL_NAME="gcr.io/exponentjs/turtle-android-base:latest"
|
||||
|
||||
pushd $DOCKER_BASE_DIR > /dev/null
|
||||
cp $CONFIGURE_ANDROID_SDK_PATH .
|
||||
docker build -t "$IMAGE_VERSION_FULL_NAME" -t "$IMAGE_LATEST_FULL_NAME" .
|
||||
pushd $ROOT_DIR > /dev/null
|
||||
echo docker build -f docker-base/Dockerfile -t "$IMAGE_VERSION_FULL_NAME" -t "$IMAGE_LATEST_FULL_NAME" .
|
||||
echo "Successfully built $IMAGE_VERSION_FULL_NAME Docker image"
|
||||
gcloud docker -- push "$IMAGE_VERSION_FULL_NAME"
|
||||
gcloud docker -- push "$IMAGE_LATEST_FULL_NAME"
|
||||
echo gcloud docker -- push "$IMAGE_VERSION_FULL_NAME"
|
||||
echo gcloud docker -- push "$IMAGE_LATEST_FULL_NAME"
|
||||
echo "Successfully pushed $IMAGE_VERSION_FULL_NAME Docker image to GCloud"
|
||||
rm -rf `basename $CONFIGURE_ANDROID_SDK_PATH`
|
||||
popd > /dev/null
|
||||
@@ -18,9 +18,3 @@ yes | $SDKMANAGER \
|
||||
"extras;android;m2repository" \
|
||||
"extras;google;m2repository" \
|
||||
"extras;google;google_play_services" | grep -v '='; [[ ${PIPESTATUS[1]} = 0 ]]
|
||||
|
||||
if [[ "$(uname -s)" == "Darwin" ]] && [[ "$(uname -m)" == "arm64" ]]; then
|
||||
echo "Skipping NDK install on M1 macOS"
|
||||
else
|
||||
yes | $SDKMANAGER "ndk;17.2.4988734" | grep -v '='; [[ ${PIPESTATUS[1]} = 0 ]]
|
||||
fi
|
||||
+1
-1
@@ -14,7 +14,7 @@ PLATFORM=$1
|
||||
yarn
|
||||
yarn run build
|
||||
if [ "$PLATFORM" = "android" ]; then
|
||||
echo "shell apps will be fetched when building a Docker image"
|
||||
$ROOT_DIR/scripts/android/fetchRemoteAndroidTarball.sh
|
||||
elif [ "$PLATFORM" = "ios" ]; then
|
||||
$ROOT_DIR/scripts/ios/fetchRemoteIosTarball.sh
|
||||
fi
|
||||
|
||||
@@ -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 and AWS_SQS_IOS_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, AWS_SQS_IOS_QUEUE_URL and AWS_SQS_OUT_QUEUE_URL variables."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -17,11 +17,13 @@ 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
|
||||
|
||||
@@ -2,12 +2,6 @@
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
if ! command -v jq &> /dev/null
|
||||
then
|
||||
echo "jq is not installed and is required by the release script. Install it through homebrew or your package manager of choice."
|
||||
exit
|
||||
fi
|
||||
|
||||
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/.. && pwd )"
|
||||
|
||||
if [[ -z "$GITHUB_TOKEN" || -z "$CIRCLE_API_USER_TOKEN" ]]; then
|
||||
|
||||
@@ -2,12 +2,6 @@
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
if ! command -v jq &> /dev/null
|
||||
then
|
||||
echo "jq is not installed and is required by the release script. Install it through homebrew or your package manager of choice."
|
||||
exit
|
||||
fi
|
||||
|
||||
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/.. && pwd )"
|
||||
|
||||
$ROOT_DIR/node_modules/.bin/release-it -c $ROOT_DIR/.release-it.beta.json --preRelease=beta
|
||||
@@ -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, and AWS_SQS_IOS_PRIORITY_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, AWS_SQS_IOS_PRIORITY_QUEUE_URL and AWS_SQS_OUT_QUEUE_URL variables."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
set -ueo pipefail
|
||||
|
||||
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/../.. && pwd )"
|
||||
|
||||
export NODE_ENV=test
|
||||
|
||||
export ENVIRONMENT="development"
|
||||
@@ -13,6 +11,7 @@ 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"
|
||||
@@ -23,10 +22,5 @@ export API_PORT="443"
|
||||
export REDIS_URL="noop"
|
||||
export REDIS_CONFIG_URL="noop"
|
||||
export DATADOG_DISABLED="true"
|
||||
export TURTLE_SDK_VERSIONS_SECRET_TOKEN="noop"
|
||||
|
||||
pushd $ROOT_DIR/workingdir/android/${SDK_VERSION:-sdk39} >/dev/null 2>&1
|
||||
yarn
|
||||
popd >/dev/null 2>&1
|
||||
|
||||
yarn test:smoke:android
|
||||
@@ -9,6 +9,7 @@ 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"
|
||||
@@ -19,9 +20,8 @@ export API_PORT="443"
|
||||
export REDIS_URL="noop"
|
||||
export REDIS_CONFIG_URL="noop"
|
||||
export DATADOG_DISABLED="true"
|
||||
export TURTLE_SDK_VERSIONS_SECRET_TOKEN="noop"
|
||||
|
||||
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/../.. && pwd )"
|
||||
$ROOT_DIR/scripts/ios/fetchRemoteIosTarball.sh
|
||||
SDK_VERSION=sdk32 $ROOT_DIR/scripts/ios/fetchRemoteIosTarball.sh
|
||||
|
||||
yarn test:smoke:ios
|
||||
@@ -9,6 +9,7 @@ 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"
|
||||
@@ -21,6 +22,5 @@ export API_PORT="443"
|
||||
export REDIS_URL="noop"
|
||||
export REDIS_CONFIG_URL="noop"
|
||||
export DATADOG_DISABLED="true"
|
||||
export TURTLE_SDK_VERSIONS_SECRET_TOKEN="noop"
|
||||
|
||||
yarn test:unit
|
||||
@@ -2,12 +2,6 @@
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
if ! command -v jq &> /dev/null
|
||||
then
|
||||
echo "jq is not installed and is required by the release script. Install it through homebrew or your package manager of choice."
|
||||
exit
|
||||
fi
|
||||
|
||||
DEPLOY_ENDPOINT_URL="https://circleci.com/api/v1.1/project/github/expo/turtle-cli-example/tree/updates-do-not-remove-me"
|
||||
|
||||
curl -X POST \
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
s3://exp-artifacts/android-shell-builder-89b2d24c86737d5a489c6a18467e31b2f9ce9005.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
s3://exp-artifacts/android-shell-builder-f796aaffa0b5715079b2950faf26c2ff4e53e4c0.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
s3://exp-artifacts/android-shell-builder-aebd669d6573b0b3c802871d94cdb8b4116678d2.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
s3://exp-artifacts/android-shell-builder-a8e204610e5712391336b378f47962bbb0c04164.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
s3://exp-artifacts/android-shell-builder-e5c29efb465c5421250eece19210c9eb61a972a8.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/android-shell-builder-bb08bdc180fccd8f90e99dafb4e0ac456232531b.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/android-shell-builder-3cf3cf0707925322bcd667d5ba79120136f9afd8.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/android-shell-builder-6cde8e00cd7bdf7a933cd8aad7f8e86981ea68a2.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/android-shell-builder-d292dcd0cc277ab665957244a8b15b9981debd29.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/android-shell-builder-277393d97877f56ba3639ab153c69f109d248436.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/android-shell-builder-29840e62dc0626e5336397dc058ef26eabeffd18.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/android-shell-builder-ff452173c174914fba8387c5539d0ab222253f67.tar.gz
|
||||
@@ -1 +1 @@
|
||||
s3://exp-artifacts/ios-expo-client-dd6b6b4840c7a99725f1ec9a9a3970de91e90b1d.tar.gz
|
||||
s3://exp-artifacts/ios-expo-client-d31aaf53daca6aa65d8cb1090fb60c73a9c47075.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-55848298c7332f7586c4281fa691a4ca31548532.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-edd02214dd84368c197df32a2d30a901d6c766ff.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-36b57e8ebb96aa8dce286c89bd56e8708eca819d.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-651588ff3445a5d87b3a5b81ec2977c02b22f3a2.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-63a8747443392411aaaf9cba12958666acca3a4e.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-0983415327f49592d81f0bd3dc8c46a3572c19b0.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-df407aadb7208fc389564aed400c39263294eb76.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-ba6ec1974977bebf8fd2db22a1c87f6a0b36ffa5.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-4a9a038998f6be13e8a2900a95afbb9f96dd023d.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-dd6b6b4840c7a99725f1ec9a9a3970de91e90b1d.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-2b9ea15e13f36c120c257039cf76e14573760570.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-678da875791a43f2426813e922ec2051cd2a1e4c.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>8de5bfc7-bc8e-5ee3-9e04-e787ff880c47</RequestId></ResponseMetadata></ReceiveMessageResponse>","rawHeaders":["x-amzn-RequestId","8de5bfc7-bc8e-5ee3-9e04-e787ff880c47","Date","Tue, 01 Dec 2020 13:10: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>0bb998bb-3156-5159-b16f-c0fb725a5d65</RequestId></ResponseMetadata></ReceiveMessageResponse>","rawHeaders":["x-amzn-RequestId","0bb998bb-3156-5159-b16f-c0fb725a5d65","Date","Tue, 01 Dec 2020 13:10: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/><ResponseMetadata><RequestId>feef69fc-27a3-5af5-83af-31bc64b1b9d7</RequestId></ResponseMetadata></ReceiveMessageResponse>","rawHeaders":["x-amzn-RequestId","feef69fc-27a3-5af5-83af-31bc64b1b9d7","Date","Tue, 01 Dec 2020 13:10: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_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><Message><MessageId>f39aaec9-47e0-4d02-bdb7-cf467fe2ea19</MessageId><ReceiptHandle>AQEBBI8nzAywIPCH57h1Iptt39uq60E5dzlj+Er50gtGqH+esoJ6iFdxoPDxvtD0xfT0qlyKSqlmoBDkQwh36tqsfqdT5FcFF8ejmPMRVIE8hexofzEbacxxw+3cBfgra2EFAik49TJbMT5pwxyaf42y+qwyWKOZ5N62VzRgGtnpj5ilNw1dt0lUzCdsfhCu7sne+dfJ8oMpbuy6T+ttoEYUS6VVKmv8f1BzuujHoKMy0kJip8r3zFoaigWE2p1bpFby9b9oBFTFT1ycD618YTu+Un5S9Q7Q6/nqJ7RPM2BfK2iPxBMk+UWmGfJ/otX11Zc0p8qx/MyKuYY/480Zta//xQ==</ReceiptHandle><MD5OfBody>1942fb5be12b59fc93b8052cf960f7d8</MD5OfBody><Body>{"id":"686530e4-c025-4a01-b84b-041e6d4f7fb3","experienceId":"4d928c1c-5be9-4380-8fd5-48a6a4805839","experienceName":"@testtest2/sdk-39-test","platform":"android","config":{"releaseChannel":"default","buildType":"apk"},"status":"sent-to-queue","sdkVersion":"39.0.0","accountId":"1ecd48ee-e393-4f6b-9f77-311f2e0d2b39","priority":"high","credentials":{"keystore":"/u3+7QAAAAIAAAABAAAAAQAgcWhybGMzcjB6eG4wbWk5enpnc3Rtemt0ZGd2emRhPT0AAAF2HlYoCQAABQEwggT9MA4GCisGAQQBKgIRAQEFAASCBOmzIBnRnHGBLgRUOJ1GGYiLjktnTeq/GXR/h4KZSSQ67PoiJqJnhrHLvj35Sr1swSL78q4j52IRV/a1mFbqQT4JFFy1ZdH2XgKUptY+kVc+ZrBI/awC8akIeYofWmKTNcS0Bc9IDT1VwIzwxxRrlnK/36Gh2m1vRuwVUdBChHjB4SHgC91F8wB0opY+RmiRhZqQevd8PBvZyqKenR5IWgZDXhsUYvvby4U4zMzvEgV3zNv7YGYM1Bb2ehJ8HdsW6O/58zFL3ufJ3+H2VonLxSn9YayninHoqkyMP40/mmnaFPz5jNItDkCQIeuudgQc8mrZlv4X0lM2ZjT4ZJDLdN4FCXV5iYDe4hopF8iF+DZmhMaZ1xFJ57boEaZ+WUcwsTkKOawusOGqW2JsvZbDMehOYLc8aqM2t28PrdYf3c7zspJALi6+tar2mwN66TX/AteeJRAk3r7HAiYPyle5gOffGgpmy0klLb5MEStkLQNNNsVMLJ7XSYrewzI6jXyAbMVc6PzbiVnCRPtoSy0TMUD7qQWMUGdePL1jxDlwhOVS3jgwOwHIFhUaLBbQOPROm1bF4hY3p25+LHFu954aDsYC3JlT6k9EOKIacKbJThq14r2Lb4EekfQlYTO/yst6ncVJcawWHYS1f93xWUlIjcpFnqJrLq2QVQfhafPWJmTS3K0lcYgFpfxvoU8RVn+ySaLOiy9J86l5YPmtpH/nFqr6BkqROy6dXps5x+D9vi3jVfYlYHnmqHxq7vyX5X+IMIMLvJ28SviuMKWb8Ikqmm7FSzlewJfF4xy/NLgQrQY6VxUahy92PZf3uR02ENolnj5nPSnh/B1FnIfrG46xFqlPg8imzen7hjKk1yXrdUjOT4WcjLdD/K/heVVHKUnsn3QCBt6eOgB8MpG9XzGRD+PAwloklASQx8iVSD67EauU2y1yayf4lNaQzdfnF3iFXSF25BU9XLJIRTtdRsTwmLRuLTmQcctLYD8hQCDQ2/njZtTkdY/AJeVlm44CdDaTLJpP8mVVscAOgH/S0DPi/oGGie8AYeKr8ZmBO1lQSN6l2LBJcAq2fh6AaUF5By21lT9FfR9KQd5WM87iUZk41nBIHQXcQSSt7H+vETEfm/8T9tOOwY5dMyf5QAYNCZuBoIFNCr0MOxe/Dcrsvd46KVbftR4HsJsQl53MnZoh4eLine 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_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><Message><MessageId>fc2fe53d-1447-4304-90e0-60b025ac9687</MessageId><ReceiptHandle>AQEBcOA9S4yhL3ZCaho9Cv+XVqJEbhOaaWJTsOvBD9SOa/NK/248s0+yI9bHro5Ti9WJrnD3H65SdK9eOETFeS/QDaaCMTYkxjvH/1DrSJt2rAptgItmxl8F6N3iDYLqplOQjmautdjCWYXrCLxMDihMHEjcvWNAq0XLAAjlQJvtm5Z8Vji5xXKJP3IpQOV2DvhS/Cqriteaqe6NW5xKwgKHOC52IVTPMSHiJ0ERUf55agntOOJJ7Za7vHdTr+Zjrxl6yVFWKC/cpwYI00OKGj4bArud0buiaD0rtjszLmcPgcwADRsmhfG65p3gLwIwjfclHqSLlmcuY3c+xsu/5VM1YA==</ReceiptHandle><MD5OfBody>c9e8a99bf73407dfa26a2cb81103c26a</MD5OfBody><Body>{"id":"b9f9f814-5603-4dd5-929d-c9eed756c591","experienceId":"531b2db0-4b14-11e9-92d6-95aebd1034a3","experienceName":"@dsokal-local/turtle-cli-example","platform":"android","config":{"releaseChannel":"default"},"status":"sent-to-queue","sdkVersion":"32.0.0","accountId":"4c44c9d8-3cb6-4980-8505-ca0637cf3165","priority":"high","credentials":{"keystore":"/u3+7QAAAAIAAAABAAAAAQAscWdyemIydGhiYzFzYjJuaGJjOTBkeGowYmd1dHkyeHBsd3Y0eXcxd2JndT0AAAFpycAadgAABQIwggT+MA4GCisGAQQBKgIRAQEFAASCBOrpcy5jViAnKMlnwuvGQ2qa5UcYfuJQwaa48a4oEcvZlrPUUvQSi1T/ZOVpWc8bhiAD8xvTbTh0w1B26K4bPrbrchQGyubs5o3tZU94I+1yMR//nITj4srlUPipX7kr2KdGDqfLfS4EwK8FXACyXx3YxC30STovgtOjTctGUQRzD2iQmu9UmlCAl4szItY2vn+j51VJBpjV9SWXrWpEOmH6hkq7xlHFhbr00FpJXnzON6ifg7ymMIUbkG2nLC3VGCVTAqWBsOgEnUExMOKTedl6Rdzze5sP9CmzUk4aUpgZK1CHjvY03/RztuFky85ODEfSLrk3zBnegQgg0x54RQq1ji+/s5IyPslfpZbcVsTM1KBLEstfCkhZT8xjCZeUxD44U1UxcMlXRYsWtpHv5gfG/4vvV9xQ+pqzuCD43DLiTrqUFw9VzIzXjU7L9CXNGN0DtcmTI5usoKhLZPYgnpT546H4rnZkPzxYs3HXd+tyBmqFTWbvoRiFI2njeaMu0/RZMR17VKjv1u7rITpi7xjwX8cxPvxHLxoDyLL/0vxu45qfmH9ScOWw0QAxQ6RybMhZuZYXuHCERrJ4DLgXNqX8yDjba/C4ioF4nl4cL1S3JtUUE8aRaB6KKQaXP2Fxj+mww3eqetWBuCBD0yBHVscqCZfePh3b1hotMaVZvu/VrxkFL+BbnOkeSinwhkHB2sLFW3wzE5NQHbMi3chaHavC0jxFfaqf8aARub+5I/0+tqI3Crj46EdcxBMpPVa82HAYLkM8pSL8Tjs15bHg+v5suU+DEAymFPauDfEOIzbAJYdBmyrLiL5HBBSM39TdjdpXm1TOdBBtpOlROpJJsOpd3HRIqBF6yHyyRSrPZ5b5k42KCbMheRREXssqZoyPtZWT8aUdi9SnwhZm/fhNPVie1F7GjfsWi5U6OLpSHk2J6GOiwBFk5AXXoe4LNqcAMwYng5a23xEyAJ2JQ4sV5Hb8asNOfVjKvwLSKhRkG1wa+zsku2B0wFa7czX3r/u+NsEfOSbgo8ICya8itu8nlaoCtol/484Ab7NHiPJpF1qeZDB5n57+aODG7rjpBXJLvB0BTI4x9bPOEEzEu6cUEo6pvVIYGb5wTfgKVZVv5pA40x61/OicbG9dR8W6co/MfCDA0BMREzxO6djh8aSphR8Wd3jFYw1MI+PzCllnD3L4/6ZTc7R4sa9EUIfIxIFp7hw48HFO6I9uhp79lQySZ+EcEFFsvMK1hRGR6lfgX8ZWqgnJP1fx0n7PXyzFQvCEsw6GEesu6IVco39vNs1WL//FhhGf+HU2/Jq7wFOjN4yQtU/h2CEG5fv/aKGswoMv2Kqiihd4LjpxQlQHlaOXjp5QnBVMl6/8QVvX50JieabW3uXmcbOGnQ8qAOyg4OCgPzJmShifOeLuDPUQIvG4Tm7514lPZJ1aGFF9tj/zEBjxJfs7N30lUG+TfcPeFQDYfwmUZED2nZgsDdNQhkkucIf53Zgly9tKzXodRdAqwSv9qAeX69nbC2Db9J//E7CaDMLgm/Ij/w11MVlikMYv0FE95PdJ/vLbWPzEF1OwxXtutlg2TPksdSU7Cl7oJNk4B++fekquRmjPGzb8EEVIsTwmzZ77LOnre/F9Zy6nGX5mGCzhnYsBux6cRaDdwcYZ6UDm2PO88c5LEiIuAAAAAQAFWC41MDkAAANhMIIDXTCCAkWgAwIBAgIEHWp77zANBgkqhkiG9w0BAQsFADBfMQswCQYDVQQGEwJVUzEJMAcGA1UECBMAMQkwBwYDVQQHEwAxCTAHBgNVBAoTADEJMAcGA1UECxMAMSQwIgYDVQQDExtjb20uZXhwby50dXJ0bGUuY2xpLmV4YW1wbGUwHhcNMTkwMzI5MTQwMDAzWhcNNDYwODE0MTQwMDAzWjBfMQswCQYDVQQGEwJVUzEJMAcGA1UECBMAMQkwBwYDVQQHEwAxCTAHBgNVBAoTADEJMAcGA1UECxMAMSQwIgYDVQQDExtjb20uZXhwby50dXJ0bGUuY2xpLmV4YW1wbGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCw5E26XXa9AHihXC2gDfA9Wi4kHOhLiC5D6D1iS3Ftc+UCgg1d4pEzVB1o5O81IhWyIdTINkmpZ/qgDi1DCWXEgFHSisHFWWisXy/Ab2zRSPkE0GsDlnNvq2wObLzhEnLyALZ57+5EjQRCQJlzbO3kCFPhf/hT4hnVrsF+nnObkiEnUPCGLebHYqzk6lvMQ2XERzTyIovHD+TvfbIpKWOjSeZeEQ/9DI6Yo9bkZ4rRs9Z1vX1UTMtvEEg/T9oyCY0uE5h6yz49eH3Q2M27DqYEC3VaDhSBSELnItfSBnay/6vaQSlEzB+FGW6Jt9rTDQ1tMayUGQKvxhXi+08NHm7vAgMBAAGjITAfMB0GA1UdDgQWBBQiidnk1c5N5F4Aeg/EEPiuJO6ApDANBgkqhkiG9w0BAQsFAAOCAQEAkPbJQpnfoZehkPPNOHvyFl5S/POROColqo4OwfaYF0LmFfhMOPi3B2iuEXDPc/lVliuhQ+b+kD+pQnqlcDxWXEP8ZJETFjVSMLAeZ43MoTs22DBKh6sMYrO7MyjZbIwMMALmnfniHQe58gV7ot0sgBCs0bN3hICpqHXzZn6QSLxW1F9W5/52XFEwl+6zwTKnphZPNBhOCPQ/Z6cCEmodrKD48YeEOu+laojg3TZhVEF8Wf6TdcHjgyaT2IRPF+J6aD2K9ZazLFN/tvz0j5+1EPYtm1l6iX9RMFg0GtbRngXcIhuPXrcNuThF5/c2dL13JNYtMHUe3AAOfkycMNVjeTDkzLXZiULCDIisCnPuJQ9cRz7N","keyPassword":"fb7409988d78459c826cf2a438cb3a33","keystoreAlias":"QGRzb2thbC1sb2NhbC90dXJ0bGUtY2xpLWV4YW1wbGU=","keystorePassword":"80c3583b33b84a1d91e5cf33b2421d7c"},"manifest":{"android":{"package":"com.expo.turtle.cli.example"},"bundledAssets":["asset_3a2ba31570920eeb9b1d217cabe58315.ttf","asset_744ce60078c17d86006dd0edabcd59a7.ttf",&qLine truncated
|
||||
Binary file not shown.
@@ -17,7 +17,8 @@ jest.mock('../builders/utils/uploader.ts', () => ({
|
||||
async function performSmokeTest(recording: string) {
|
||||
jest.setTimeout(60 * 60 * 1000);
|
||||
|
||||
const fixtureExists = await fs.pathExists(recording);
|
||||
// @ts-ignore
|
||||
const fixtureExists = await fs.exists(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<string>());
|
||||
}, new Set());
|
||||
|
||||
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];
|
||||
|
||||
+18
-1
@@ -2,8 +2,9 @@ import retry from 'async-retry';
|
||||
import AWS from 'aws-sdk';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { QUEUE_URL } from 'turtle/aws/utils';
|
||||
import { OUTPUT_QUEUE_URL, 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';
|
||||
|
||||
@@ -72,3 +73,19 @@ 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,3 +1,4 @@
|
||||
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,11 +29,6 @@ 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,12 +15,7 @@ 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 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',
|
||||
'the URL of an externally hosted manifest (for self-hosted apps).',
|
||||
)
|
||||
.option(
|
||||
'--release-channel <channel-name>',
|
||||
|
||||
@@ -5,6 +5,7 @@ import { ExponentTools } from '@expo/xdl';
|
||||
import fs from 'fs-extra';
|
||||
import _which from 'which';
|
||||
|
||||
import ensureAndroidNDKIsPresent from 'turtle/bin/setup/android/ndk';
|
||||
import ensureAndroidSDKIsPresent from 'turtle/bin/setup/android/sdk';
|
||||
import { checkSystem, ensureShellAppIsPresent } from 'turtle/bin/setup/utils/common';
|
||||
import { IToolDefinition } from 'turtle/bin/setup/utils/toolsDetector';
|
||||
@@ -14,7 +15,6 @@ import { PLATFORMS } from 'turtle/constants';
|
||||
import logger from 'turtle/logger';
|
||||
|
||||
const which = util.promisify(_which);
|
||||
const JAVA_REQUIRED_VERSION = 8;
|
||||
const REQUIRED_TOOLS: IToolDefinition[] = [
|
||||
{
|
||||
command: 'bash',
|
||||
@@ -22,30 +22,16 @@ const REQUIRED_TOOLS: IToolDefinition[] = [
|
||||
},
|
||||
{
|
||||
command: 'javac',
|
||||
missingDescription:
|
||||
`Please install JDK 8 - keep in mind that other versions are not supported by Android`,
|
||||
missingDescription: 'Please install JDK (version 8 or newer) - check https://jdk.java.net/',
|
||||
testFn: async () => {
|
||||
const { status, stdout, stderr } = await ExponentTools.spawnAsyncThrowError(
|
||||
'java',
|
||||
const { status, stdout } = await ExponentTools.spawnAsyncThrowError(
|
||||
'javac',
|
||||
['-version'],
|
||||
{ stdio: 'pipe' },
|
||||
);
|
||||
if (stdout.match(/no java runtime present/i)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const matchResult = stderr.match(/.*version "(.*)"/);
|
||||
if (matchResult) {
|
||||
const [, currentFullJavaVersion] = matchResult;
|
||||
const javaMajorVersionPosition = currentFullJavaVersion.startsWith('1.') ? 1 : 0;
|
||||
const javaMajorVersion = Number(currentFullJavaVersion.split('.')[javaMajorVersionPosition]);
|
||||
if (javaMajorVersion !== JAVA_REQUIRED_VERSION) {
|
||||
throw new Error(`You're on Java ${currentFullJavaVersion}, please install version ${JAVA_REQUIRED_VERSION}`);
|
||||
}
|
||||
} else {
|
||||
logger.warn(`Couldn't find Java version number, assuming you're on Java ${JAVA_REQUIRED_VERSION}...`);
|
||||
}
|
||||
|
||||
return status === 0;
|
||||
},
|
||||
},
|
||||
@@ -68,8 +54,9 @@ export default async function setup(sdkVersion?: string) {
|
||||
async function prepareAndroidEnv() {
|
||||
await fs.ensureDir(config.directories.androidDependenciesDir);
|
||||
const sdkConfig = await ensureAndroidSDKIsPresent();
|
||||
_setEnvVars(sdkConfig.envVars);
|
||||
_alterPath(sdkConfig.path);
|
||||
const ndkConfig = await ensureAndroidNDKIsPresent();
|
||||
_setEnvVars({ ...sdkConfig.envVars, ...ndkConfig.envVars });
|
||||
_alterPath([...sdkConfig.path, ...sdkConfig.path]);
|
||||
}
|
||||
|
||||
function formatShellAppTarballUriPath(sdkMajorVersion: string) {
|
||||
@@ -101,9 +88,7 @@ async function _shellAppPostDownloadAction(sdkVersion: string, workingdir: strin
|
||||
async function _installNodeModules(cwd: string) {
|
||||
l.info(`installing dependencies in ${cwd} directory...`);
|
||||
const command = await _shouldUseYarnOrNpm();
|
||||
// Keep in sync with /Dockerfile
|
||||
// --prod requires --ignore-scripts (otherwise expo-yarn-workspaces errors as missing)
|
||||
await ExponentTools.spawnAsyncThrowError(command, ['install', '--ignore-scripts', '--production'], {
|
||||
await ExponentTools.spawnAsyncThrowError(command, ['install'], {
|
||||
pipeToLogger: true,
|
||||
loggerFields: LOGGER_FIELDS,
|
||||
cwd,
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
import decompress from 'decompress';
|
||||
import fs from 'fs-extra';
|
||||
|
||||
import * as utils from 'turtle/bin/setup/utils/common';
|
||||
import download from 'turtle/bin/setup/utils/downloader';
|
||||
import config from 'turtle/config';
|
||||
import logger from 'turtle/logger';
|
||||
|
||||
const ANDROID_NDK_URL = `https://dl.google.com/android/repository/android-ndk-r10e-${os.platform()}-x86_64.zip`;
|
||||
|
||||
const LOGGER_FIELDS = { buildPhase: 'setting up environment' };
|
||||
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);
|
||||
|
||||
try {
|
||||
l.info('Downloading Android NDK');
|
||||
await fs.ensureDir(config.directories.artifactsDir);
|
||||
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);
|
||||
throw err;
|
||||
} finally {
|
||||
await fs.remove(androidNdkDownloadPath);
|
||||
}
|
||||
}
|
||||
return {
|
||||
envVars: _createEnvVars(androidNdkDir),
|
||||
path: _createPaths(androidNdkDir),
|
||||
};
|
||||
}
|
||||
|
||||
function _createEnvVars(androidNdkDir: string) {
|
||||
return {
|
||||
ANDROID_NDK: androidNdkDir,
|
||||
};
|
||||
}
|
||||
|
||||
function _createPaths(androidNdkDir: string) {
|
||||
return [androidNdkDir];
|
||||
}
|
||||
@@ -42,7 +42,7 @@ export default async function ensureAndroidSDKIsPresent() {
|
||||
}
|
||||
}
|
||||
return {
|
||||
envVars: await _createEnvVars(androidSdkDir),
|
||||
envVars: _createEnvVars(androidSdkDir),
|
||||
path: _createPaths(androidSdkDir),
|
||||
};
|
||||
}
|
||||
@@ -63,16 +63,10 @@ async function _configureSdk(androidSdkDir: string) {
|
||||
});
|
||||
}
|
||||
|
||||
async function _createEnvVars(androidSdkDir: string) {
|
||||
const ndkPath = path.join(androidSdkDir, 'ndk/17.2.4988734');
|
||||
const ndkPathExists = await fs.pathExists(ndkPath);
|
||||
if (!ndkPathExists) {
|
||||
l.warn('Skipping NDK installation');
|
||||
}
|
||||
function _createEnvVars(androidSdkDir: string) {
|
||||
return {
|
||||
ANDROID_HOME: androidSdkDir,
|
||||
ANDROID_SDK: androidSdkDir,
|
||||
...(ndkPathExists ? { ANDROID_NDK_HOME: ndkPath } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+13
-44
@@ -1,6 +1,3 @@
|
||||
import _url from 'url';
|
||||
|
||||
import { ConfigError, getExpoSDKVersion, ProjectConfig } from '@expo/config';
|
||||
import { ExponentTools } from '@expo/xdl';
|
||||
import _ from 'lodash';
|
||||
import uuid from 'uuid';
|
||||
@@ -57,29 +54,21 @@ export function createBuilderAction({
|
||||
);
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
const projectAbsoluteDir = ProjectUtils.resolveAbsoluteDir(projectDirArg);
|
||||
const args = {
|
||||
releaseChannel: cmd.releaseChannel || 'default',
|
||||
buildType: cmd.type,
|
||||
buildMode: cmd.mode,
|
||||
username: userData.username || 'anonymous',
|
||||
projectDir: projectAbsoluteDir,
|
||||
projectDir: ProjectUtils.resolveAbsoluteDir(projectDirArg),
|
||||
publicUrl: cmd.publicUrl,
|
||||
};
|
||||
|
||||
const projectConfig = await ProjectUtils.getConfig(projectDirArg, cmd.config);
|
||||
const sdkVersion = getExpoSDKVersionSafely(projectAbsoluteDir, projectConfig);
|
||||
const appJSON = await ProjectUtils.loadAppJSON(projectDirArg, cmd.config);
|
||||
const sdkVersion = _.get(appJSON, 'expo.sdkVersion');
|
||||
await setup(platform, sdkVersion);
|
||||
const credentials = await prepareCredentials(cmd);
|
||||
const rawJob = {
|
||||
...await buildJobObject(cmd, platform, projectConfig, args, credentials, sdkVersion),
|
||||
...await buildJobObject(platform, appJSON, args, credentials),
|
||||
...cmd.buildDir && { fakeUploadDir: ProjectUtils.resolveAbsoluteDir(cmd.buildDir) },
|
||||
...cmd.output && { fakeUploadBuildPath: ProjectUtils.resolveAbsoluteDir(cmd.output) },
|
||||
};
|
||||
@@ -97,53 +86,33 @@ export function createBuilderAction({
|
||||
};
|
||||
}
|
||||
|
||||
function getExpoSDKVersionSafely(projectDir: string, projectConfig: ProjectConfig) {
|
||||
try {
|
||||
return getExpoSDKVersion(projectDir, projectConfig.exp);
|
||||
} catch (err) {
|
||||
if (err instanceof ConfigError) {
|
||||
throw new Error(
|
||||
'Couldn\'t find the `expo` library in your project\'s dependencies.'
|
||||
+ ' Have you run \'yarn install\' or \'npm install\' for your project?',
|
||||
);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const buildJobObject = async (
|
||||
cmd: any,
|
||||
platform: 'android' | 'ios',
|
||||
projectConfig: ProjectConfig,
|
||||
appJSON: any,
|
||||
{ releaseChannel, buildType, buildMode, username, publicUrl, projectDir }: any,
|
||||
credentials: any,
|
||||
sdkVersion: string,
|
||||
) => {
|
||||
const owner = projectConfig.exp.owner || username;
|
||||
const experienceName = `@${owner}/${projectConfig.exp.slug}`;
|
||||
const job = {
|
||||
config: {
|
||||
...(projectConfig.exp?.[platform]?.config || {}),
|
||||
..._.get(appJSON, `expo.${platform}.config`, {}),
|
||||
buildType,
|
||||
releaseChannel,
|
||||
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 } : {}),
|
||||
releaseChannel,
|
||||
...(platform === 'ios' ? { bundleIdentifier: _.get(appJSON, 'expo.ios.bundleIdentifier') } : {}),
|
||||
...(platform === 'android' ? { androidPackage: _.get(appJSON, 'expo.android.package') } : {}),
|
||||
publicUrl,
|
||||
},
|
||||
id: uuid.v4(),
|
||||
platform,
|
||||
projectDir,
|
||||
sdkVersion,
|
||||
experienceName,
|
||||
sdkVersion: _.get(appJSON, 'expo.sdkVersion'),
|
||||
experienceName: `@${username}/${_.get(appJSON, 'expo.slug')}`,
|
||||
...(credentials && { credentials }),
|
||||
};
|
||||
const url = getExperienceUrl(job.experienceName, job.config.publicUrl);
|
||||
|
||||
const manifest = await ExponentTools.getManifestAsync(url, {
|
||||
'Exponent-SDK-Version': sdkVersion,
|
||||
'Exponent-SDK-Version': _.get(appJSON, 'expo.sdkVersion'),
|
||||
'Exponent-Platform': platform,
|
||||
'Expo-Release-Channel': releaseChannel,
|
||||
'Accept': 'application/expo+json,application/json',
|
||||
|
||||
+13
-11
@@ -1,18 +1,20 @@
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
|
||||
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);
|
||||
export async function loadAppJSON(projectDirArg: string, config: string | null) {
|
||||
let appJSONPath;
|
||||
if (config) {
|
||||
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);
|
||||
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);
|
||||
}
|
||||
return await getProjectConfig(projectDir, {});
|
||||
}
|
||||
|
||||
export const resolveAbsoluteDir = (dir: string) => {
|
||||
|
||||
+12
-17
@@ -3,6 +3,7 @@ import path from 'path';
|
||||
import { AndroidShellApp, ImageUtils } from '@expo/xdl';
|
||||
import fs from 'fs-extra';
|
||||
import _ from 'lodash';
|
||||
import semver from 'semver';
|
||||
import { ANDROID_BUILD_TYPES } from 'turtle/constants';
|
||||
import uuidv4 from 'uuid/v4';
|
||||
|
||||
@@ -10,7 +11,7 @@ import getOrCreateCredentials from 'turtle/builders/utils/android/credentials';
|
||||
import { formatShellAppDirectory } from 'turtle/builders/utils/android/workingdir';
|
||||
import * as commonUtils from 'turtle/builders/utils/common';
|
||||
import * as imageHelpers from 'turtle/builders/utils/image';
|
||||
import { resolveExplicitOptIn, resolveNativeModules } from 'turtle/builders/utils/unimodules';
|
||||
import { resolveExplicitOptIn } from 'turtle/builders/utils/unimodules';
|
||||
import { uploadBuildToS3 } from 'turtle/builders/utils/uploader';
|
||||
import { ensureCanBuildSdkVersion } from 'turtle/builders/utils/version';
|
||||
import config from 'turtle/config';
|
||||
@@ -26,7 +27,7 @@ export default async function buildAndroid(jobData: IJob): Promise<IJobResult> {
|
||||
const s3FileExtension = jobData.config.buildType === ANDROID_BUILD_TYPES.APP_BUNDLE ? 'aab' : 'apk';
|
||||
const s3Filename = `${jobData.experienceName}-${randomHex}-signed.${s3FileExtension}`;
|
||||
const s3FileKey = `android/${s3Filename}`;
|
||||
const fakeUploadFilename = s3Filename.replace('/', '__');
|
||||
const fakeUploadFilename = s3Filename.replace('/', '\\');
|
||||
|
||||
const artifactUrl = await uploadBuildToS3({
|
||||
uploadPath: outputFilePath,
|
||||
@@ -34,8 +35,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),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -72,20 +73,15 @@ async function runShellAppBuilder(
|
||||
const sdkVersion = _.get(manifest, 'sdkVersion', sdkVersionFromJob);
|
||||
const workingDir = formatShellAppDirectory({ sdkVersion });
|
||||
|
||||
// Default behaviour:
|
||||
// - load all modules except [expo-branch]
|
||||
// - load expo-branch only if present in package.json dependencies
|
||||
// (2019-07-31) We are explicitly choosing to disable this option until we have more
|
||||
// infrastructure/tooling built around optional modules and OTA updates, as right now it's
|
||||
// very easy for developers to break apps in production with optional modules.
|
||||
//
|
||||
// Behaviour with "enableDangerousExperimentalLeanBuilds" flag enabled
|
||||
// - add unimodules from `manifest.dependencies` (project package.json dependecies)
|
||||
// - add unimodules from react-native-unimodules package.json
|
||||
// - add unimodules from expo package package.json
|
||||
// - add recusively all dependecies of already added unimodules
|
||||
// to enable full resolver switch resolveExplicitOptIn to resolveNativeModules
|
||||
logger.info({ buildPhase: 'resolve native modules' }, 'Resolving universal modules dependencies');
|
||||
const packageJsonDependecies = _.get(manifest, 'dependencies');
|
||||
const enabledModules = _.get(manifest, 'android.enableDangerousExperimentalLeanBuilds')
|
||||
? await resolveNativeModules(workingDir, sdkVersion, packageJsonDependecies)
|
||||
: await resolveExplicitOptIn(workingDir, packageJsonDependecies);
|
||||
const enabledModules = semver.satisfies(sdkVersion, '>= 33.0.0')
|
||||
? await resolveExplicitOptIn(workingDir, _.get(manifest, 'dependencies'))
|
||||
: null;
|
||||
|
||||
try {
|
||||
await AndroidShellApp.createAndroidShellAppAsync({
|
||||
@@ -103,7 +99,6 @@ async function runShellAppBuilder(
|
||||
modules: enabledModules,
|
||||
buildType: jobData.config.buildType,
|
||||
buildMode: jobData.config.buildMode,
|
||||
gradleArgs: jobData.config.gradleArgs,
|
||||
});
|
||||
} catch (err) {
|
||||
commonUtils.logErrorOnce(err);
|
||||
|
||||
@@ -131,7 +131,7 @@ export function createBuilderContext(job: IJob): IContext {
|
||||
const s3FileExtension = buildType === IOS_BUILD_TYPES.SIMULATOR ? 'tar.gz' : 'ipa';
|
||||
const s3Filename = `${job.experienceName}-${appUUID}-${buildType}.${s3FileExtension}`;
|
||||
if (config.builder.fakeUpload) {
|
||||
const fakeUploadFilename = s3Filename.replace('/', '__');
|
||||
const fakeUploadFilename = s3Filename.replace('/', '\\');
|
||||
context.fakeUploadBuildPath = job.fakeUploadBuildPath
|
||||
? job.fakeUploadBuildPath
|
||||
: join(job.fakeUploadDir || config.directories.fakeUploadDir, fakeUploadFilename);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import fs from 'fs-extra';
|
||||
import pick from 'lodash/pick';
|
||||
|
||||
import spawnAsync from '@expo/spawn-async';
|
||||
import buildArchive from 'turtle/builders/ios/archive';
|
||||
import { createBuilderContext, IContext } from 'turtle/builders/ios/context';
|
||||
import buildSimulator from 'turtle/builders/ios/simulator';
|
||||
@@ -52,13 +51,6 @@ async function initBuilder(ctx: IContext) {
|
||||
await fs.ensureDir(dir);
|
||||
await fs.chmod(dir, 0o755);
|
||||
}
|
||||
|
||||
if (config.builder.mode === 'online') {
|
||||
await spawnAsync('sudo', ['xcrun', 'simctl', 'list']);
|
||||
} else {
|
||||
// sudo not needed for CLI builds
|
||||
await spawnAsync('xcrun', ['simctl', 'list']);
|
||||
}
|
||||
}
|
||||
|
||||
async function cleanup(ctx: IContext) {
|
||||
@@ -69,4 +61,4 @@ async function cleanup(ctx: IContext) {
|
||||
}
|
||||
|
||||
const getTemporaryDirs = (ctx: IContext) =>
|
||||
Object.values(pick(ctx, ['appDir', 'provisioningProfileDir'])) as string[];
|
||||
Object.values(pick(ctx, ['appDir', 'provisioningProfileDir']));
|
||||
@@ -5,10 +5,11 @@ 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) {
|
||||
@@ -49,7 +50,9 @@ async function getOrCreateCredentials(jobData: IJob): Promise<IAndroidCredential
|
||||
l.info(`Key password: ${credentials.keyPassword}`);
|
||||
l.info(`Please keep these credentials safe`);
|
||||
} else {
|
||||
await sendCredentialsUpdate(jobData.id, 'android', credentials);
|
||||
await sqs.sendMessage(jobData.id, UPDATE_CREDENTIALS, {
|
||||
...credentials,
|
||||
});
|
||||
l.info('Keystore sent to storage successfully');
|
||||
}
|
||||
await fs.unlink(keystoreFilename);
|
||||
|
||||
@@ -4,11 +4,12 @@ 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;
|
||||
@@ -63,7 +64,7 @@ async function prepareAdHocBuildCredentials(job: IJob) {
|
||||
await fs.writeFile(provisioningProfilePath, Buffer.from(credentials.provisioningProfile, 'base64'));
|
||||
logger.info(`Saved provisioning profile to ${provisioningProfilePath}`);
|
||||
} else {
|
||||
await sendCredentialsUpdate(job.id, 'ios', {
|
||||
await sqs.sendMessage(job.id, UPDATE_CREDENTIALS, {
|
||||
provisioningProfileId: credentials.provisioningProfileId,
|
||||
provisioningProfile: credentials.provisioningProfile,
|
||||
});
|
||||
|
||||
@@ -36,7 +36,6 @@ export default async function runShellAppBuilder(ctx: IContext, job: IJob): Prom
|
||||
manifest,
|
||||
output: ctx.outputPath,
|
||||
verbose: true,
|
||||
shellAppSdkVersion: sdkVersion,
|
||||
};
|
||||
if (buildType === IOS_BUILD_TYPES.CLIENT) {
|
||||
Object.assign(shellAppParams, {
|
||||
|
||||
@@ -4,7 +4,6 @@ import keys from 'lodash/keys';
|
||||
import merge from 'lodash/merge';
|
||||
import values from 'lodash/values';
|
||||
import path from 'path';
|
||||
import semver from 'semver';
|
||||
import logger from 'turtle/logger';
|
||||
|
||||
export interface IUnimoduleEntry {
|
||||
@@ -20,37 +19,21 @@ interface IPackageInfo {
|
||||
dependencies: string[];
|
||||
}
|
||||
|
||||
export async function resolveExplicitOptIn(
|
||||
workingdir: string,
|
||||
packages?: string[],
|
||||
): Promise<IUnimoduleEntry[]> {
|
||||
export async function resolveExplicitOptIn(workingdir: string, packages?: string[]): Promise<IUnimoduleEntry[]> {
|
||||
const resolver = new Resolver(workingdir);
|
||||
await resolver.init();
|
||||
|
||||
const optionalModules = ['expo-branch'];
|
||||
resolver.addAll();
|
||||
const modules = packages
|
||||
? resolver
|
||||
.getModules()
|
||||
.filter(
|
||||
(mod) =>
|
||||
!optionalModules.includes(mod.name) || packages.includes(mod.name),
|
||||
)
|
||||
: resolver
|
||||
.getModules()
|
||||
.filter((mod) => !optionalModules.includes(mod.name));
|
||||
? resolver.getModules().filter((mod) => !optionalModules.includes(mod.name) || packages.includes(mod.name))
|
||||
: resolver.getModules().filter((mod) => !optionalModules.includes(mod.name));
|
||||
|
||||
modules.forEach(({ name, version }) => {
|
||||
logger.info(`Adding ${name}:${version}`);
|
||||
});
|
||||
modules.forEach(({ name, version }) => { logger.info(`Adding ${name}:${version}`); });
|
||||
return modules;
|
||||
}
|
||||
|
||||
export async function resolveNativeModules(
|
||||
workingdir: string,
|
||||
sdkVersion: string,
|
||||
packages?: string[],
|
||||
): Promise<IUnimoduleEntry[]> {
|
||||
export async function resolveNativeModules(workingdir: string, packages?: string[]): Promise<IUnimoduleEntry[]> {
|
||||
const resolver = new Resolver(workingdir);
|
||||
await resolver.init();
|
||||
|
||||
@@ -58,13 +41,6 @@ export async function resolveNativeModules(
|
||||
resolver.addAll();
|
||||
} else {
|
||||
const corePackages = await readCorePackages(workingdir);
|
||||
|
||||
// expo-notifications is required for shell apps in SDK >= 39
|
||||
// https://github.com/expo/expo/issues/10569
|
||||
if (semver.gte(sdkVersion, '39.0.0')) {
|
||||
resolver.addModule('expo-notifications');
|
||||
}
|
||||
|
||||
for (const pkg of corePackages) {
|
||||
if (resolver.isUnimodule(pkg)) {
|
||||
resolver.addModule(pkg);
|
||||
@@ -77,36 +53,17 @@ export async function resolveNativeModules(
|
||||
}
|
||||
}
|
||||
const modules = resolver.getModules();
|
||||
modules.forEach(({ name, version }) => {
|
||||
logger.info(`Adding ${name}:${version}`);
|
||||
});
|
||||
modules.forEach(({ name, version }) => { logger.info(`Adding ${name}:${version}`); });
|
||||
return modules;
|
||||
}
|
||||
|
||||
async function readCorePackages(workingdir: string) {
|
||||
const pkgJsonPath = path.join(
|
||||
workingdir,
|
||||
'node_modules',
|
||||
'react-native-unimodules',
|
||||
'package.json',
|
||||
);
|
||||
const expoPkgJsonPath = path.join(
|
||||
workingdir,
|
||||
'packages',
|
||||
'expo',
|
||||
'package.json',
|
||||
);
|
||||
if (
|
||||
(await fs.pathExists(pkgJsonPath)) &&
|
||||
(await fs.pathExists(expoPkgJsonPath))
|
||||
) {
|
||||
const pkgJsonPath = path.join(workingdir, 'node_modules', 'react-native-unimodules', 'package.json');
|
||||
const expoPkgJsonPath = path.join(workingdir, 'packages', 'expo', 'package.json');
|
||||
if (await fs.pathExists(pkgJsonPath) && await fs.pathExists(expoPkgJsonPath)) {
|
||||
const packageJson = JSON.parse(await fs.readFile(pkgJsonPath, 'utf-8'));
|
||||
const expoPackageJson = JSON.parse(
|
||||
await fs.readFile(expoPkgJsonPath, 'utf-8'),
|
||||
);
|
||||
return keys(packageJson.dependencies).concat(
|
||||
keys(expoPackageJson.dependencies),
|
||||
);
|
||||
const expoPackageJson = JSON.parse(await fs.readFile(expoPkgJsonPath, 'utf-8'));
|
||||
return keys(packageJson.dependencies).concat(keys(expoPackageJson.dependencies));
|
||||
} else {
|
||||
logger.warn('No core packages detected');
|
||||
return [];
|
||||
@@ -119,7 +76,7 @@ interface IDependencyInfo {
|
||||
|
||||
class Resolver {
|
||||
private workingdir: string;
|
||||
private modulesMap: { [key: string]: IUnimoduleEntry };
|
||||
private modulesMap: {[key: string]: IUnimoduleEntry};
|
||||
private dependencyMap: IDependencyInfo;
|
||||
|
||||
constructor(workingdir: string) {
|
||||
@@ -151,7 +108,7 @@ class Resolver {
|
||||
}
|
||||
|
||||
public getModules(): IUnimoduleEntry[] {
|
||||
return values(this.modulesMap);
|
||||
return values(this.modulesMap);
|
||||
}
|
||||
|
||||
private async resolveModule(moduleName: string) {
|
||||
@@ -170,9 +127,7 @@ class Resolver {
|
||||
}
|
||||
}
|
||||
|
||||
async function generateDependenciesInfo(
|
||||
workingdir: string,
|
||||
): Promise<IDependencyInfo> {
|
||||
async function generateDependenciesInfo(workingdir: string): Promise<IDependencyInfo> {
|
||||
const dir = await fs.readdir(path.join(workingdir, 'packages'));
|
||||
const map: IDependencyInfo = {};
|
||||
|
||||
@@ -185,9 +140,7 @@ async function generateDependenciesInfo(
|
||||
}
|
||||
|
||||
// handle @unimodules directory
|
||||
const unimodulesDir = await fs.readdir(
|
||||
path.join(workingdir, 'packages', '@unimodules'),
|
||||
);
|
||||
const unimodulesDir = await fs.readdir(path.join(workingdir, 'packages', '@unimodules'));
|
||||
for (const pkgName of unimodulesDir) {
|
||||
const pkg = await getPackage(workingdir, path.join('@unimodules', pkgName));
|
||||
if (pkg) {
|
||||
@@ -202,27 +155,19 @@ async function generateDependenciesInfo(
|
||||
return map;
|
||||
}
|
||||
|
||||
async function getPackage(
|
||||
workingdir: string,
|
||||
pkgName: string,
|
||||
): Promise<IPackageInfo | null> {
|
||||
async function getPackage(workingdir: string, pkgName: string): Promise<IPackageInfo | null> {
|
||||
const pkgPath = path.join(workingdir, 'packages', pkgName);
|
||||
const isAndroid = await fs.pathExists(path.join(pkgPath, 'android'));
|
||||
const isIos = await fs.pathExists(path.join(pkgPath, 'ios'));
|
||||
const isUnimodule = await fs.pathExists(path.join(pkgPath, 'unimodule.json'));
|
||||
const hasPackageJson = await fs.pathExists(
|
||||
path.join(pkgPath, 'package.json'),
|
||||
);
|
||||
const hasPackageJson = await fs.pathExists(path.join(pkgPath, 'package.json'));
|
||||
if (!isUnimodule || !hasPackageJson || (!isAndroid && !isIos)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const packageJson = JSON.parse(
|
||||
await fs.readFile(path.join(pkgPath, 'package.json'), 'utf-8'),
|
||||
);
|
||||
const packageJson = JSON.parse(await fs.readFile(path.join(pkgPath, 'package.json'), 'utf-8'));
|
||||
|
||||
const pkgDeps = merge(
|
||||
{}, // reading everything to make sure
|
||||
const pkgDeps = merge({}, // reading everything to make sure
|
||||
packageJson.dependencies,
|
||||
packageJson.peerDependencies,
|
||||
packageJson.unimodulePeerDependencies,
|
||||
|
||||
+4
-20
@@ -1,4 +1,3 @@
|
||||
import fs from 'fs';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
@@ -29,6 +28,7 @@ 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,17 +44,8 @@ export default {
|
||||
intervalMs: env('DATADOG_INTERVAL_MS', 5 * 60 * 1000),
|
||||
},
|
||||
redis: {
|
||||
main: {
|
||||
url: env('REDIS_URL'),
|
||||
caCertificate: envTransform(
|
||||
'REDIS_CA_CERTIFICATE',
|
||||
null,
|
||||
(caCertificate: string) => caCertificate && fs.readFileSync(caCertificate),
|
||||
),
|
||||
},
|
||||
turtle: {
|
||||
url: env('REDIS_CONFIG_URL'),
|
||||
},
|
||||
url: env('REDIS_URL'),
|
||||
configUrl: env('REDIS_CONFIG_URL'),
|
||||
},
|
||||
logger: {
|
||||
level: env('LOGGER_LEVEL', 'info'),
|
||||
@@ -90,7 +81,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(
|
||||
@@ -98,11 +89,4 @@ export default {
|
||||
path.join(os.platform() === 'darwin' ? '/private' : '/', 'tmp', 'turtle'),
|
||||
),
|
||||
},
|
||||
www: {
|
||||
secretToken: env('TURTLE_SDK_VERSIONS_SECRET_TOKEN'),
|
||||
},
|
||||
leader: {
|
||||
redisKey: env('LEADER_REDIS_KEY', 'turtle-v1:leader'),
|
||||
redisKeyTTLSec: envNum('LEADER_REDIS_KEY_TTL', 30),
|
||||
},
|
||||
};
|
||||
@@ -15,7 +15,6 @@ export interface IJob {
|
||||
// android
|
||||
androidPackage?: string;
|
||||
buildMode?: ANDROID_BUILD_MODES;
|
||||
gradleArgs?: string[];
|
||||
};
|
||||
credentials: {
|
||||
// android
|
||||
|
||||
+24
-56
@@ -10,9 +10,8 @@ import logger from 'turtle/logger';
|
||||
import * as buildDurationMetric from 'turtle/metrics/buildDuration';
|
||||
import * as buildStatusMetric from 'turtle/metrics/buildStatus';
|
||||
import { checkShouldExit, setCurrentJobId, turtleVersion } from 'turtle/turtleContext';
|
||||
import { getPriorities, labelConfiguration, TurtleMode } from 'turtle/utils/priorities';
|
||||
import { getPriorities } from 'turtle/utils/priorities';
|
||||
import * as redis from 'turtle/utils/redis';
|
||||
import { sendBuildStatusUpdate } from 'turtle/utils/www';
|
||||
import { sanitizeJob } from 'turtle/validator';
|
||||
|
||||
function _maybeExit() {
|
||||
@@ -23,8 +22,8 @@ function _maybeExit() {
|
||||
}
|
||||
|
||||
export async function doJob() {
|
||||
const { job, turtleMode } = await getJob();
|
||||
await processJob(job, turtleMode);
|
||||
const jobData = await getJob();
|
||||
await processJob(jobData);
|
||||
_maybeExit();
|
||||
}
|
||||
|
||||
@@ -35,7 +34,6 @@ export async function getJob() {
|
||||
try {
|
||||
let job = null;
|
||||
const priorities = await getPriorities();
|
||||
const turtleMode = labelConfiguration(priorities);
|
||||
for (const priority of priorities) {
|
||||
job = await sqs.receiveMessage(priority);
|
||||
_maybeExit();
|
||||
@@ -46,7 +44,7 @@ export async function getJob() {
|
||||
}
|
||||
_maybeExit();
|
||||
if (job !== null) {
|
||||
return { job, turtleMode };
|
||||
return job;
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error({ err }, 'Error at receiving messages');
|
||||
@@ -54,38 +52,23 @@ export async function getJob() {
|
||||
}
|
||||
}
|
||||
|
||||
async function processJob(jobData: any, turtleMode: TurtleMode) {
|
||||
async function processJob(jobData: any) {
|
||||
const receiptHandle = jobData.ReceiptHandle;
|
||||
const { priority } = jobData;
|
||||
|
||||
let timeoutId;
|
||||
try {
|
||||
let rawJob;
|
||||
let job;
|
||||
try {
|
||||
rawJob = JSON.parse(jobData.Body);
|
||||
timeoutId = failAfterMaxJobTime(priority, receiptHandle, rawJob);
|
||||
logger.info(
|
||||
{ buildJobId: rawJob.id, messageId: jobData.MessageId },
|
||||
`Processing job with priority=${priority.slice(0, priority.length - 8)} timestamp=${Date.now()}`,
|
||||
);
|
||||
job = await sanitizeJob(rawJob);
|
||||
} catch (err) {
|
||||
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 sendBuildStatusUpdate(rawJob.id, {
|
||||
status: BUILD.JOB_STATES.ERRORED,
|
||||
turtleVersion,
|
||||
buildDuration: 0,
|
||||
reason: 'The build job is invalid',
|
||||
});
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
const rawJob = JSON.parse(jobData.Body);
|
||||
timeoutId = failAfterMaxJobTime(priority, receiptHandle, rawJob);
|
||||
const job = await sanitizeJob(rawJob);
|
||||
|
||||
setCurrentJobId(job.id);
|
||||
const pingerHandle = sqs.changeMessageVisibilityRecurring(priority, jobData.ReceiptHandle, job.id);
|
||||
|
||||
logger.info(
|
||||
`Doing job MessageId=${jobData.MessageId} BuildId=${job.id} `
|
||||
+ `Priority=${priority.slice(0, priority.length - 8)} ${Date.now()}`,
|
||||
);
|
||||
|
||||
const cancelled = await redis.checkIfCancelled(job.id);
|
||||
if (cancelled) {
|
||||
logger.info('The job has been cancelled');
|
||||
@@ -95,7 +78,7 @@ async function processJob(jobData: any, turtleMode: TurtleMode) {
|
||||
let buildFailed = false;
|
||||
const buildType = _.get(job, 'config.buildType', 'default');
|
||||
try {
|
||||
const status = await build(job, turtleMode);
|
||||
const status = await build(job);
|
||||
buildStatusMetric.add(buildType, priority, status);
|
||||
buildFailed = !status;
|
||||
} catch (err) {
|
||||
@@ -130,7 +113,7 @@ async function processJob(jobData: any, turtleMode: TurtleMode) {
|
||||
function failAfterMaxJobTime(priority: string, receiptHandle: string, job: any) {
|
||||
return setTimeout(async () => {
|
||||
try {
|
||||
sendBuildStatusUpdate(job.id, { status: BUILD.JOB_STATES.ERRORED, turtleVersion });
|
||||
sqs.sendMessage(job.id, BUILD.JOB_STATES.ERRORED, { turtleVersion });
|
||||
await deleteMessage(priority, receiptHandle);
|
||||
} finally {
|
||||
logger.error('Build timed out. Going to terminate turtle agent.');
|
||||
@@ -140,33 +123,20 @@ function failAfterMaxJobTime(priority: string, receiptHandle: string, job: any)
|
||||
}, config.builder.maxJobTimeMs);
|
||||
}
|
||||
|
||||
async function build(job: any, turtleMode: TurtleMode) {
|
||||
async function build(job: any) {
|
||||
const startTimestamp = Date.now();
|
||||
const s3Url = await logger.initForJob(job);
|
||||
const calculateBuildDuration = () => Math.ceil((Date.now() - startTimestamp) / 1000);
|
||||
|
||||
const commonPayload = {
|
||||
logs: {
|
||||
url: s3Url,
|
||||
format: 'json',
|
||||
},
|
||||
extraData: {
|
||||
turtleMode,
|
||||
},
|
||||
};
|
||||
try {
|
||||
await sendBuildStatusUpdate(job.id, {
|
||||
...commonPayload,
|
||||
status: BUILD.JOB_STATES.IN_PROGRESS,
|
||||
await sqs.sendMessage(job.id, BUILD.JOB_STATES.IN_PROGRESS, {
|
||||
logUrl: s3Url,
|
||||
logFormat: 'json',
|
||||
});
|
||||
const { artifactUrl } = await (builders as any)[job.platform](job);
|
||||
const result = await (builders as any)[job.platform](job);
|
||||
const buildDuration = calculateBuildDuration();
|
||||
sendBuildStatusUpdate(job.id, {
|
||||
...commonPayload,
|
||||
artifacts: {
|
||||
url: artifactUrl,
|
||||
},
|
||||
status: BUILD.JOB_STATES.FINISHED,
|
||||
sqs.sendMessage(job.id, BUILD.JOB_STATES.FINISHED, {
|
||||
...result,
|
||||
turtleVersion,
|
||||
buildDuration,
|
||||
});
|
||||
@@ -178,9 +148,7 @@ async function build(job: any, turtleMode: TurtleMode) {
|
||||
if (err instanceof BuildError) {
|
||||
reason = err.reason;
|
||||
}
|
||||
sendBuildStatusUpdate(job.id, {
|
||||
...commonPayload,
|
||||
status: BUILD.JOB_STATES.ERRORED,
|
||||
sqs.sendMessage(job.id, BUILD.JOB_STATES.ERRORED, {
|
||||
turtleVersion,
|
||||
buildDuration,
|
||||
...reason && { reason },
|
||||
|
||||
@@ -15,7 +15,6 @@ 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()),
|
||||
}),
|
||||
}),
|
||||
);
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
import EventEmitter from 'events';
|
||||
import path from 'path';
|
||||
|
||||
|
||||
@@ -5,11 +5,11 @@ import take from 'lodash/take';
|
||||
import logger from 'turtle/logger';
|
||||
import { sendMetric } from 'turtle/metrics/datadog';
|
||||
import { getReplicaCount } from 'turtle/utils/metadata';
|
||||
import { getLabeledConfiguration, TurtleMode } from 'turtle/utils/priorities';
|
||||
import { getLabeledConfiguration, TurtleModeLabels } from 'turtle/utils/priorities';
|
||||
|
||||
const createMetricName = () => `turtle.replicaCount`;
|
||||
const createModeMetricName = (mode: TurtleMode) => `${createMetricName()}.${mode}`;
|
||||
const createModeTag = (mode: TurtleMode) => `mode:${mode}`;
|
||||
const createModeMetricName = (mode: TurtleModeLabels) => `${createMetricName()}.${mode}`;
|
||||
const createModeTag = (mode: TurtleModeLabels) => `mode:${mode}`;
|
||||
|
||||
export default async function sendConfigToDatadog() {
|
||||
let configuration;
|
||||
@@ -30,28 +30,28 @@ export default async function sendConfigToDatadog() {
|
||||
|
||||
const metricName = createMetricName();
|
||||
|
||||
const normalReplicaCount = replicaCounts[TurtleMode.Normal] || 0;
|
||||
const highReplicaCount = replicaCounts[TurtleMode.High] || 0;
|
||||
const highOnlyReplicaCount = replicaCounts[TurtleMode.HighOnly] || 0;
|
||||
const normalReplicaCount = replicaCounts[TurtleModeLabels.Normal] || 0;
|
||||
const highReplicaCount = replicaCounts[TurtleModeLabels.High] || 0;
|
||||
const highOnlyReplicaCount = replicaCounts[TurtleModeLabels.HighOnly] || 0;
|
||||
|
||||
const normalTag = createModeTag(TurtleMode.Normal);
|
||||
const normalMetricName = createModeMetricName(TurtleMode.Normal);
|
||||
const normalTag = createModeTag(TurtleModeLabels.Normal);
|
||||
const normalMetricName = createModeMetricName(TurtleModeLabels.Normal);
|
||||
logger.debug(
|
||||
`Sending ${metricName}=${normalReplicaCount} (${normalTag}), ${normalMetricName}=${normalReplicaCount} to Datadog`,
|
||||
);
|
||||
await sendMetric(metricName, normalReplicaCount, [normalTag]);
|
||||
await sendMetric(normalMetricName, normalReplicaCount);
|
||||
|
||||
const highTag = createModeTag(TurtleMode.High);
|
||||
const highMetricName = createModeMetricName(TurtleMode.High);
|
||||
const highTag = createModeTag(TurtleModeLabels.High);
|
||||
const highMetricName = createModeMetricName(TurtleModeLabels.High);
|
||||
logger.debug(
|
||||
`Sending ${metricName}=${highReplicaCount} (${highTag}), ${highMetricName}=${highReplicaCount} to Datadog`,
|
||||
);
|
||||
await sendMetric(metricName, highReplicaCount, [highTag]);
|
||||
await sendMetric(highMetricName, highReplicaCount);
|
||||
|
||||
const highOnlyTag = createModeTag(TurtleMode.HighOnly);
|
||||
const highOnlyMetricName = createModeMetricName(TurtleMode.HighOnly);
|
||||
const highOnlyTag = createModeTag(TurtleModeLabels.HighOnly);
|
||||
const highOnlyMetricName = createModeMetricName(TurtleModeLabels.HighOnly);
|
||||
logger.debug(
|
||||
`Sending ${metricName}=${highOnlyReplicaCount} (${highOnlyTag}),`
|
||||
+ ` ${highOnlyMetricName}=${highOnlyReplicaCount} to Datadog`,
|
||||
|
||||
+16
-34
@@ -6,9 +6,10 @@ 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';
|
||||
import { getRedisClient } 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'));
|
||||
|
||||
@@ -35,49 +36,30 @@ async function main() {
|
||||
await setup[config.platform]();
|
||||
}
|
||||
|
||||
await electLeaderAndSynchronize();
|
||||
|
||||
try {
|
||||
await setTurtleVersion(turtleVersion);
|
||||
logger.info(`Registered Turtle version (${turtleVersion}) in www`);
|
||||
const sdkVersions = (await findSupportedSdkVersions(config.platform)).map((version) => `${version}.0.0`);
|
||||
await setSupportedSdkVersions(config.platform, sdkVersions);
|
||||
logger.info(`Registered supported SDK versions (${sdkVersions}) in www`);
|
||||
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)');
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error({ err }, 'Failed to register versions in www');
|
||||
logger.error({ err }, 'Failed to set versions in Redis');
|
||||
}
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
await doJob();
|
||||
} catch (err) {
|
||||
logger.error({ err }, 'Failed to process a job');
|
||||
logger.error({ err }, 'Failed to do a job');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,6 +4,7 @@ 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';
|
||||
Vendored
-472
@@ -1,472 +0,0 @@
|
||||
interface pbxFile {
|
||||
basename: string;
|
||||
lastKnownFileType?: string;
|
||||
group?: string;
|
||||
path?: string;
|
||||
fileEncoding?: number;
|
||||
defaultEncoding?: number;
|
||||
sourceTree: string;
|
||||
includeInIndex?: number;
|
||||
explicitFileType?: unknown;
|
||||
settings?: object;
|
||||
uuid?: string;
|
||||
fileRef: string;
|
||||
target?: string;
|
||||
}
|
||||
|
||||
declare module 'xcode' {
|
||||
/**
|
||||
* UUID that is a key to each fragment of PBXProject.
|
||||
*/
|
||||
type UUID = string;
|
||||
|
||||
/**
|
||||
* if has following format `${UUID}_comment`
|
||||
*/
|
||||
type UUIDComment = string;
|
||||
|
||||
type XCObjectType =
|
||||
| 'PBXBuildFile'
|
||||
| 'PBXFileReference'
|
||||
| 'PBXFrameworksBuildPhase'
|
||||
| 'PBXGroup'
|
||||
| 'PBXNativeTarget'
|
||||
| 'PBXProject'
|
||||
| 'PBXResourcesBuildPhase'
|
||||
| 'PBXShellScriptBuildPhase'
|
||||
| 'PBXSourcesBuildPhase'
|
||||
| 'PBXVariantGroup'
|
||||
| 'XCBuildConfiguration'
|
||||
| 'XCConfigurationList';
|
||||
|
||||
type PBXFile = pbxFile;
|
||||
|
||||
interface PBXProject {
|
||||
isa: 'PBXProject';
|
||||
attributes: {
|
||||
LastUpgradeCheck: number;
|
||||
TargetAttributes: Record<
|
||||
UUID,
|
||||
{
|
||||
CreatedOnToolsVersion?: string;
|
||||
TestTargetID?: UUID;
|
||||
LastSwiftMigration?: number;
|
||||
ProvisioningStyle?: string;
|
||||
} & Record<string, undefined | number | string>
|
||||
>;
|
||||
};
|
||||
buildConfigurationList: UUID;
|
||||
buildConfigurationList_comment: string;
|
||||
compatibilityVersion: string;
|
||||
developmentRegion: string;
|
||||
hasScannedForEncodings: number;
|
||||
knownRegions: string[];
|
||||
mainGroup: UUID;
|
||||
productRefGroup: UUID;
|
||||
productRefGroup_comment: string;
|
||||
projectDirPath: string;
|
||||
projectRoot: string;
|
||||
targets: Array<{
|
||||
value: UUID;
|
||||
comment: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
interface PBXNativeTarget {
|
||||
isa: 'PBXNativeTarget';
|
||||
buildConfigurationList: UUID;
|
||||
buildConfigurationList_comment: string;
|
||||
buildPhases: Array<{
|
||||
value: UUID;
|
||||
comment: string;
|
||||
}>;
|
||||
buildRules: [];
|
||||
dependencies: [];
|
||||
name: string;
|
||||
productName: string;
|
||||
productReference: UUID;
|
||||
productReference_comment: string;
|
||||
productType: string;
|
||||
}
|
||||
|
||||
interface PBXBuildFile {
|
||||
isa: 'PBXBuildFile';
|
||||
fileRef: UUID;
|
||||
// "AppDelegate.m"
|
||||
fileRef_comment: string;
|
||||
}
|
||||
|
||||
interface XCConfigurationList {
|
||||
isa: 'XCConfigurationList';
|
||||
buildConfigurations: Array<{
|
||||
value: UUID;
|
||||
comment: string | 'Release' | 'Debug';
|
||||
}>;
|
||||
defaultConfigurationIsVisible: number;
|
||||
defaultConfigurationName: string;
|
||||
}
|
||||
|
||||
interface XCBuildConfiguration {
|
||||
isa: 'XCBuildConfiguration';
|
||||
baseConfigurationReference: UUID;
|
||||
baseConfigurationReference_comment: string;
|
||||
buildSettings: Record<string, string | undefined | number | Array<unknown>> & {
|
||||
// '"$(TARGET_NAME)"',
|
||||
PRODUCT_NAME?: string;
|
||||
// '"io.expo.demo.$(PRODUCT_NAME:rfc1034identifier)"',
|
||||
PRODUCT_BUNDLE_IDENTIFIER?: string;
|
||||
PROVISIONING_PROFILE_SPECIFIER?: string;
|
||||
// '"$(BUILT_PRODUCTS_DIR)/rni.app/rni"'
|
||||
TEST_HOST?: any;
|
||||
DEVELOPMENT_TEAM?: string;
|
||||
CODE_SIGN_IDENTITY?: string;
|
||||
CODE_SIGN_STYLE?: string;
|
||||
// '"$(TEST_HOST)"'
|
||||
BUNDLE_LOADER?: string;
|
||||
GCC_PREPROCESSOR_DEFINITIONS?: Array<unknown>;
|
||||
INFOPLIST_FILE?: string;
|
||||
IPHONEOS_DEPLOYMENT_TARGET?: string;
|
||||
LD_RUNPATH_SEARCH_PATHS?: string;
|
||||
OTHER_LDFLAGS?: Array<unknown>;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME?: string;
|
||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME?: string;
|
||||
CLANG_ANALYZER_NONNULL?: string;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS?: string;
|
||||
CLANG_WARN_INFINITE_RECURSION?: string;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE?: string;
|
||||
DEBUG_INFORMATION_FORMAT?: string;
|
||||
ENABLE_TESTABILITY?: string;
|
||||
GCC_NO_COMMON_BLOCKS?: string;
|
||||
// 'appletvos'
|
||||
SDKROOT?: string;
|
||||
TARGETED_DEVICE_FAMILY?: number | string;
|
||||
// '10.0'
|
||||
TVOS_DEPLOYMENT_TARGET?: string;
|
||||
};
|
||||
name: string;
|
||||
}
|
||||
|
||||
type ProductType =
|
||||
| 'com.apple.product-type.application'
|
||||
| 'com.apple.product-type.app-extension'
|
||||
| 'com.apple.product-type.bundle'
|
||||
| 'com.apple.product-type.tool'
|
||||
| 'com.apple.product-type.library.dynamic'
|
||||
| 'com.apple.product-type.framework'
|
||||
| 'com.apple.product-type.library.static'
|
||||
| 'com.apple.product-type.bundle.unit-test'
|
||||
| 'com.apple.product-type.application.watchapp'
|
||||
| 'com.apple.product-type.application.watchapp2'
|
||||
| 'com.apple.product-type.watchkit-extension'
|
||||
| 'com.apple.product-type.watchkit2-extension';
|
||||
|
||||
interface PBXGroup {
|
||||
isa: 'PBXGroup';
|
||||
children: Array<{
|
||||
value: UUID;
|
||||
comment?: string;
|
||||
}>;
|
||||
name: string;
|
||||
path?: string;
|
||||
sourceTree: '"<group>"' | unknown;
|
||||
}
|
||||
|
||||
export class XcodeProject {
|
||||
|
||||
/**
|
||||
* `.pbxproj` file path.
|
||||
*/
|
||||
public filepath: string;
|
||||
|
||||
// Ex: '$(TARGET_NAME)'
|
||||
public productName: string;
|
||||
|
||||
public hash: {
|
||||
headComment: string;
|
||||
project: {
|
||||
archiveVersion: number;
|
||||
objectVersion: number;
|
||||
objects: {
|
||||
[T in XCObjectType]: Record<
|
||||
string,
|
||||
{
|
||||
isa: T;
|
||||
name: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
>;
|
||||
};
|
||||
rootObject: string;
|
||||
rootObject_comment: string;
|
||||
};
|
||||
};
|
||||
constructor(pbxprojPath: string);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
//
|
||||
// `.pbxproj` related operation - starting & ending point.
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* First step to be executed while working with `.pbxproj` file.
|
||||
*/
|
||||
public parse(callback?: (err: Error | null, results?: string) => void): this;
|
||||
|
||||
public parseSync(): void;
|
||||
|
||||
/**
|
||||
* @returns Content of .pbxproj file.
|
||||
*/
|
||||
public writeSync(options?: { omitEmptyValues?: boolean }): string;
|
||||
|
||||
public allUuids(): UUID[];
|
||||
public generateUuid(): UUID;
|
||||
|
||||
public addPluginFile(path: unknown, opt: unknown): unknown;
|
||||
public removePluginFile(path: unknown, opt: unknown): unknown;
|
||||
public addProductFile(targetPath: unknown, opt: unknown): unknown;
|
||||
public removeProductFile(path: unknown, opt: unknown): unknown;
|
||||
public addSourceFile(path: string, opt: unknown, group: string): unknown;
|
||||
public removeSourceFile(path: string, opt: unknown, group: string): unknown;
|
||||
public addHeaderFile(path: string, opt: unknown, group: string): unknown;
|
||||
public removeHeaderFile(path: string, opt: unknown, group: string): unknown;
|
||||
public addResourceFile(path: string, opt: unknown, group: string): unknown;
|
||||
public removeResourceFile(path: string, opt: unknown, group: string): unknown;
|
||||
public addFramework(fpath: unknown, opt: unknown): unknown;
|
||||
public removeFramework(fpath: unknown, opt: unknown): unknown;
|
||||
public addCopyfile(fpath: unknown, opt: unknown): unknown;
|
||||
public pbxCopyfilesBuildPhaseObj(target: unknown): unknown;
|
||||
public addToPbxCopyfilesBuildPhase(file: unknown): void;
|
||||
public removeCopyfile(fpath: unknown, opt: unknown): unknown;
|
||||
public removeFromPbxCopyfilesBuildPhase(file: unknown): void;
|
||||
public addStaticLibrary(path: unknown, opt: unknown): unknown;
|
||||
/**
|
||||
* Adds to `PBXBuildFile` section
|
||||
*/
|
||||
public addToPbxBuildFileSection(file: PBXFile): void;
|
||||
public removeFromPbxBuildFileSection(file: unknown): void;
|
||||
public addPbxGroup(
|
||||
filePathsArray: string[],
|
||||
name: string,
|
||||
path: string,
|
||||
sourceTree?: string,
|
||||
): { uuid: UUID; pbxGroup: PBXGroup };
|
||||
public removePbxGroup(groupName: unknown): void;
|
||||
public addToPbxProjectSection(target: unknown): void;
|
||||
public addToPbxNativeTargetSection(target: unknown): void;
|
||||
public addToPbxFileReferenceSection(file: any): void;
|
||||
public removeFromPbxFileReferenceSection(file: unknown): unknown;
|
||||
public addToXcVersionGroupSection(file: unknown): void;
|
||||
public addToPluginsPbxGroup(file: unknown): void;
|
||||
public removeFromPluginsPbxGroup(file: unknown): unknown;
|
||||
public addToResourcesPbxGroup(file: unknown): void;
|
||||
public removeFromResourcesPbxGroup(file: unknown): unknown;
|
||||
public addToFrameworksPbxGroup(file: unknown): void;
|
||||
public removeFromFrameworksPbxGroup(file: unknown): unknown;
|
||||
public addToPbxEmbedFrameworksBuildPhase(file: unknown): void;
|
||||
public removeFromPbxEmbedFrameworksBuildPhase(file: unknown): void;
|
||||
public addToProductsPbxGroup(file: unknown): void;
|
||||
public removeFromProductsPbxGroup(file: unknown): unknown;
|
||||
public addToPbxSourcesBuildPhase(file: unknown): void;
|
||||
public removeFromPbxSourcesBuildPhase(file: unknown): void;
|
||||
/**
|
||||
* Adds to PBXResourcesBuildPhase` section
|
||||
* @param resourcesBuildPhaseSectionKey Because there's might more than one `Resources` build phase we need to ensure file is placed under correct one.
|
||||
*/
|
||||
public addToPbxResourcesBuildPhase(file: PBXFile): void;
|
||||
public removeFromPbxResourcesBuildPhase(file: unknown): void;
|
||||
public addToPbxFrameworksBuildPhase(file: unknown): void;
|
||||
public removeFromPbxFrameworksBuildPhase(file: unknown): void;
|
||||
public addXCConfigurationList(
|
||||
configurationObjectsArray: unknown,
|
||||
defaultConfigurationName: unknown,
|
||||
comment: unknown,
|
||||
): {
|
||||
uuid: unknown;
|
||||
xcConfigurationList: {
|
||||
isa: string;
|
||||
buildConfigurations: Array<unknown>;
|
||||
defaultConfigurationIsVisible: number;
|
||||
defaultConfigurationName: unknown;
|
||||
};
|
||||
};
|
||||
public addTargetDependency(
|
||||
target: unknown,
|
||||
dependencyTargets: unknown,
|
||||
): {
|
||||
uuid: unknown;
|
||||
target: unknown;
|
||||
};
|
||||
public addBuildPhase(
|
||||
filePathsArray: unknown,
|
||||
buildPhaseType: unknown,
|
||||
comment: unknown,
|
||||
target: unknown,
|
||||
optionsOrFolderType: unknown,
|
||||
subfolderPath: unknown,
|
||||
): {
|
||||
uuid: unknown;
|
||||
buildPhase: {
|
||||
isa: unknown;
|
||||
buildActionMask: number;
|
||||
files: Array<unknown>;
|
||||
runOnlyForDeploymentPostprocessing: number;
|
||||
};
|
||||
};
|
||||
/**
|
||||
* Retrieves main part describing PBXProjects that are available in `.pbxproj` file.
|
||||
*/
|
||||
public pbxProjectSection(): Record<UUID, PBXProject> & Record<UUIDComment, string>;
|
||||
public pbxBuildFileSection(): Record<UUID, PBXBuildFile> & Record<UUIDComment, string>;
|
||||
public pbxXCBuildConfigurationSection(): Record<UUID, XCBuildConfiguration> &
|
||||
Record<UUIDComment, string>;
|
||||
public pbxFileReferenceSection(): Record<UUID, PBXFile> & Record<UUIDComment, string>;
|
||||
public pbxNativeTargetSection(): Record<UUID, PBXNativeTarget> & Record<UUIDComment, string>;
|
||||
public xcVersionGroupSection(): unknown;
|
||||
public pbxXCConfigurationList(): Record<UUID, XCConfigurationList> & Record<UUIDComment, string>;
|
||||
public pbxGroupByName(name: string): PBXGroup | undefined;
|
||||
/**
|
||||
* @param targetName in most cases it's the name of the application
|
||||
*/
|
||||
public pbxTargetByName(targetName: string): PBXNativeTarget | undefined;
|
||||
public findTargetKey(name: string): string;
|
||||
public pbxItemByComment(name: string, pbxSectionName: unknown): unknown;
|
||||
public pbxSourcesBuildPhaseObj(target: unknown): unknown;
|
||||
public pbxResourcesBuildPhaseObj(target: unknown): unknown;
|
||||
public pbxFrameworksBuildPhaseObj(target: unknown): unknown;
|
||||
public pbxEmbedFrameworksBuildPhaseObj(target: unknown): unknown;
|
||||
public buildPhase(group: unknown, target: unknown): string;
|
||||
public buildPhaseObject(name: string, group: unknown, target: unknown): unknown;
|
||||
public addBuildProperty(prop: unknown, value: unknown, build_name: unknown): void;
|
||||
public removeBuildProperty(prop: unknown, build_name: unknown): void;
|
||||
public updateBuildProperty(prop: string, value: unknown, build: string): void;
|
||||
public updateProductName(name: string): void;
|
||||
public removeFromFrameworkSearchPaths(file: unknown): void;
|
||||
public addToFrameworkSearchPaths(file: unknown): void;
|
||||
public removeFromLibrarySearchPaths(file: unknown): void;
|
||||
public addToLibrarySearchPaths(file: unknown): void;
|
||||
public removeFromHeaderSearchPaths(file: unknown): void;
|
||||
public addToHeaderSearchPaths(file: unknown): void;
|
||||
public addToOtherLinkerFlags(flag: unknown): void;
|
||||
public removeFromOtherLinkerFlags(flag: unknown): void;
|
||||
public addToBuildSettings(buildSetting: unknown, value: unknown): void;
|
||||
public removeFromBuildSettings(buildSetting: unknown): void;
|
||||
/**
|
||||
* Checks whether there is a file with given `filePath` in the project.
|
||||
*/
|
||||
public hasFile(filePath: string): PBXFile | false;
|
||||
public addTarget(
|
||||
name: unknown,
|
||||
type: unknown,
|
||||
subfolder: unknown,
|
||||
): {
|
||||
uuid: unknown;
|
||||
pbxNativeTarget: {
|
||||
isa: string;
|
||||
name: string;
|
||||
productName: string;
|
||||
productReference: unknown;
|
||||
productType: string;
|
||||
buildConfigurationList: unknown;
|
||||
buildPhases: Array<unknown>;
|
||||
buildRules: Array<unknown>;
|
||||
dependencies: Array<unknown>;
|
||||
};
|
||||
};
|
||||
/**
|
||||
* Get First PBXProject that can be found in `.pbxproj` file.
|
||||
*/
|
||||
public getFirstProject(): { uuid: UUID; firstProject: PBXProject };
|
||||
public getFirstTarget(): {
|
||||
uuid: UUID;
|
||||
firstTarget: unknown;
|
||||
};
|
||||
/**
|
||||
* Retrieves PBXNativeTarget by the type
|
||||
*/
|
||||
public getTarget(productType: ProductType): { uuid: UUID; target: PBXNativeTarget } | null;
|
||||
public addToPbxGroupType(file: unknown, groupKey: unknown, groupType: unknown): void;
|
||||
public addToPbxVariantGroup(file: unknown, groupKey: unknown): void;
|
||||
public addToPbxGroup(file: PBXFile, groupKey: UUID): void;
|
||||
public pbxCreateGroupWithType(name: unknown, pathName: unknown, groupType: unknown): unknown;
|
||||
public pbxCreateVariantGroup(name: unknown): unknown;
|
||||
public pbxCreateGroup(name: string, pathName: string): UUID;
|
||||
public removeFromPbxGroupAndType(file: unknown, groupKey: unknown, groupType: unknown): void;
|
||||
public removeFromPbxGroup(file: unknown, groupKey: unknown): void;
|
||||
public removeFromPbxVariantGroup(file: unknown, groupKey: unknown): void;
|
||||
public getPBXGroupByKeyAndType(key: unknown, groupType: unknown): unknown;
|
||||
/**
|
||||
* @param groupKey UUID.
|
||||
*/
|
||||
public getPBXGroupByKey(groupKey: string): PBXGroup | undefined;
|
||||
public getPBXVariantGroupByKey(key: unknown): unknown;
|
||||
public findPBXGroupKeyAndType(criteria: unknown, groupType: unknown): string;
|
||||
/**
|
||||
* @param criteria Params that should be used to locate desired PBXGroup.
|
||||
*/
|
||||
public findPBXGroupKey(criteria: { name?: string; path?: string }): UUID | undefined;
|
||||
public findPBXVariantGroupKey(criteria: unknown): string;
|
||||
public addLocalizationVariantGroup(
|
||||
name: unknown,
|
||||
): {
|
||||
uuid: unknown;
|
||||
fileRef: unknown;
|
||||
basename: unknown;
|
||||
};
|
||||
public addKnownRegion(name: string): void;
|
||||
public removeKnownRegion(name: string): void;
|
||||
public hasKnownRegion(name: string): boolean;
|
||||
public getPBXObject(name: string): unknown;
|
||||
/**
|
||||
* - creates `PBXFile`
|
||||
* - adds to `PBXFileReference` section
|
||||
* - adds to `PBXGroup` or `PBXVariantGroup` if applicable
|
||||
* @returns `null` if file is already in `pbxproj`.
|
||||
*/
|
||||
public addFile(
|
||||
path: string,
|
||||
group?: string,
|
||||
opt?: {
|
||||
plugin?: string;
|
||||
target?: string;
|
||||
variantGroup?: string;
|
||||
lastKnownFileType?: string;
|
||||
defaultEncoding?: 4;
|
||||
customFramework?: true;
|
||||
explicitFileType?: number;
|
||||
weak?: true;
|
||||
compilerFLags?: string;
|
||||
embed?: boolean;
|
||||
sign?: boolean;
|
||||
},
|
||||
): PBXFile | null;
|
||||
public removeFile(path: unknown, group: unknown, opt: unknown): unknown;
|
||||
public getBuildProperty(prop: unknown, build: unknown): unknown;
|
||||
public getBuildConfigByName(name: unknown): object;
|
||||
public addDataModelDocument(filePath: unknown, group: unknown, opt: unknown): unknown;
|
||||
public addTargetAttribute(prop: unknown, value: unknown, target: unknown): void;
|
||||
public removeTargetAttribute(prop: unknown, target: unknown): void;
|
||||
}
|
||||
|
||||
export function project(projectPath: string): XcodeProject;
|
||||
}
|
||||
|
||||
declare module 'xcode/lib/pbxFile' {
|
||||
export default class PBXFile implements pbxFile {
|
||||
public basename: string;
|
||||
public lastKnownFileType?: string;
|
||||
public group?: string;
|
||||
public path?: string;
|
||||
public fileEncoding?: number;
|
||||
public defaultEncoding?: number;
|
||||
public sourceTree: string;
|
||||
public includeInIndex?: number;
|
||||
public explicitFileType?: unknown;
|
||||
public settings?: object;
|
||||
public uuid?: string;
|
||||
public fileRef: string;
|
||||
public target?: string;
|
||||
constructor(file: string);
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
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}`;
|
||||
@@ -1,164 +0,0 @@
|
||||
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 };
|
||||
+10
-12
@@ -9,7 +9,7 @@ import { getRedisClient, RedisClient } from 'turtle/utils/redis';
|
||||
export const NORMAL = 'normalPriority';
|
||||
export const HIGH = 'highPriority';
|
||||
|
||||
export enum TurtleMode {
|
||||
export enum TurtleModeLabels {
|
||||
Normal = 'normal',
|
||||
High = 'high',
|
||||
HighOnly = 'highOnly',
|
||||
@@ -100,15 +100,13 @@ async function getConfiguration(currentRedisClient: any) {
|
||||
|
||||
export async function getLabeledConfiguration(currentRedisClient?: any) {
|
||||
const configuration = await getConfiguration(currentRedisClient);
|
||||
return configuration.map((i: string[]) => labelConfiguration(i));
|
||||
}
|
||||
|
||||
export function labelConfiguration(configuration: string[]): TurtleMode {
|
||||
if (isEqual(configuration, NORMAL_CONFIGURATION)) {
|
||||
return TurtleMode.Normal;
|
||||
} else if (isEqual(configuration, HIGH_CONFIGURATION)) {
|
||||
return TurtleMode.High;
|
||||
} else {
|
||||
return TurtleMode.HighOnly;
|
||||
}
|
||||
return configuration.map((i: string[]) => {
|
||||
if (isEqual(i, NORMAL_CONFIGURATION)) {
|
||||
return TurtleModeLabels.Normal;
|
||||
} else if (isEqual(i, HIGH_CONFIGURATION)) {
|
||||
return TurtleModeLabels.High;
|
||||
} else {
|
||||
return TurtleModeLabels.HighOnly;
|
||||
}
|
||||
});
|
||||
}
|
||||
+6
-15
@@ -12,27 +12,18 @@ export enum RedisClient {
|
||||
Configuration = 'REDIS_CLIENT_CONFIGURATION',
|
||||
}
|
||||
|
||||
interface IClientConfig {
|
||||
[key: string]: {
|
||||
url: string;
|
||||
caCertificate?: string;
|
||||
};
|
||||
}
|
||||
interface IClientConfig { [key: string]: string; }
|
||||
|
||||
const clientConfigs: IClientConfig = {
|
||||
[RedisClient.Subscriber]: config.redis.main,
|
||||
[RedisClient.Default]: config.redis.main,
|
||||
[RedisClient.Configuration]: config.redis.turtle,
|
||||
const clientToUrl: IClientConfig = {
|
||||
[RedisClient.Subscriber]: config.redis.url,
|
||||
[RedisClient.Default]: config.redis.url,
|
||||
[RedisClient.Configuration]: config.redis.configUrl,
|
||||
};
|
||||
|
||||
export function connect(timeoutMs: number, type: string): Promise<any> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const { url, caCertificate } = clientConfigs[type];
|
||||
const redisClient = new Redis(url, {
|
||||
const redisClient = new Redis(clientToUrl[type], {
|
||||
maxRetriesPerRequest: 2,
|
||||
...caCertificate && {
|
||||
tls: { ca: caCertificate },
|
||||
},
|
||||
});
|
||||
const timer = setTimeout(() => reject(new Error('Timeout at connecting to Redis')), timeoutMs);
|
||||
redisClient.on('ready', () => {
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
import { URL } from 'url';
|
||||
|
||||
import request from 'request-promise';
|
||||
|
||||
import config from 'turtle/config';
|
||||
|
||||
async function setSupportedSdkVersions(platform: string, sdkVersions: string[]) {
|
||||
const { href } = new URL('/--/api/v2/standalone-build/setSupportedSDKVersions', resolveWWWEndpoint());
|
||||
await request({
|
||||
method: 'POST',
|
||||
uri: href,
|
||||
headers: {
|
||||
'secret-token': config.www.secretToken,
|
||||
},
|
||||
body: {
|
||||
platform,
|
||||
sdkVersions,
|
||||
},
|
||||
json: true,
|
||||
});
|
||||
}
|
||||
|
||||
async function setTurtleVersion(version: string) {
|
||||
const { href } = new URL('/--/api/v2/standalone-build/setTurtleVersion', resolveWWWEndpoint());
|
||||
await request({
|
||||
method: 'POST',
|
||||
uri: href,
|
||||
headers: {
|
||||
'secret-token': config.www.secretToken,
|
||||
},
|
||||
body: {
|
||||
version,
|
||||
},
|
||||
json: true,
|
||||
});
|
||||
}
|
||||
|
||||
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 { setSupportedSdkVersions, setTurtleVersion };
|
||||
@@ -1,56 +0,0 @@
|
||||
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 };
|
||||
@@ -2,9 +2,6 @@ import * as schemas from 'turtle/jobsSchemas';
|
||||
|
||||
export async function sanitizeJob(job: any) {
|
||||
const schema = (schemas as any)[job.platform];
|
||||
if (!schema) {
|
||||
throw new Error(`Unsupported platform: ${job.platform}`);
|
||||
}
|
||||
const { error, value } = schema.validate(job, { stripUnknown: true });
|
||||
if (error) {
|
||||
throw error;
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
#! /usr/bin/env bash
|
||||
# This file was generated by nix-binstubs
|
||||
exec nix run -f "$(dirname "$0")/../../../nix" nodejs-12_x --command node "$@"
|
||||
exec nix run -f "$(dirname "$0")/../../../nix" nodejs-8_x --command node "$@"
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
#! /usr/bin/env bash
|
||||
# This file was generated by nix-binstubs
|
||||
exec nix run -f "$(dirname "$0")/../../../nix" nodejs-12_x --command npm "$@"
|
||||
exec nix run -f "$(dirname "$0")/../../../nix" nodejs-8_x --command npm "$@"
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
#! /usr/bin/env bash
|
||||
# This file was generated by nix-binstubs
|
||||
exec nix run -f "$(dirname "$0")/../../../nix" nodejs-12_x --command npx "$@"
|
||||
exec nix run -f "$(dirname "$0")/../../../nix" nodejs-8_x --command npx "$@"
|
||||
+1
-6
@@ -10,10 +10,5 @@
|
||||
},
|
||||
"rulesDirectory": [
|
||||
"node_modules/tslint-eslint-rules/dist/rules"
|
||||
],
|
||||
"linterOptions": {
|
||||
"exclude": [
|
||||
"src/types/xcode.d.ts"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in new issue
Block a user