mirror of
https://github.com/expo/turtle.git
synced 2026-11-14 19:12:55 -10:00
Compare commits
111
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2df39da2e6 | ||
|
|
6925e290cc | ||
|
|
9e2557b6f4 | ||
|
|
d743f8313e | ||
|
|
7df3f70e9c | ||
|
|
34cf811fd7 | ||
|
|
1d825e6310 | ||
|
|
dd6c806e0f | ||
|
|
ccbdf7418e | ||
|
|
552c1074c0 | ||
|
|
18d35d7730 | ||
|
|
7aaac7b648 | ||
|
|
c472a5a6ea | ||
|
|
527821ee50 | ||
|
|
d2bff1639c | ||
|
|
84cf930537 | ||
|
|
4c3582b8df | ||
|
|
52b029a5a9 | ||
|
|
86047db677 | ||
|
|
2b8548f489 | ||
|
|
44b0d8c696 | ||
|
|
9b70b047a3 | ||
|
|
98310af75a | ||
|
|
5f9bf0e735 | ||
|
|
32c8032bb3 | ||
|
|
10322bbca1 | ||
|
|
88ca49766a | ||
|
|
0d22f3ed0f | ||
|
|
32d104a03b | ||
|
|
97422aeb54 | ||
|
|
7a80d92e72 | ||
|
|
1a2a7654c2 | ||
|
|
a5aaa46790 | ||
|
|
1691655f61 | ||
|
|
f38ab7c9ee | ||
|
|
8fd8a6e70e | ||
|
|
43a319b12b | ||
|
|
511f58e6ec | ||
|
|
350f68e330 | ||
|
|
851b0a62ab | ||
|
|
d97f290ce1 | ||
|
|
2feb10aeec | ||
|
|
8a288c271a | ||
|
|
47fe68abbd | ||
|
|
51d00a8706 | ||
|
|
3f25edccd7 | ||
|
|
2f10ab1bc9 | ||
|
|
4f8c21a075 | ||
|
|
7179f6019c | ||
|
|
2bbf2d7784 | ||
|
|
3ccb4c994e | ||
|
|
46706a7cdb | ||
|
|
383358b11d | ||
|
|
a87cc75b5d | ||
|
|
391a3a9937 | ||
|
|
7cfedbc448 | ||
|
|
9b6eb8b66a | ||
|
|
c52a126409 | ||
|
|
908ab0f74d | ||
|
|
ab15d4c407 | ||
|
|
9f7b77a09c | ||
|
|
67260647ff | ||
|
|
849759c6c5 | ||
|
|
fdcf67c96f | ||
|
|
407db0efb6 | ||
|
|
8ec619a627 | ||
|
|
849e026833 | ||
|
|
13652b0e07 | ||
|
|
06c2c71515 | ||
|
|
5f98e9f5ce | ||
|
|
f314ef17dd | ||
|
|
30274bfd7e | ||
|
|
8ef99f2eae | ||
|
|
855e4bb962 | ||
|
|
df789b2de7 | ||
|
|
eff0556291 | ||
|
|
db74843ae0 | ||
|
|
a0e1382531 | ||
|
|
952dcd0cd3 | ||
|
|
0cd4e2953a | ||
|
|
a03d93cb27 | ||
|
|
010e92472b | ||
|
|
75316b5f07 | ||
|
|
4baa49e8fe | ||
|
|
edb167e6b1 | ||
|
|
d552b97654 | ||
|
|
12718c0b36 | ||
|
|
f9600f26e8 | ||
|
|
68f9744f7b | ||
|
|
8c2031c3d7 | ||
|
|
3165b5346e | ||
|
|
1552c9e7f2 | ||
|
|
51a0e772c0 | ||
|
|
98747c1db6 | ||
|
|
4f64aa2617 | ||
|
|
1f487d39fb | ||
|
|
f7e647c1f4 | ||
|
|
d900e3c491 | ||
|
|
32b049df86 | ||
|
|
723c84b575 | ||
|
|
0ab4d2ed90 | ||
|
|
05b96a5b6f | ||
|
|
5467aca0fb | ||
|
|
cf1e1daa26 | ||
|
|
8649968531 | ||
|
|
b89214fcc9 | ||
|
|
0142147a61 | ||
|
|
331c8edba7 | ||
|
|
ed382e0d2c | ||
|
|
3f0958845d | ||
|
|
6e345757e3 |
No files matched your search
@@ -137,6 +137,23 @@ commands:
|
||||
paths:
|
||||
- "<< parameters.workingdir >>/<< parameters.platform >>/<< parameters.sdk_version >>"
|
||||
|
||||
deploy_turtle:
|
||||
parameters:
|
||||
platform:
|
||||
type: string
|
||||
env:
|
||||
type: string
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Install curl & jq
|
||||
command: nix-env -iA nixpkgs.curl nixpkgs.jq
|
||||
- run:
|
||||
name: Schedule a Turtle deploy
|
||||
command: |
|
||||
echo "We're going to deploy << parameters.platform >> Turtles to << parameters.env >>"
|
||||
./scripts/deploy.sh "<< parameters.platform >>" "<< parameters.env >>"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
executor: nix
|
||||
@@ -203,6 +220,34 @@ jobs:
|
||||
sdk_version: sdk32
|
||||
platform: android
|
||||
|
||||
android_staging_deploy:
|
||||
executor: nix
|
||||
steps:
|
||||
- deploy_turtle:
|
||||
platform: android
|
||||
env: staging
|
||||
|
||||
android_production_deploy:
|
||||
executor: nix
|
||||
steps:
|
||||
- deploy_turtle:
|
||||
platform: android
|
||||
env: production
|
||||
|
||||
ios_staging_deploy:
|
||||
executor: nix
|
||||
steps:
|
||||
- deploy_turtle:
|
||||
platform: ios
|
||||
env: staging
|
||||
|
||||
ios_production_deploy:
|
||||
executor: nix
|
||||
steps:
|
||||
- deploy_turtle:
|
||||
platform: ios
|
||||
env: production
|
||||
|
||||
workflows:
|
||||
checks:
|
||||
jobs:
|
||||
@@ -212,3 +257,25 @@ workflows:
|
||||
- unit_tests
|
||||
- ios_smoke_tests
|
||||
- android_smoke_tests
|
||||
deploy:
|
||||
jobs:
|
||||
- android_staging_approve_deploy:
|
||||
type: approval
|
||||
- android_staging_deploy:
|
||||
requires:
|
||||
- android_staging_approve_deploy
|
||||
- android_production_approve_deploy:
|
||||
type: approval
|
||||
- android_production_deploy:
|
||||
requires:
|
||||
- android_production_approve_deploy
|
||||
- ios_staging_approve_deploy:
|
||||
type: approval
|
||||
- ios_staging_deploy:
|
||||
requires:
|
||||
- ios_staging_approve_deploy
|
||||
- ios_production_approve_deploy:
|
||||
type: approval
|
||||
- ios_production_deploy:
|
||||
requires:
|
||||
- ios_production_approve_deploy
|
||||
@@ -8,16 +8,20 @@ source_local() {
|
||||
watch_file $file
|
||||
}
|
||||
|
||||
source_up || true
|
||||
source_local
|
||||
|
||||
if [[ "$CI" != "true" && (-z "$GITHUB_TOKEN" || -z "$CIRCLE_API_USER_TOKEN") ]]; then
|
||||
yellow=`tput setaf 3`
|
||||
reset=`tput sgr0`
|
||||
echo "${yellow}please set GITHUB_TOKEN and CIRCLE_API_USER_TOKEN env variables in .envrc.local file if you wish to release turtle-cli"
|
||||
echo "run 'cp .envrc.local.example .envrc.local' if you don't have one yet and edit the new file${reset}"
|
||||
fi
|
||||
|
||||
export NODE_ENV=development
|
||||
|
||||
export EXPO_TURTLE_TOOLS_DIR="$(pwd)/tools"
|
||||
|
||||
if [ -z "$EXPO_UNIVERSE_DIR" ]; then
|
||||
PATH_add $EXPO_TURTLE_TOOLS_DIR/bin
|
||||
if [ "$CI" = "true" ]; then
|
||||
PATH_add $EXPO_TURTLE_TOOLS_DIR/ci/bin
|
||||
fi
|
||||
PATH_add $EXPO_TURTLE_TOOLS_DIR/bin
|
||||
if [ "$CI" = "true" ]; then
|
||||
PATH_add $EXPO_TURTLE_TOOLS_DIR/ci/bin
|
||||
fi
|
||||
@@ -0,0 +1,2 @@
|
||||
export GITHUB_TOKEN=__PUT_YOUR_GITHUB_TOKEN_HERE__ # follow the guide to create one: https://help.github.com/en/articles/creating-a-personal-access-token-for-the-command-line
|
||||
export CIRCLE_API_USER_TOKEN=__PUT_YOUR_CIRCLECI_API_TOKEN_HERE__ # create one here: https://circleci.com/account/api
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
name: "\U0001F41B Bug Report"
|
||||
about: You want to report a reproducible bug or regression in turtle-cli.
|
||||
title: ''
|
||||
labels: 'bug'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!-- Thanks for helping expo! Before you submit your issue, please make sure you followed our checklist and check the appropriate boxes by putting an x in the [ ]: [x] -->
|
||||
|
||||
### New Issue Checklist
|
||||
|
||||
- [ ] Updated turtle-cli to the latest version (`yarn global add turtle-cli` or `npm install --global turtle-cli`).
|
||||
- [ ] I read the [Contribution Guidelines](https://github.com/expo/turtle/blob/master/CONTRIBUTING.md).
|
||||
- [ ] I read [docs.expo.io](https://docs.expo.io) (Managed Workflow > Distributing Your App).
|
||||
- [ ] I searched for [existing GitHub issues](https://github.com/expo/turtle/issues).
|
||||
- [ ] **I enclosed the complete output when running turtle, including the stack trace and command used.**
|
||||
|
||||
### Issue Description
|
||||
<!-- Please include what's happening, expected behavior, and any relevant code samples -->
|
||||
|
||||
##### Command executed
|
||||
<!-- The command you executed on the command line that resulted in an error -->
|
||||
|
||||
##### Complete output when running turtle, including the stack trace and command used
|
||||
|
||||
<details>
|
||||
<pre> [PUT LOGS HERE] </pre>
|
||||
</details>
|
||||
|
||||
### Environment
|
||||
|
||||
<!-- Please run `expo diagnostics` and copy the output below. This will help us help you. -->
|
||||
|
||||
<details>
|
||||
<pre> [PUT OUTPUT HERE] </pre>
|
||||
</details>
|
||||
@@ -0,0 +1,22 @@
|
||||
---
|
||||
name: "\U0001F64B Feature Request"
|
||||
about: Want us to add something to turtle-cli?
|
||||
title: ''
|
||||
labels: 'enhancement'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Feature Request
|
||||
|
||||
#### Motivation Behind Feature
|
||||
<!-- Why should this feature be implemented? What problem does it solve? -->
|
||||
|
||||
#### Feature Description
|
||||
<!-- Describe your feature request in detail -->
|
||||
<!-- Please provide any code examples or screenshots of what this feature would look like -->
|
||||
<!-- Are there any drawbacks? Will this break anything for existing users? -->
|
||||
|
||||
#### Alternatives or Workarounds
|
||||
<!-- Describe alternatives or workarounds you are currently using -->
|
||||
<!-- Are there ways to do this with existing commands? -->
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
name: "\U00002753 Questions and discussions"
|
||||
about: You have a question about turtle-cli or want to discuss some aspects of turtle-cli.
|
||||
title: ''
|
||||
labels: 'question'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Question Checklist
|
||||
|
||||
- [ ] I read the [Contribution Guidelines](https://github.com/expo/turtle/blob/master/CONTRIBUTING.md).
|
||||
- [ ] I read [docs.expo.io](https://docs.expo.io) (Managed Workflow > Distributing Your App).
|
||||
- [ ] I searched for [existing GitHub issues](https://github.com/expo/turtle/issues).
|
||||
|
||||
### Question Subject
|
||||
<!-- What command do you have a question about? -->
|
||||
<!-- Is this a question about documentation? -->
|
||||
|
||||
#### Question Description
|
||||
<!-- Please include expected behavior and any relevant code samples with your question if possible -->
|
||||
@@ -1,11 +0,0 @@
|
||||
# Why
|
||||
|
||||
Please describe the motivation for this PR, and link to relevant GitHub issues, forums posts, or feature requests.
|
||||
|
||||
# How
|
||||
|
||||
How did you build this feature or fix this bug and why?
|
||||
|
||||
# Test Plan
|
||||
|
||||
Please describe how you tested this change and how a reviewer could reproduce your test, especially if this PR does not include automated tests! If possible, please also provide terminal output and/or screenshots demonstrating your test/reproduction.
|
||||
@@ -0,0 +1,15 @@
|
||||
<!-- Thanks for contributing to _turtle_! Before you submit your pull request, please make sure to check the following boxes by putting an x in the [ ] (don't: [x ], [ x], do: [x]) -->
|
||||
|
||||
### Checklist
|
||||
- [ ] I've read the [Contribution Guidelines](https://github.com/expo/turtle/blob/master/CONTRIBUTING.md).
|
||||
- [ ] I've updated the [CHANGELOG](https://github.com/expo/turtle/blob/master/CHANGELOG.md) if necessary.
|
||||
- [ ] I've ensured the unit and smoke tests are still passing - either by running `yarn test:unit` and `yarn test:smoke:[ios|android]` or by checking the appropriate CircleCI builds' statuses.
|
||||
- [ ] **I've manually tested whether the changes I made work as expected.**
|
||||
|
||||
### Motivation and Context
|
||||
<!-- Why is this change required? What problem does it solve? -->
|
||||
<!-- If it fixes an open issue, please link to the issue here. -->
|
||||
|
||||
### Description
|
||||
<!-- Describe your changes in detail -->
|
||||
<!-- Please describe in detail how you tested your changes. -->
|
||||
@@ -12,3 +12,5 @@ shell.apk
|
||||
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
.envrc.local
|
||||
@@ -8,5 +8,8 @@
|
||||
},
|
||||
"github": {
|
||||
"release": true
|
||||
},
|
||||
"hooks": {
|
||||
"after:release": "yarn release:update:turtle-cli-example"
|
||||
}
|
||||
}
|
||||
+123
-5
@@ -4,11 +4,130 @@ 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/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
## Unreleased
|
||||
|
||||
## [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))!
|
||||
- Added shell apps for SDK 33.
|
||||
- Support for Android App Bundles
|
||||
- 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.
|
||||
@@ -18,7 +137,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- 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).
|
||||
- Fixed support for Android tarballs without `universe-package.json`.
|
||||
|
||||
## [0.7.2] - 2019-05-09
|
||||
### Added
|
||||
@@ -91,7 +209,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [0.5.10] - 2019-02-19
|
||||
### Added
|
||||
- Register Turtle version in Redis.
|
||||
- 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.
|
||||
|
||||
|
||||
+2
-5
@@ -16,9 +16,6 @@ This repository contains the codebase for the `turtle-cli` NPM package. The same
|
||||
### Branches
|
||||
The `master` branch of the repository should be kept releasable at any time. This way we can continuously release fixes and improvements without costly managing of different branches and issues will be noticed and fixed quickly. This also ensures other contributors can check out the latest version from GitHub and work on it with minimal disruption from other features in progress.
|
||||
|
||||
## Setting up the repository for development
|
||||
*TODO*
|
||||
|
||||
## Submitting a pull request
|
||||
To submit a pull request:
|
||||
1. Fork the [repository](https://github.com/expo/turtle) and create a feature branch. (Existing contributors can create feature branches without forking. Prefix the branch name with `@your-github-username/`.)
|
||||
@@ -27,7 +24,7 @@ To submit a pull request:
|
||||
4. Wait for a review and adjust the code if necessary.
|
||||
|
||||
## Publishing a release
|
||||
- Make sure you have set `GITHUB_TOKEN` and `CIRCLE_API_USER_TOKEN` environment variables in `.envrc.local` file. If you don't have the file, run `cp .envrc.local.example .envrc.local` and edit the file.
|
||||
- To release a new version of `turtle-cli`, run `yarn release` command.
|
||||
- If you wish to release a new *beta* version of `turtle-cli`, run `yarn release:beta` instead.
|
||||
- Update [Changelog](CHANGELOG.md).
|
||||
- In a terminal, `cd` into [expo/turtle-cli-example](https://github.com/expo/turtle-cli-example) repository, run `yarn update-turtle-cli-version` (this script updates `turtle-cli` version number in CI configuration files and commits the changes) and then run `git push`. Thanks!
|
||||
- Update the [changelog](CHANGELOG.md).
|
||||
@@ -0,0 +1,35 @@
|
||||
# Turtle Development
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Working `www` service, see [this README](https://github.com/expo/universe/tree/master/server/www/README.md) for more details.
|
||||
- Own AWS SQS queues. See [this README](https://github.com/expo/universe/tree/master/terraform/turtle-queues/README.md) to learn more.
|
||||
|
||||
## Setup
|
||||
|
||||
- Run `update-local-secrets` to populate the `.secrets*` files. You'll need to run this any time any secret changes (it shouldn't be very often).
|
||||
- Run `EXPO_UNIVERSE_DIR=/path/to/universe/dir yarn secrets:init-private YOUR_SQS_NICKNAME`. Alternatively, you can create `.secrets.local-queue` file with the SQS queues' urls yourself (`AWS_SQS_OUT_QUEUE_URL`, `AWS_SQS_ANDROID_QUEUE_URL`, `AWS_SQS_ANDROID_PRIORITY_QUEUE_URL`, `AWS_SQS_IOS_QUEUE_URL`, `AWS_SQS_IOS_PRIORITY_QUEUE_URL`)
|
||||
- Run `yarn set-workingdir:local` or `yarn set-workingdir:remote`:
|
||||
- `:local` creates symlinks to the shell apps in `expo` repository (_unfortunately this is currently broken_)
|
||||
- `:remote` downloads precompiled shell apps
|
||||
- Run `yarn` to install node modules.
|
||||
- Run `yarn start:ios` or `yarn start:android` to run Turtle.
|
||||
|
||||
## Updating shell apps
|
||||
|
||||
_TODO_
|
||||
|
||||
## Generating recording files for smoke tests
|
||||
|
||||
Smoke tests are powered by [Nock](https://www.npmjs.com/package/nock) which uses JSON files containing responses to the HTTP requests fired by the build process.
|
||||
|
||||
To record new responses remove old `recording.json` and run tests and then manually schedule a build with `expo-cli` tool.
|
||||
|
||||
As a precaution, the file with HTTP requests/responses contains, among other things, iOS certificates used for the test build, is
|
||||
encrypted with `git-crypt`. Remember not to revoke them, because then the tests will fail.
|
||||
|
||||
## Other notes
|
||||
|
||||
Turtle uses Redis to get notifications (from www) about builds cancellations. To make this feature working, you have to use the same Redis instance as www. Therefore, you need to remember about starting www before starting Turtle. If you forget about it, don't worry, Turtle will remind you to run `yarn start-docker` in `server/www` directory.
|
||||
|
||||
Turtle uploads build artifacts to S3. This could take some time if you have a poor internet connection. To facilitate local development, there is a feature which allows Turtle to fake artifacts upload. `secrets:init-private` script, which you should have run while setting up Turtle, sets fake upload directory to your user's default `Downloads` directory (we're assuming you're using Mac). If you need to test uploading artifacts to S3, you have to edit `.secrets.local` file and comment or remove `TURTLE_FAKE_UPLOAD` and `TURTLE_FAKE_UPLOAD_DIR` environment variables.
|
||||
+5
-102
@@ -1,104 +1,5 @@
|
||||
FROM openjdk:8u141
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
|
||||
# https://github.com/yarnpkg/yarn/issues/2821
|
||||
RUN apt-get update && apt-get install apt-transport-https
|
||||
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
|
||||
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
|
||||
|
||||
# Install dependencies
|
||||
RUN dpkg --add-architecture i386 && \
|
||||
apt-get update && \
|
||||
apt-get install -yq \
|
||||
ant\
|
||||
build-essential\
|
||||
bzip2:i386\
|
||||
file\
|
||||
lib32ncurses5\
|
||||
lib32z1\
|
||||
libc6:i386\
|
||||
libncurses5:i386\
|
||||
libstdc++6:i386\
|
||||
rsync\
|
||||
unzip\
|
||||
yarn\
|
||||
zlib1g:i386\
|
||||
--no-install-recommends && \
|
||||
apt-get clean
|
||||
|
||||
ENV NPM_CONFIG_LOGLEVEL warn
|
||||
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 \
|
||||
&& ln -s /usr/local/bin/node /usr/local/bin/nodejs
|
||||
|
||||
# Download and untar SDK
|
||||
ENV ANDROID_HOME /usr/local/android-sdk-linux
|
||||
ENV ANDROID_SDK /usr/local/android-sdk-linux
|
||||
ENV ANDROID_SDK_URL https://dl.google.com/android/repository/sdk-tools-linux-4333796.zip
|
||||
RUN mkdir -p ${ANDROID_HOME} && \
|
||||
curl -L "${ANDROID_SDK_URL}" > ${ANDROID_HOME}/sdk.zip && \
|
||||
cd ${ANDROID_HOME} && \
|
||||
unzip -qq sdk.zip && \
|
||||
rm sdk.zip && \
|
||||
mkdir -p ${HOME}/.android && \
|
||||
touch ${HOME}/.android/repositories.cfg
|
||||
|
||||
ENV PATH ${ANDROID_HOME}/platform-tools:${PATH}
|
||||
ENV PATH ${ANDROID_HOME}/tools:${PATH}
|
||||
ENV PATH ${ANDROID_HOME}/tools/bin:${PATH}
|
||||
ENV PATH ${ANDROID_HOME}/build-tools/28.0.3/:${PATH}
|
||||
|
||||
RUN yes | sdkmanager --licenses > /dev/null
|
||||
RUN yes | sdkmanager \
|
||||
"platforms;android-23" \
|
||||
"platforms;android-24" \
|
||||
"platforms;android-25" \
|
||||
"platforms;android-26" \
|
||||
"platforms;android-27" \
|
||||
"platforms;android-28" | grep -v '=' || echo 'no output'
|
||||
RUN yes | sdkmanager "platform-tools" | grep -v '=' || echo 'no output'
|
||||
RUN yes | sdkmanager "build-tools;28.0.3" | grep -v '=' || echo 'no output'
|
||||
RUN yes | sdkmanager \
|
||||
"extras;android;m2repository" \
|
||||
"extras;google;m2repository" \
|
||||
"extras;google;google_play_services" | grep -v '=' || echo 'no output'
|
||||
|
||||
# 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
|
||||
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
|
||||
# see docker-base/Dockerfile to learn what's installed in the turtle-android-base image
|
||||
FROM gcr.io/exponentjs/turtle-android-base:0.1.0
|
||||
|
||||
ADD . /app/turtle
|
||||
|
||||
@@ -123,4 +24,6 @@ ENV TURTLE_WORKING_DIR_PATH /app/turtle/workingdir/
|
||||
|
||||
WORKDIR /app/turtle
|
||||
|
||||
CMD ["node", "./build/server.js"]
|
||||
ADD supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||
|
||||
CMD ["/usr/bin/supervisord"]
|
||||
@@ -15,21 +15,20 @@ Turtle CLI is a command line interface for building Expo standalone apps.
|
||||
You can use it both on your CI and your private computer.
|
||||
|
||||
- [Changelog](CHANGELOG.md)
|
||||
- [Contributing to Turtle CLI](CONTRIBUTING.md)
|
||||
- [Contributing](CONTRIBUTING.md)
|
||||
- [Development](DEVELOPMENT.md)
|
||||
- [Code of Conduct](CODE_OF_CONDUCT.md)
|
||||
|
||||
## Glossary
|
||||
- **Turtle** - script which takes a shell app, fills it with user's code and produces a standalone app
|
||||
- **Shell app** — precompiled (in case of iOS builds) Expo app which doesn't have user's code
|
||||
- **Standalone app** - .ipa/.apk file, a user uploads standalone apps to the Google Play Store/Apple App Store
|
||||
|
||||
## Installation
|
||||
|
||||
[Installation instructions and documentation here.](https://docs.expo.io/versions/latest/distribution/turtle-cli)
|
||||
|
||||
## Usage example
|
||||
|
||||
See the [expo/turtle-cli-example](https://github.com/expo/turtle-cli-example) repository to learn how to use Turtle CLI in order to build Expo standalone apps on your CI.
|
||||
|
||||
## Do you need help?
|
||||
|
||||
- Make sure you've read [the Expo Docs](https://docs.expo.io/), especially [Building Standalone Apps on Your CI
|
||||
](https://docs.expo.io/versions/latest/distribution/turtle-cli) and [Building Standalone Apps](https://docs.expo.io/versions/latest/distribution/building-standalone-apps) guides.
|
||||
- Search for existing GitHub issues [in this repository](https://github.com/expo/turtle/issues) and in [expo/expo](https://github.com/expo/expo/issues) repository.
|
||||
@@ -39,5 +38,6 @@ See the [expo/turtle-cli-example](https://github.com/expo/turtle-cli-example) re
|
||||
* ask a question on [Expo Developers Slack](http://slack.expo.io).
|
||||
|
||||
## License
|
||||
|
||||
The Turtle CLI source code is made available under the [MIT license](LICENSE).
|
||||
Some of the dependencies are licensed differently, with the BSD license, for example.
|
||||
@@ -0,0 +1,92 @@
|
||||
# If you ever need to rebuild this, run:
|
||||
# yarn docker:build-and-push:android-base-image NEW_IMAGE_SEMVER
|
||||
FROM openjdk:8u141
|
||||
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
|
||||
# https://github.com/yarnpkg/yarn/issues/2821
|
||||
RUN apt-get update && apt-get install apt-transport-https
|
||||
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
|
||||
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
|
||||
|
||||
# Install dependencies
|
||||
RUN dpkg --add-architecture i386 && \
|
||||
apt-get update && \
|
||||
apt-get install -yq \
|
||||
ant\
|
||||
build-essential\
|
||||
bzip2:i386\
|
||||
file\
|
||||
lib32ncurses5\
|
||||
lib32z1\
|
||||
libc6:i386\
|
||||
libncurses5:i386\
|
||||
libstdc++6:i386\
|
||||
rsync\
|
||||
unzip\
|
||||
yarn\
|
||||
zlib1g:i386\
|
||||
supervisor\
|
||||
--no-install-recommends && \
|
||||
apt-get clean
|
||||
|
||||
ENV NPM_CONFIG_LOGLEVEL warn
|
||||
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 \
|
||||
&& ln -s /usr/local/bin/node /usr/local/bin/nodejs
|
||||
|
||||
# Download and untar SDK
|
||||
ENV ANDROID_HOME /usr/local/android-sdk-linux
|
||||
ENV ANDROID_SDK /usr/local/android-sdk-linux
|
||||
ENV ANDROID_SDK_URL https://dl.google.com/android/repository/sdk-tools-linux-4333796.zip
|
||||
RUN mkdir -p ${ANDROID_HOME} && \
|
||||
curl -L "${ANDROID_SDK_URL}" > ${ANDROID_HOME}/sdk.zip && \
|
||||
cd ${ANDROID_HOME} && \
|
||||
unzip -qq sdk.zip && \
|
||||
rm sdk.zip && \
|
||||
mkdir -p ${HOME}/.android && \
|
||||
touch ${HOME}/.android/repositories.cfg
|
||||
|
||||
ENV PATH ${ANDROID_HOME}/platform-tools:${PATH}
|
||||
ENV PATH ${ANDROID_HOME}/tools:${PATH}
|
||||
ENV PATH ${ANDROID_HOME}/tools/bin:${PATH}
|
||||
ENV PATH ${ANDROID_HOME}/build-tools/28.0.3/:${PATH}
|
||||
|
||||
ADD scripts/android/configureAndroidSdk.sh /tmp/configureAndroidSdk.sh
|
||||
RUN /tmp/configureAndroidSdk.sh --install-all-platforms
|
||||
|
||||
# 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
|
||||
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
|
||||
+13
-23
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "turtle-cli",
|
||||
"version": "0.8.0",
|
||||
"version": "0.12.4",
|
||||
"description": "The command-line tool for building standalone Expo apps",
|
||||
"preferGlobal": true,
|
||||
"scripts": {
|
||||
@@ -13,14 +13,10 @@
|
||||
"prepare": "rimraf ./build && yarn build",
|
||||
"build": "ttsc",
|
||||
"build:production": "./scripts/build.sh",
|
||||
"watch": "ttsc --watch",
|
||||
"secrets:init-private": "./scripts/initPrivateSecrets.sh",
|
||||
"set-workingdir:remote": "./scripts/setWorkingdirMode.sh remote",
|
||||
"set-workingdir:local": "./scripts/setWorkingdirMode.sh local",
|
||||
"docker:pull": "retry5 gcloud docker -- pull gcr.io/exponentjs/turtle-android:latest",
|
||||
"docker:pull:tag": "retry5 gcloud docker -- pull gcr.io/exponentjs/turtle-android:${TAG}",
|
||||
"docker:build": "yarn build:production android && gcloud docker -- build -t gcr.io/exponentjs/turtle-android:latest -t gcr.io/exponentjs/turtle-android:${TAG} .",
|
||||
"docker:push": "retry5 gcloud docker -- push gcr.io/exponentjs/turtle-android:${TAG} && retry5 gcloud docker -- push gcr.io/exponentjs/turtle-android:latest",
|
||||
"deploy:android": "./scripts/android/deploy.sh",
|
||||
"test": "yarn jest",
|
||||
"test:integration": "yarn test --config jest/integration-config.json",
|
||||
"test:unit": "yarn test --config jest/unit-config.json",
|
||||
@@ -29,18 +25,8 @@
|
||||
"test:smoke:ios": "PLATFORM=ios yarn test:smoke --testNamePattern=iOS",
|
||||
"release": "./scripts/release.sh",
|
||||
"release:beta": "./scripts/releaseBeta.sh",
|
||||
"ssh:android:pods-names": "./scripts/ssh/findAndroidPods.sh",
|
||||
"ssh:android:connect": "./scripts/ssh/connectToAndroidPod.sh",
|
||||
"ssh:ios:ips": "./scripts/ssh/findIosIps.sh",
|
||||
"set-priorities": "yarn set-priorities:local",
|
||||
"set-priorities:default": "expenv ts-node -r tsconfig-paths/register --files src/scripts/setConfigurations.ts",
|
||||
"set-priorities:local": "EXPENV_OVERRIDES=local-common,local,local-queue yarn set-priorities:default",
|
||||
"set-priorities:staging": "yarn set-priorities:default",
|
||||
"set-priorities:production": "EXPENV_OVERRIDES=prod yarn set-priorities:default",
|
||||
"set-replica-count:default": "expenv ts-node -r tsconfig-paths/register --files src/scripts/setReplicaCount.ts | bunyan -o short -l debug",
|
||||
"set-replica-count:local": "EXPENV_OVERRIDES=local-common,local,local-queue yarn set-replica-count:default",
|
||||
"set-replica-count:staging": "yarn set-replica-count:default",
|
||||
"set-replica-count:production": "EXPENV_OVERRIDES=prod yarn set-replica-count:default"
|
||||
"release:update:turtle-cli-example": "./scripts/updateTurtleCliExampleRepo.sh",
|
||||
"docker:build-and-push:android-base-image": "./scripts/android/buildAndPushAndroidBaseImage.sh"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
@@ -59,7 +45,7 @@
|
||||
"files": [
|
||||
"bin",
|
||||
"build",
|
||||
"scripts/cli",
|
||||
"scripts/android/configureAndroidSdk.sh",
|
||||
"shellTarballs"
|
||||
],
|
||||
"keywords": [
|
||||
@@ -79,11 +65,13 @@
|
||||
"registry": "https://registry.npmjs.org/"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@expo/babel-preset-cli": "^0.1.3",
|
||||
"@types/decompress": "^4.2.3",
|
||||
"@types/fs-extra": "^5.0.4",
|
||||
"@types/jest": "^23.3.9",
|
||||
"@types/joi": "^13.4.3",
|
||||
"@types/lodash": "^4.14.129",
|
||||
"@types/npm-package-arg": "^6.1.0",
|
||||
"@types/progress": "^2.0.1",
|
||||
"@types/raven": "^2.5.1",
|
||||
"@types/request": "^2.47.1",
|
||||
@@ -91,13 +79,15 @@
|
||||
"@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": "^23.6.0",
|
||||
"lint-staged": "^8.1.5",
|
||||
"nock": "^10.0.1",
|
||||
"nodemon": "^1.18.11",
|
||||
"release-it": "^10.0.0",
|
||||
"release-it": "^12.3.4",
|
||||
"rimraf": "^2.6.2",
|
||||
"ts-jest": "^23.10.4",
|
||||
"ts-node": "^8.0.3",
|
||||
@@ -110,7 +100,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@expo/spawn-async": "^1.4.2",
|
||||
"@expo/xdl": "54.1.4",
|
||||
"@expo/xdl": "56.2.2-alpha.2",
|
||||
"@google-cloud/logging-bunyan": "^0.9.5",
|
||||
"async-retry": "^1.2.1",
|
||||
"aws-sdk": "^2.226.1",
|
||||
@@ -131,13 +121,13 @@
|
||||
"request": "^2.88.0",
|
||||
"request-progress": "^3.0.0",
|
||||
"semver": "^6.0.0",
|
||||
"sharp": "^0.21.0",
|
||||
"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.9.4"
|
||||
"@expo/traveling-fastlane-darwin": "1.9.9"
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/../.. && pwd )"
|
||||
|
||||
IMAGE_TAG="$1"
|
||||
if [[ -z "$IMAGE_TAG" ]]; then
|
||||
echo "usage: yarn docker:build:android-base-image IMAGE_SEMVER"
|
||||
exit 1
|
||||
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 $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"
|
||||
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"
|
||||
popd > /dev/null
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
SDKMANAGER=$ANDROID_HOME/tools/bin/sdkmanager
|
||||
|
||||
yes | $SDKMANAGER --licenses > /dev/null
|
||||
if [[ "$1" = "--install-all-platforms" ]]; then
|
||||
yes | $SDKMANAGER \
|
||||
"platforms;android-23" \
|
||||
"platforms;android-24" \
|
||||
"platforms;android-25" \
|
||||
"platforms;android-26" \
|
||||
"platforms;android-27" | grep -v '='; [[ ${PIPESTATUS[1]} = 0 ]]
|
||||
fi
|
||||
yes | $SDKMANAGER "platforms;android-28" | grep -v '='; [[ ${PIPESTATUS[1]} = 0 ]]
|
||||
yes | $SDKMANAGER "platform-tools" | grep -v '='; [[ ${PIPESTATUS[1]} = 0 ]]
|
||||
yes | $SDKMANAGER "build-tools;28.0.3" | grep -v '='; [[ ${PIPESTATUS[1]} = 0 ]]
|
||||
yes | $SDKMANAGER \
|
||||
"extras;android;m2repository" \
|
||||
"extras;google;m2repository" \
|
||||
"extras;google;google_play_services" | grep -v '='; [[ ${PIPESTATUS[1]} = 0 ]]
|
||||
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
printf "READY\n"; # signal to superivsord that listener is ready
|
||||
|
||||
while read line; do
|
||||
echo "[supervisord:eventlistener] Processing Event: $line" >&2;
|
||||
kill -SIGQUIT $PPID
|
||||
done < /dev/stdin
|
||||
@@ -1,12 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
SDKMANAGER=$ANDROID_HOME/tools/bin/sdkmanager
|
||||
|
||||
yes | $SDKMANAGER --licenses > /dev/null
|
||||
yes | $SDKMANAGER "platforms;android-28"
|
||||
yes | $SDKMANAGER "platform-tools"
|
||||
yes | $SDKMANAGER "build-tools;28.0.3"
|
||||
yes | $SDKMANAGER \
|
||||
"extras;android;m2repository" \
|
||||
"extras;google;m2repository" \
|
||||
"extras;google;google_play_services"
|
||||
Executable
+76
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
SCRIPT_NAME=`basename "$0"`
|
||||
DEPLOY_ENDPOINT_URL="https://circleci.com/api/v1.1/project/github/expo/turtle-deploy/tree/master"
|
||||
|
||||
if [[ -z "$1" || -z "$2" ]]; then
|
||||
echo "usage: ${bold}$SCRIPT_NAME PLATFORM ENVIRONMENT [FORCE]${normal}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PLATFORM="$1"
|
||||
ENVIRONMENT="$2"
|
||||
|
||||
if [[ "$3" = "--force" ]]; then
|
||||
FORCE_DEPLOY="true"
|
||||
fi
|
||||
|
||||
if [[ "$PLATFORM" != "android" && "$PLATFORM" != "ios" ]]; then
|
||||
echo "unsupported PLATFORM passed: ${bold}$PLATFORM${normal}"
|
||||
echo "valid values are: ${bold}android${normal}, ${bold}ios${normal}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$ENVIRONMENT" != "staging" && "$ENVIRONMENT" != "production" ]]; then
|
||||
echo "unsupported ENVIRONMENT passed: ${bold}$ENVIRONMENT${normal}"
|
||||
echo "valid values are: ${bold}staging${normal}, ${bold}production${normal}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -z "$CIRCLE_SHA1" ]]; then
|
||||
TURTLE_COMMIT="$CIRCLE_SHA1"
|
||||
elif [[ -z "$FORCE_DEPLOY" ]]; then
|
||||
read -p "You're about to schedule a deploy, are you sure you want to deploy the current commit? (y/n) " -n 1 -r
|
||||
echo # (optional) move to a new line
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "exiting..."
|
||||
exit 0
|
||||
else
|
||||
TURTLE_COMMIT=`git log --pretty=format:%H -1`
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -z "$TURTLE_BOT_CIRCLE_API_USER_TOKEN" ]]; then
|
||||
echo "Please set the TURTLE_BOT_CIRCLE_API_USER_TOKEN env variable."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $FORCE_DEPLOY = "true" ]]; then
|
||||
curl -X POST \
|
||||
--header "Content-Type: application/json" \
|
||||
-u $TURTLE_BOT_CIRCLE_API_USER_TOKEN: \
|
||||
-d '
|
||||
{
|
||||
"build_parameters": {
|
||||
"CIRCLE_JOB": "deploy_'$PLATFORM'",
|
||||
"TURTLE_ENV": "'$ENVIRONMENT'",
|
||||
"TURTLE_FORCE_DEPLOY": "true"
|
||||
}
|
||||
}' \
|
||||
$DEPLOY_ENDPOINT_URL | jq -r .build_url
|
||||
else
|
||||
curl -X POST \
|
||||
--header "Content-Type: application/json" \
|
||||
-u $TURTLE_BOT_CIRCLE_API_USER_TOKEN: \
|
||||
-d '
|
||||
{
|
||||
"build_parameters": {
|
||||
"CIRCLE_JOB": "deploy_'$PLATFORM'",
|
||||
"TURTLE_ENV": "'$ENVIRONMENT'",
|
||||
"TURTLE_COMMIT": "'$TURTLE_COMMIT'"
|
||||
}
|
||||
}' \
|
||||
$DEPLOY_ENDPOINT_URL | jq -r .build_url
|
||||
fi
|
||||
@@ -13,13 +13,17 @@ fi
|
||||
TURTLE_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/.. && pwd )"
|
||||
TERRAFORM_DIR="${EXPO_UNIVERSE_DIR}/terraform"
|
||||
|
||||
ANDROID=`cd $TERRAFORM_DIR; terraform state show module.turtle_queues_local_$1.aws_sqs_queue.jobs_android_in | head -1 | cut -d"=" -f2 | xargs`
|
||||
IOS=`cd $TERRAFORM_DIR; terraform state show module.turtle_queues_local_$1.aws_sqs_queue.jobs_ios_in | head -1 | cut -d"=" -f2 | xargs`
|
||||
ANDROID_NORMAL=`cd $TERRAFORM_DIR; terraform state show module.turtle_queues_local_$1.aws_sqs_queue.jobs_android_in | head -1 | cut -d"=" -f2 | xargs`
|
||||
ANDROID_PRIORITY=`cd $TERRAFORM_DIR; terraform state show module.turtle_queues_local_$1.aws_sqs_queue.jobs_android_in_priority | head -1 | cut -d"=" -f2 | xargs`
|
||||
IOS_NORMAL=`cd $TERRAFORM_DIR; terraform state show module.turtle_queues_local_$1.aws_sqs_queue.jobs_ios_in | head -1 | cut -d"=" -f2 | xargs`
|
||||
IOS_PRIORITY=`cd $TERRAFORM_DIR; terraform state show module.turtle_queues_local_$1.aws_sqs_queue.jobs_ios_in_priority | head -1 | cut -d"=" -f2 | xargs`
|
||||
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"
|
||||
AWS_SQS_IOS_QUEUE_URL="$IOS"
|
||||
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
|
||||
|
||||
@@ -4,6 +4,14 @@ set -eo pipefail
|
||||
|
||||
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/.. && pwd )"
|
||||
|
||||
if [[ -z "$GITHUB_TOKEN" || -z "$CIRCLE_API_USER_TOKEN" ]]; then
|
||||
yellow=`tput setaf 3`
|
||||
reset=`tput sgr0`
|
||||
echo "${yellow}please set GITHUB_TOKEN and CIRCLE_API_USER_TOKEN env variables in .envrc.local file if you wish to release turtle-cli"
|
||||
echo "run 'cp .envrc.local.example .envrc.local' if you don't have one yet and edit the new file${reset}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
$ROOT_DIR/node_modules/.bin/release-it
|
||||
echo
|
||||
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
||||
|
||||
@@ -6,42 +6,44 @@ 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 .secrets.local-queue file yourself with AWS_SQS_ANDROID_QUEUE_URL, AWS_SQS_IOS_QUEUE_URL and AWS_SQS_OUT_QUEUE_URL variables."
|
||||
if [ ! -f "$ROOT_DIR/.secrets.local-queue" ]; then
|
||||
echo "You need to run \"yarn secrets:init-private [SQS_NAME]\" or create 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
|
||||
|
||||
setup_local() {
|
||||
ensure_link_exists() {
|
||||
if [ ! -L "$2" ]; then
|
||||
ln -s $1 $2
|
||||
echo "$2 link created"
|
||||
fi
|
||||
}
|
||||
WORKINGDIR="$ROOT_DIR/workingdir/local"
|
||||
|
||||
if [[ -d $WORKINGDIR ]]; then
|
||||
echo "Local workingdir already prepared"
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ -z "$EXPO_UNIVERSE_DIR" ]]; then
|
||||
echo "EXPO_UNIVERSE_DIR needs to be set"
|
||||
exit -1
|
||||
fi
|
||||
|
||||
cd $EXPO_UNIVERSE_DIR/exponent && yarn
|
||||
cd $EXPO_UNIVERSE_DIR/exponent/tools-public && yarn && ./generate-dynamic-macros-android.sh
|
||||
|
||||
mkdir -p $WORKINGDIR
|
||||
echo "$WORKINGDIR directory created"
|
||||
|
||||
LINKS=("template-files" "package.json" "android" "expokit-npm-package" "packages" "client-builds" "cpp" "exponent-view-template" "ios" "shellAppBase-builds" "shellAppWorkspaces" "node_modules")
|
||||
|
||||
for LINKNAME in ${LINKS[@]}; do
|
||||
ensure_link_exists "$EXPO_UNIVERSE_DIR/exponent/$LINKNAME" "$WORKINGDIR/$LINKNAME"
|
||||
done
|
||||
}
|
||||
# @dsokal: this is currently broken
|
||||
#
|
||||
# setup_local() {
|
||||
# ensure_link_exists() {
|
||||
# if [ ! -L "$2" ]; then
|
||||
# ln -s $1 $2
|
||||
# echo "$2 link created"
|
||||
# fi
|
||||
# }
|
||||
# WORKINGDIR="$ROOT_DIR/workingdir/local"
|
||||
#
|
||||
# if [[ -d $WORKINGDIR ]]; then
|
||||
# echo "Local workingdir already prepared"
|
||||
# return
|
||||
# fi
|
||||
#
|
||||
# if [[ -z "$EXPO_UNIVERSE_DIR" ]]; then
|
||||
# echo "EXPO_UNIVERSE_DIR needs to be set"
|
||||
# exit -1
|
||||
# fi
|
||||
#
|
||||
# cd $EXPO_UNIVERSE_DIR/exponent && yarn
|
||||
# cd $EXPO_UNIVERSE_DIR/exponent/tools-public && yarn && ./generate-dynamic-macros-android.sh
|
||||
#
|
||||
# mkdir -p $WORKINGDIR
|
||||
# echo "$WORKINGDIR directory created"
|
||||
#
|
||||
# LINKS=("template-files" "package.json" "android" "expokit-npm-package" "packages" "client-builds" "cpp" "exponent-view-template" "ios" "shellAppBase-builds" "shellAppWorkspaces" "node_modules")
|
||||
#
|
||||
# for LINKNAME in ${LINKS[@]}; do
|
||||
# ensure_link_exists "$EXPO_UNIVERSE_DIR/exponent/$LINKNAME" "$WORKINGDIR/$LINKNAME"
|
||||
# done
|
||||
# }
|
||||
|
||||
setup_remote() {
|
||||
if [[ -d $ROOT_DIR/workingdir/android && -d $ROOT_DIR/workingdir/ios ]]; then
|
||||
@@ -55,7 +57,7 @@ setup_remote() {
|
||||
$ROOT_DIR/scripts/ios/fetchRemoteIosTarball.sh
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
for sdk in $ROOT_DIR/workingdir/android/* ; do
|
||||
if [[ -f "$sdk/universe-package.json" ]]; then
|
||||
mv $sdk/package.json $sdk/exponent-package.json
|
||||
@@ -87,8 +89,10 @@ EOF
|
||||
}
|
||||
|
||||
if [ "$1" == "local" ]; then
|
||||
setup_local
|
||||
switch_local
|
||||
# setup_local
|
||||
# switch_local
|
||||
echo "Setting local workingdir is currently broken, sorry :("
|
||||
exit -1
|
||||
elif [ "$1" == "remote" ]; then
|
||||
setup_remote
|
||||
switch_remote
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "Please provide an environment name as a first argument"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$2" ]; then
|
||||
echo "Please provide a pod name as a second argument"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
kubectl --namespace $1 exec -it $2 -- /bin/bash
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
ENVIRONMENT=${1:-production}
|
||||
|
||||
kubectl get pods --namespace $ENVIRONMENT | grep "turtle-android-" | sed -e "s/ */ /g" | cut -d" " -f1
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
ENVIRONMENT=${1:-production}
|
||||
|
||||
govc vm.ip -wait 5s turtle-js-"${ENVIRONMENT}"-*
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
DEPLOY_ENDPOINT_URL="https://circleci.com/api/v1.1/project/github/expo/turtle-cli-example/tree/updates-do-not-remove-me"
|
||||
|
||||
curl -X POST \
|
||||
--header "Content-Type: application/json" \
|
||||
-u $CIRCLE_API_USER_TOKEN: \
|
||||
-d '
|
||||
{
|
||||
"build_parameters": {
|
||||
"CIRCLE_JOB": "update",
|
||||
"TURTLE_TAG": "latest"
|
||||
}
|
||||
}' \
|
||||
$DEPLOY_ENDPOINT_URL 2>/dev/null | jq -r .build_url
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/android-shell-builder-c19ce0d88a153f481fd790e23bdcd6f2d5ea7fd6.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/android-shell-builder-c19ce0d88a153f481fd790e23bdcd6f2d5ea7fd6.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/android-shell-builder-c19ce0d88a153f481fd790e23bdcd6f2d5ea7fd6.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/android-shell-builder-c19ce0d88a153f481fd790e23bdcd6f2d5ea7fd6.tar.gz
|
||||
@@ -1 +1 @@
|
||||
s3://exp-artifacts/android-shell-builder-86974c7df1fc9db46f02b59f4a663b45e2f7a2af.tar.gz
|
||||
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-426a9f7f926d97174ba2ac4c3cb9c0fc8767ba42.tar.gz
|
||||
@@ -1 +1 @@
|
||||
s3://exp-artifacts/ios-expo-client-a2b1e16f330b36fa0dc627a76caabe4d2ff45f77.tar.gz
|
||||
s3://exp-artifacts/ios-expo-client-d31aaf53daca6aa65d8cb1090fb60c73a9c47075.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-27-db356a09877642d64023af98e4e2e1e632fbe4df.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-28-db356a09877642d64023af98e4e2e1e632fbe4df.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-29-db356a09877642d64023af98e4e2e1e632fbe4df.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-30-6863276e6b9605e31228c845a047387571959e9b.tar.gz
|
||||
@@ -1 +1 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-e1a8bd0ab2e1eba546792c0ffc282b5b202ccc39.tar.gz
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-55848298c7332f7586c4281fa691a4ca31548532.tar.gz
|
||||
@@ -1 +1 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-dc981c7110b7d508de8e9c352064dc3d745c9f72.tar.gz
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-edd02214dd84368c197df32a2d30a901d6c766ff.tar.gz
|
||||
@@ -1 +1 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-a2b1e16f330b36fa0dc627a76caabe4d2ff45f77.tar.gz
|
||||
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,6 +1,5 @@
|
||||
import fs from 'fs-extra';
|
||||
import _ from 'lodash';
|
||||
import uuid from 'uuid';
|
||||
|
||||
import { ErrorWithCommandHelp } from 'turtle/bin/commands/ErrorWithCommandHelp';
|
||||
import { createBuilderAction } from 'turtle/bin/utils/builder';
|
||||
@@ -24,16 +23,21 @@ export default (program: any, setCommonCommandOptions: any) => {
|
||||
/^(app-bundle|apk)$/i,
|
||||
'app-bundle',
|
||||
)
|
||||
.option(
|
||||
'-m --mode <build>',
|
||||
'type of build: debug|release',
|
||||
/^(debug|release)$/i,
|
||||
'release',
|
||||
)
|
||||
.description(
|
||||
'Build a standalone APK or App Bundle for your project, signed and ready for submission to the Google Play'
|
||||
+ ' Store.',
|
||||
'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.',
|
||||
)
|
||||
.asyncAction(
|
||||
createBuilderAction({
|
||||
program,
|
||||
command,
|
||||
prepareCredentials,
|
||||
buildJobObject,
|
||||
builder,
|
||||
platform: PLATFORMS.ANDROID,
|
||||
os: ['darwin', 'linux'],
|
||||
@@ -41,26 +45,6 @@ export default (program: any, setCommonCommandOptions: any) => {
|
||||
);
|
||||
};
|
||||
|
||||
const buildJobObject = (
|
||||
appJSON: any,
|
||||
{ releaseChannel, username, projectDir, publicUrl, buildType }: any,
|
||||
credentials: any,
|
||||
) => ({
|
||||
config: {
|
||||
..._.get(appJSON, 'expo.android.config', {}),
|
||||
releaseChannel,
|
||||
androidPackage: _.get(appJSON, 'expo.android.package'),
|
||||
publicUrl,
|
||||
buildType,
|
||||
},
|
||||
id: uuid.v4(),
|
||||
platform: PLATFORMS.ANDROID,
|
||||
sdkVersion: _.get(appJSON, 'expo.sdkVersion'),
|
||||
projectDir,
|
||||
experienceName: `@${username}/${_.get(appJSON, 'expo.slug')}`,
|
||||
...(credentials && { credentials }),
|
||||
});
|
||||
|
||||
const prepareCredentials = async (cmd: any) => {
|
||||
const { keystorePath, keystoreAlias } = cmd;
|
||||
const keystorePassword = process.env.EXPO_ANDROID_KEYSTORE_PASSWORD;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import fs from 'fs-extra';
|
||||
import _ from 'lodash';
|
||||
import uuid from 'uuid';
|
||||
|
||||
import { ErrorWithCommandHelp } from 'turtle/bin/commands/ErrorWithCommandHelp';
|
||||
import { createBuilderAction } from 'turtle/bin/utils/builder';
|
||||
@@ -32,7 +31,6 @@ export default (program: any, setCommonCommandOptions: any) => {
|
||||
program,
|
||||
command,
|
||||
prepareCredentials,
|
||||
buildJobObject,
|
||||
builder,
|
||||
platform: PLATFORMS.IOS,
|
||||
os: 'darwin',
|
||||
@@ -40,21 +38,6 @@ export default (program: any, setCommonCommandOptions: any) => {
|
||||
);
|
||||
};
|
||||
|
||||
const buildJobObject = (appJSON: any, { releaseChannel, buildType, username, publicUrl }: any, credentials: any) => ({
|
||||
config: {
|
||||
..._.get(appJSON, 'expo.ios.config', {}),
|
||||
buildType,
|
||||
releaseChannel,
|
||||
bundleIdentifier: _.get(appJSON, 'expo.ios.bundleIdentifier'),
|
||||
publicUrl,
|
||||
},
|
||||
id: uuid.v4(),
|
||||
platform: PLATFORMS.IOS,
|
||||
sdkVersion: _.get(appJSON, 'expo.sdkVersion'),
|
||||
experienceName: `@${username}/${_.get(appJSON, 'expo.slug')}`,
|
||||
...(credentials && { credentials }),
|
||||
});
|
||||
|
||||
const prepareCredentials = async (cmd: any) => {
|
||||
if (cmd.type !== IOS_BUILD_TYPES.ARCHIVE) {
|
||||
return null;
|
||||
|
||||
@@ -20,10 +20,6 @@ const REQUIRED_TOOLS: IToolDefinition[] = [
|
||||
command: 'bash',
|
||||
missingDescription: 'Please install bash',
|
||||
},
|
||||
{
|
||||
command: 'gulp',
|
||||
missingDescription: 'Run `npm install -g gulp-cli` (or `yarn global add gulp-cli`) to install gulp',
|
||||
},
|
||||
{
|
||||
command: 'javac',
|
||||
missingDescription: 'Please install JDK (version 8 or newer) - check https://jdk.java.net/',
|
||||
@@ -67,7 +63,7 @@ function formatShellAppTarballUriPath(sdkMajorVersion: string) {
|
||||
return path.join(config.directories.shellTarballsDir, PLATFORMS.ANDROID, `sdk${sdkMajorVersion}`);
|
||||
}
|
||||
|
||||
async function _shellAppPostDownloadAction(workingdir: string) {
|
||||
async function _shellAppPostDownloadAction(sdkVersion: string, workingdir: string) {
|
||||
const inWorkingdir = (filename: string) => path.join(workingdir, filename);
|
||||
|
||||
if (await fs.pathExists(inWorkingdir('universe-package.json'))) {
|
||||
@@ -82,9 +78,11 @@ async function _shellAppPostDownloadAction(workingdir: string) {
|
||||
await _installNodeModules(workingdir);
|
||||
}
|
||||
|
||||
// TODO: remove following lines after upgrading android shell app
|
||||
const toolsPublicDir = path.join(workingdir, 'tools-public');
|
||||
await _installNodeModules(toolsPublicDir);
|
||||
// TODO: remove this after making sure that we don't need node_modules in tools-public for older sdks
|
||||
if (ExponentTools.parseSdkMajorVersion(sdkVersion) < 33) {
|
||||
const toolsPublicDir = path.join(workingdir, 'tools-public');
|
||||
await _installNodeModules(toolsPublicDir);
|
||||
}
|
||||
}
|
||||
|
||||
async function _installNodeModules(cwd: string) {
|
||||
|
||||
@@ -4,7 +4,7 @@ import path from 'path';
|
||||
import decompress from 'decompress';
|
||||
import fs from 'fs-extra';
|
||||
|
||||
import { formatArtifactDownloadPath } from 'turtle/bin/setup/utils/common';
|
||||
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';
|
||||
@@ -16,9 +16,10 @@ 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 = formatArtifactDownloadPath(ANDROID_NDK_URL);
|
||||
const androidNdkDownloadPath = utils.formatArtifactDownloadPath(ANDROID_NDK_URL);
|
||||
|
||||
try {
|
||||
l.info('Downloading Android NDK');
|
||||
@@ -26,6 +27,7 @@ export default async function ensureAndroidNDKIsPresent() {
|
||||
await download(ANDROID_NDK_URL, androidNdkDownloadPath);
|
||||
l.info('Decompressing Android NDK');
|
||||
await decompress(androidNdkDownloadPath, androidNdkDir, { strip: 1 });
|
||||
await utils.markDirectoryAsReady(androidNdkDir);
|
||||
l.info('Android NDK installed successfully');
|
||||
} catch (err) {
|
||||
await fs.remove(androidNdkDir);
|
||||
|
||||
@@ -5,7 +5,7 @@ import { ExponentTools } from '@expo/xdl';
|
||||
import decompress from 'decompress';
|
||||
import fs from 'fs-extra';
|
||||
|
||||
import { formatArtifactDownloadPath } from 'turtle/bin/setup/utils/common';
|
||||
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';
|
||||
@@ -17,9 +17,10 @@ const l = logger.child(LOGGER_FIELDS);
|
||||
|
||||
export default async function ensureAndroidSDKIsPresent() {
|
||||
const androidSdkDir = path.join(config.directories.androidDependenciesDir, 'sdk');
|
||||
await utils.removeDirectoryUnlessReady(androidSdkDir);
|
||||
if (!(await fs.pathExists(androidSdkDir))) {
|
||||
await fs.ensureDir(androidSdkDir);
|
||||
const androidSdkDownloadPath = formatArtifactDownloadPath(ANDROID_SDK_URL);
|
||||
const androidSdkDownloadPath = utils.formatArtifactDownloadPath(ANDROID_SDK_URL);
|
||||
|
||||
try {
|
||||
l.info('Downloading Android SDK');
|
||||
@@ -31,6 +32,7 @@ export default async function ensureAndroidSDKIsPresent() {
|
||||
await fs.remove(androidSdkDownloadPath);
|
||||
l.info('Configuring Android SDK, this may take a while');
|
||||
await _configureSdk(androidSdkDir);
|
||||
await utils.markDirectoryAsReady(androidSdkDir);
|
||||
l.info('Android SDK installed and configured successfully');
|
||||
} catch (err) {
|
||||
await fs.remove(androidSdkDir);
|
||||
@@ -52,7 +54,7 @@ async function _configureSdk(androidSdkDir: string) {
|
||||
await ExponentTools.spawnAsyncThrowError('./configureAndroidSdk.sh', [], {
|
||||
pipeToLogger: true,
|
||||
loggerFields: LOGGER_FIELDS,
|
||||
cwd: path.join(config.directories.rootDir, 'scripts/cli'),
|
||||
cwd: path.join(config.directories.rootDir, 'scripts/android'),
|
||||
env: {
|
||||
...process.env,
|
||||
ANDROID_HOME: androidSdkDir,
|
||||
|
||||
+26
-2
@@ -10,6 +10,7 @@ import { IToolDefinition } from 'turtle/bin/setup/utils/toolsDetector';
|
||||
import { formatShellAppDirectory } from 'turtle/builders/utils/ios/workingdir';
|
||||
import config from 'turtle/config';
|
||||
import { PLATFORMS } from 'turtle/constants';
|
||||
import logger from 'turtle/logger';
|
||||
|
||||
const REQUIRED_TOOLS: IToolDefinition[] = [
|
||||
{
|
||||
@@ -30,7 +31,7 @@ const REQUIRED_TOOLS: IToolDefinition[] = [
|
||||
const fastlaneVersion = parseFastlaneVersion(stdout);
|
||||
if (fastlaneVersion && !semver.satisfies(fastlaneVersion, `>= ${MINIMAL_VERSION}`)) {
|
||||
throw new Error(
|
||||
`Your fastlane on version ${fastlaneVersion}. Please upgrade it to at least ${MINIMAL_VERSION}.`,
|
||||
`Your fastlane is on version ${fastlaneVersion}. Please upgrade it to at least ${MINIMAL_VERSION}.`,
|
||||
);
|
||||
}
|
||||
},
|
||||
@@ -47,7 +48,30 @@ const REQUIRED_TOOLS: IToolDefinition[] = [
|
||||
if (stdout.match(/requires xcode/i)) {
|
||||
return false;
|
||||
}
|
||||
return status === 0;
|
||||
|
||||
if (status !== 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
await ExponentTools.spawnAsyncThrowError('ibtool', ['--version'], { stdio: 'pipe' });
|
||||
} catch (err) {
|
||||
if (err.stderr) {
|
||||
const stderr = err.stderr.trim();
|
||||
if (stderr.match(/Agreeing to the Xcode\/iOS license/)) {
|
||||
logger.error('You have not accepted the Xcode license. Run \'sudo xcodebuild -runFirstLaunch\' to do so.');
|
||||
return false;
|
||||
}
|
||||
if (stderr.match(/The bundle is damaged or missing necessary resources/)) {
|
||||
logger.error(
|
||||
'Make sure to install additional required components. Run \'sudo xcodebuild -runFirstLaunch\' to do so.',
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@@ -17,7 +17,7 @@ interface IShellAppFormaters {
|
||||
formatShellAppTarballUriPath: (sdkMajorVersion: string) => string;
|
||||
}
|
||||
|
||||
type PostDownloadAction = (workingdir: string) => void;
|
||||
type PostDownloadAction = (sdkVersion: string, workingdir: string) => void;
|
||||
|
||||
export async function checkSystem(requiredTools: IToolDefinition[]) {
|
||||
await ensureToolsAreInstalled(requiredTools);
|
||||
@@ -29,14 +29,17 @@ export async function ensureShellAppIsPresent(
|
||||
postDownloadAction?: PostDownloadAction,
|
||||
) {
|
||||
const workingdir = formatters.formatShellAppDirectory({ sdkVersion });
|
||||
const shellAppMetadata = await _readShellAppTarballS3Uri(sdkVersion, formatters);
|
||||
await removeDirectoryUnlessReady(workingdir, shellAppMetadata);
|
||||
if (await fs.pathExists(workingdir)) {
|
||||
return;
|
||||
}
|
||||
l.info(`shell app for SDK ${sdkVersion} doesn't exist, downloading...`);
|
||||
await _downloadShellApp(sdkVersion, workingdir, formatters);
|
||||
if (postDownloadAction) {
|
||||
await postDownloadAction(workingdir);
|
||||
await postDownloadAction(sdkVersion, workingdir);
|
||||
}
|
||||
await markDirectoryAsReady(workingdir, shellAppMetadata);
|
||||
}
|
||||
|
||||
async function _downloadShellApp(sdkVersion: string, targetDirectory: string, formatters: IShellAppFormaters) {
|
||||
@@ -65,3 +68,31 @@ async function _readShellAppTarballS3Uri(sdkVersion: string, formatters: IShellA
|
||||
const data = await fs.readFile(filePath, 'utf8');
|
||||
return data.trim();
|
||||
}
|
||||
|
||||
export async function removeDirectoryUnlessReady(dir: string, metadata?: string) {
|
||||
const readyFilePath = path.join(dir, '.ready');
|
||||
const readyFileExists = await fs.pathExists(readyFilePath);
|
||||
let shouldRemove = false;
|
||||
if (readyFileExists) {
|
||||
if (metadata !== undefined) {
|
||||
const readyFileContents = (await fs.readFile(readyFilePath, 'utf-8')).trim();
|
||||
if (readyFileContents !== metadata) {
|
||||
shouldRemove = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
shouldRemove = true;
|
||||
}
|
||||
if (shouldRemove) {
|
||||
await fs.remove(dir);
|
||||
}
|
||||
}
|
||||
|
||||
export async function markDirectoryAsReady(dir: string, metadata?: string) {
|
||||
const readyFilePath = path.join(dir, '.ready');
|
||||
if (metadata === undefined) {
|
||||
await fs.open(readyFilePath, 'w');
|
||||
} else {
|
||||
await fs.writeFile(readyFilePath, metadata);
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ export async function ensureToolsAreInstalled(tools: IToolDefinition[]) {
|
||||
try {
|
||||
if (testFn) {
|
||||
if (!await testFn()) {
|
||||
throw new Error('Required tool doesn\'t exist');
|
||||
throw new Error('Required tool is not properly installed');
|
||||
}
|
||||
} else {
|
||||
await which(command);
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
import { ExponentTools } from '@expo/xdl';
|
||||
import _ from 'lodash';
|
||||
import uuid from 'uuid';
|
||||
|
||||
import { ErrorWithCommandHelp } from 'turtle/bin/commands/ErrorWithCommandHelp';
|
||||
import { ErrorWithProgramHelp } from 'turtle/bin/commands/ErrorWithProgramHelp';
|
||||
import setup from 'turtle/bin/setup/setup';
|
||||
import * as ProjectUtils from 'turtle/bin/utils/project';
|
||||
import * as UserUtils from 'turtle/bin/utils/user';
|
||||
import { getExperienceUrl } from 'turtle/builders/utils/common';
|
||||
import logger from 'turtle/logger';
|
||||
import { sanitizeJob } from 'turtle/validator';
|
||||
|
||||
@@ -12,7 +15,6 @@ export function createBuilderAction({
|
||||
program,
|
||||
command,
|
||||
prepareCredentials,
|
||||
buildJobObject,
|
||||
builder,
|
||||
platform,
|
||||
os,
|
||||
@@ -55,6 +57,7 @@ export function createBuilderAction({
|
||||
const args = {
|
||||
releaseChannel: cmd.releaseChannel || 'default',
|
||||
buildType: cmd.type,
|
||||
buildMode: cmd.mode,
|
||||
username: userData.username || 'anonymous',
|
||||
projectDir: ProjectUtils.resolveAbsoluteDir(projectDirArg),
|
||||
publicUrl: cmd.publicUrl,
|
||||
@@ -65,7 +68,7 @@ export function createBuilderAction({
|
||||
await setup(platform, sdkVersion);
|
||||
const credentials = await prepareCredentials(cmd);
|
||||
const rawJob = {
|
||||
...buildJobObject(appJSON, args, credentials),
|
||||
...await buildJobObject(platform, appJSON, args, credentials),
|
||||
...cmd.buildDir && { fakeUploadDir: ProjectUtils.resolveAbsoluteDir(cmd.buildDir) },
|
||||
...cmd.output && { fakeUploadBuildPath: ProjectUtils.resolveAbsoluteDir(cmd.output) },
|
||||
};
|
||||
@@ -82,3 +85,38 @@ export function createBuilderAction({
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const buildJobObject = async (
|
||||
platform: 'android' | 'ios',
|
||||
appJSON: any,
|
||||
{ releaseChannel, buildType, buildMode, username, publicUrl, projectDir }: any,
|
||||
credentials: any,
|
||||
) => {
|
||||
const job = {
|
||||
config: {
|
||||
..._.get(appJSON, `expo.${platform}.config`, {}),
|
||||
buildType,
|
||||
...(platform === 'android' ? { buildMode } : {}),
|
||||
releaseChannel,
|
||||
...(platform === 'ios' ? { bundleIdentifier: _.get(appJSON, 'expo.ios.bundleIdentifier') } : {}),
|
||||
...(platform === 'android' ? { androidPackage: _.get(appJSON, 'expo.android.package') } : {}),
|
||||
publicUrl,
|
||||
},
|
||||
id: uuid.v4(),
|
||||
platform,
|
||||
projectDir,
|
||||
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': _.get(appJSON, 'expo.sdkVersion'),
|
||||
'Exponent-Platform': platform,
|
||||
'Expo-Release-Channel': releaseChannel,
|
||||
'Accept': 'application/expo+json,application/json',
|
||||
});
|
||||
|
||||
return { ...job, manifest };
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import { User as UserManager } from '@expo/xdl';
|
||||
import { UserManager } from '@expo/xdl';
|
||||
|
||||
import { ErrorWithProgramHelp } from 'turtle/bin/commands/ErrorWithProgramHelp';
|
||||
|
||||
|
||||
@@ -11,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 { 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';
|
||||
@@ -73,14 +73,19 @@ async function runShellAppBuilder(
|
||||
const sdkVersion = _.get(manifest, 'sdkVersion', sdkVersionFromJob);
|
||||
const workingDir = formatShellAppDirectory({ sdkVersion });
|
||||
|
||||
// (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.
|
||||
//
|
||||
// to enable full resolver switch resolveExplicitOptIn to resolveNativeModules
|
||||
logger.info({ buildPhase: 'resolve native modules' }, 'Resolving universal modules dependencies');
|
||||
const enabledModules = semver.satisfies(sdkVersion, '>= 33.0.0')
|
||||
? await resolveNativeModules(workingDir, manifest.dependencies)
|
||||
? await resolveExplicitOptIn(workingDir, _.get(manifest, 'dependencies'))
|
||||
: null;
|
||||
|
||||
try {
|
||||
await AndroidShellApp.createAndroidShellAppAsync({
|
||||
url: commonUtils.getExperienceUrl(jobData),
|
||||
url: commonUtils.getExperienceUrl(jobData.experienceName, jobData.config.publicUrl),
|
||||
sdkVersion,
|
||||
keystore: tempKeystorePath,
|
||||
manifest,
|
||||
@@ -93,6 +98,7 @@ async function runShellAppBuilder(
|
||||
outputFile: outputFilePath,
|
||||
modules: enabledModules,
|
||||
buildType: jobData.config.buildType,
|
||||
buildMode: jobData.config.buildMode,
|
||||
});
|
||||
} catch (err) {
|
||||
commonUtils.logErrorOnce(err);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as path from 'path';
|
||||
|
||||
import { IosShellApp } from '@expo/xdl';
|
||||
import { ExponentTools, IosShellApp } from '@expo/xdl';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import { formatShellAppDirectory } from 'turtle/builders/utils/ios/workingdir';
|
||||
@@ -41,6 +41,7 @@ export function createBuilderContext(job: IJob): IContext {
|
||||
|
||||
const sdkVersion = sdkVersionFromJob || sdkVersionFromManifest;
|
||||
const workingDir = formatShellAppDirectory({ sdkVersion, buildType: buildType! });
|
||||
const majorSdkVersion = ExponentTools.parseSdkMajorVersion(sdkVersion);
|
||||
|
||||
const context: any = {
|
||||
appDir: join(config.directories.temporaryFilesRoot, appUUID),
|
||||
@@ -84,13 +85,24 @@ export function createBuilderContext(job: IJob): IContext {
|
||||
'Applications',
|
||||
`${EXPOKIT_APP}.app`,
|
||||
);
|
||||
context.workspacePath = path.join(
|
||||
workingDir,
|
||||
'shellAppWorkspaces',
|
||||
'ios',
|
||||
'default',
|
||||
`${EXPOKIT_APP}.xcworkspace`,
|
||||
);
|
||||
if (majorSdkVersion >= 33) {
|
||||
context.workspacePath = path.join(
|
||||
workingDir,
|
||||
'shellAppWorkspaces',
|
||||
'default',
|
||||
'ios',
|
||||
`${EXPOKIT_APP}.xcworkspace`,
|
||||
);
|
||||
} else {
|
||||
context.workspacePath = path.join(
|
||||
workingDir,
|
||||
'shellAppWorkspaces',
|
||||
'ios',
|
||||
'default',
|
||||
`${EXPOKIT_APP}.xcworkspace`,
|
||||
);
|
||||
}
|
||||
|
||||
} else if (buildType === IOS_BUILD_TYPES.CLIENT) {
|
||||
context.outputPath = join(context.appDir, 'archive.xcarchive');
|
||||
context.uploadPath = join(context.buildDir, 'archive.ipa');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import path from 'path';
|
||||
|
||||
import { Credentials } from '@expo/xdl';
|
||||
import { AndroidCredentials } from '@expo/xdl';
|
||||
import fs from 'fs-extra';
|
||||
import get from 'lodash/get';
|
||||
import uuidv4 from 'uuid/v4';
|
||||
@@ -29,7 +29,7 @@ async function getOrCreateCredentials(jobData: IJob): Promise<IAndroidCredential
|
||||
);
|
||||
}
|
||||
|
||||
await Credentials.Android.createKeystore(
|
||||
await AndroidCredentials.createKeystore(
|
||||
{
|
||||
keystorePath: keystoreFilename,
|
||||
keystorePassword: credentials.keystorePassword,
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
import * as url from 'url';
|
||||
|
||||
import config from 'turtle/config';
|
||||
import { IJob } from 'turtle/job';
|
||||
import logger from 'turtle/logger';
|
||||
|
||||
export function getExperienceUrl(job: IJob) {
|
||||
const { experienceName, config: jobConfig } = job;
|
||||
const { publicUrl } = jobConfig;
|
||||
|
||||
export function getExperienceUrl(experienceName: string, publicUrl?: string) {
|
||||
// publicUrl is passed in if user wants to build an externally hosted app
|
||||
if (publicUrl) {
|
||||
return publicUrl;
|
||||
|
||||
@@ -3,7 +3,6 @@ import path from 'path';
|
||||
import spawnAsync from '@expo/spawn-async';
|
||||
import { IosCodeSigning } from '@expo/xdl';
|
||||
import fs from 'fs-extra';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
|
||||
import * as sqs from 'turtle/aws/sqs';
|
||||
import BuildError, { BuildErrorReason } from 'turtle/builders/BuildError';
|
||||
@@ -21,10 +20,18 @@ async function prepareAdHocBuildCredentials(job: IJob) {
|
||||
}
|
||||
|
||||
const { bundleIdentifier } = job.config;
|
||||
const { certP12, certPassword, teamId, appleSession, udids } = job.credentials;
|
||||
const {
|
||||
certP12,
|
||||
certPassword,
|
||||
teamId,
|
||||
appleSession,
|
||||
udids,
|
||||
provisioningProfileId,
|
||||
} = job.credentials;
|
||||
|
||||
const certSerialNumber = IosCodeSigning.findP12CertSerialNumber(certP12, certPassword);
|
||||
const args = [
|
||||
...(provisioningProfileId ? ['--profile-id', provisioningProfileId] : []),
|
||||
teamId,
|
||||
udids!.join(','),
|
||||
bundleIdentifier,
|
||||
@@ -32,25 +39,26 @@ async function prepareAdHocBuildCredentials(job: IJob) {
|
||||
];
|
||||
|
||||
try {
|
||||
if (provisioningProfileId) {
|
||||
logger.info(
|
||||
`Using ad hoc provisioning profile id: ${provisioningProfileId}`,
|
||||
);
|
||||
}
|
||||
|
||||
const credentials = await runFastlaneAction(
|
||||
travelingFastlane.manageAdHocProvisioningProfile,
|
||||
args,
|
||||
{ env: { FASTLANE_SESSION: appleSession } },
|
||||
);
|
||||
if (isEmpty(credentials)) {
|
||||
if (!job.credentials.provisioningProfile) {
|
||||
// a user has generated the provisioning profile for his app, but he probably deleted it from Expo servers, ...
|
||||
throw new BuildError(
|
||||
BuildErrorReason.PROVISIONING_PROFILE_MISSING,
|
||||
`Provisioning profile is missing on Expo servers.`,
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info('New ad hoc provisioning profile successfully created');
|
||||
job.credentials.provisioningProfile = credentials.provisioningProfile;
|
||||
|
||||
if (!credentials.provisioningProfileUpdateTimestamp) {
|
||||
// dont need to persist profile because nothing changed
|
||||
return;
|
||||
}
|
||||
|
||||
if (isOffline()) {
|
||||
const provisioningProfilePath = path.join(job.projectDir, `adhoc.mobileprovision`);
|
||||
await fs.writeFile(provisioningProfilePath, Buffer.from(credentials.provisioningProfile, 'base64'));
|
||||
|
||||
@@ -43,7 +43,7 @@ export default async function runShellAppBuilder(ctx: IContext, job: IJob): Prom
|
||||
});
|
||||
} else {
|
||||
Object.assign(shellAppParams, {
|
||||
url: commonUtils.getExperienceUrl(job),
|
||||
url: commonUtils.getExperienceUrl(job.experienceName, job.config.publicUrl),
|
||||
releaseChannel,
|
||||
sdkVersion,
|
||||
});
|
||||
|
||||
@@ -19,6 +19,20 @@ interface IPackageInfo {
|
||||
dependencies: string[];
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
modules.forEach(({ name, version }) => { logger.info(`Adding ${name}:${version}`); });
|
||||
return modules;
|
||||
}
|
||||
|
||||
export async function resolveNativeModules(workingdir: string, packages?: string[]): Promise<IUnimoduleEntry[]> {
|
||||
const resolver = new Resolver(workingdir);
|
||||
await resolver.init();
|
||||
@@ -38,15 +52,18 @@ export async function resolveNativeModules(workingdir: string, packages?: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resolver.getModules();
|
||||
const modules = resolver.getModules();
|
||||
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');
|
||||
if (await fs.pathExists(pkgJsonPath)) {
|
||||
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'));
|
||||
return keys(packageJson.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 [];
|
||||
@@ -99,7 +116,6 @@ class Resolver {
|
||||
return;
|
||||
}
|
||||
const pkg = this.dependencyMap[moduleName];
|
||||
logger.info(`Adding ${moduleName}:${pkg.version}`);
|
||||
this.modulesMap[moduleName] = {
|
||||
name: pkg.name,
|
||||
dirname: pkg.dirname,
|
||||
|
||||
@@ -5,26 +5,32 @@ import path from 'path';
|
||||
import config from 'turtle/config';
|
||||
import { IJob } from 'turtle/job';
|
||||
|
||||
let SUPPORTED_SDK_VERSIONS: number[];
|
||||
interface IVersionsMap {
|
||||
[platform: string]: number[];
|
||||
}
|
||||
|
||||
const versions: IVersionsMap = {};
|
||||
|
||||
export async function ensureCanBuildSdkVersion(job: IJob) {
|
||||
if (config.builder.useLocalWorkingDir) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!SUPPORTED_SDK_VERSIONS) {
|
||||
SUPPORTED_SDK_VERSIONS = await findSupportedSdkVersions(job.platform);
|
||||
}
|
||||
|
||||
const platformVersions = await findSupportedSdkVersions(job.platform);
|
||||
const targetMajorSdkVersion = ExponentTools.parseSdkMajorVersion(job.sdkVersion || job.manifest.sdkVersion);
|
||||
if (!SUPPORTED_SDK_VERSIONS.includes(targetMajorSdkVersion)) {
|
||||
if (!platformVersions.includes(targetMajorSdkVersion)) {
|
||||
throw new Error(`Unsupported SDK Version!`);
|
||||
}
|
||||
}
|
||||
|
||||
async function findSupportedSdkVersions(platform: 'android' | 'ios'): Promise<number[]> {
|
||||
const SDK_DIR_PREFIX = 'sdk';
|
||||
const files = await fs.readdir(path.join(config.directories.workingDir, platform));
|
||||
const sdks = files.filter((file) => file.startsWith(SDK_DIR_PREFIX));
|
||||
return sdks.map((sdk) => parseInt(sdk.substr(SDK_DIR_PREFIX.length), 10));
|
||||
export async function findSupportedSdkVersions(platform: 'android' | 'ios'): Promise<number[]> {
|
||||
if (versions[platform]) {
|
||||
return versions[platform];
|
||||
} else {
|
||||
const SDK_DIR_PREFIX = 'sdk';
|
||||
const files = await fs.readdir(path.join(config.directories.workingDir, platform));
|
||||
const sdks = files.filter((file) => file.startsWith(SDK_DIR_PREFIX));
|
||||
versions[platform] = sdks.map((sdk) => parseInt(sdk.substr(SDK_DIR_PREFIX.length), 10));
|
||||
return versions[platform];
|
||||
}
|
||||
}
|
||||
@@ -16,4 +16,9 @@ export enum ANDROID_BUILD_TYPES {
|
||||
APP_BUNDLE = 'app-bundle',
|
||||
}
|
||||
|
||||
export enum ANDROID_BUILD_MODES {
|
||||
DEBUG = 'debug',
|
||||
RELEASE = 'release',
|
||||
}
|
||||
|
||||
export { BUILD };
|
||||
+3
-1
@@ -1,4 +1,4 @@
|
||||
import { ANDROID_BUILD_TYPES, IOS_BUILD_TYPES } from 'turtle/constants';
|
||||
import { ANDROID_BUILD_MODES, ANDROID_BUILD_TYPES, IOS_BUILD_TYPES } from 'turtle/constants';
|
||||
|
||||
export interface IJob {
|
||||
platform: 'android' | 'ios';
|
||||
@@ -14,6 +14,7 @@ export interface IJob {
|
||||
bundleIdentifier?: string;
|
||||
// android
|
||||
androidPackage?: string;
|
||||
buildMode?: ANDROID_BUILD_MODES;
|
||||
};
|
||||
credentials: {
|
||||
// android
|
||||
@@ -25,6 +26,7 @@ export interface IJob {
|
||||
certP12?: string;
|
||||
certPassword?: string;
|
||||
provisioningProfile?: string;
|
||||
provisioningProfileId?: string;
|
||||
teamId?: string;
|
||||
appleSession?: string;
|
||||
udids?: string[];
|
||||
|
||||
+4
-1
@@ -64,7 +64,10 @@ async function processJob(jobData: any) {
|
||||
setCurrentJobId(job.id);
|
||||
const pingerHandle = sqs.changeMessageVisibilityRecurring(priority, jobData.ReceiptHandle, job.id);
|
||||
|
||||
logger.info(`Doing job MessageId=${jobData.MessageId} BuildId=${job.id} ${Date.now()}`);
|
||||
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) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Joi from 'joi';
|
||||
|
||||
import { PLATFORMS } from 'turtle/constants';
|
||||
import { ANDROID_BUILD_MODES, ANDROID_BUILD_TYPES, PLATFORMS } from 'turtle/constants';
|
||||
import baseJobSchema from 'turtle/jobsSchemas/base';
|
||||
|
||||
export default baseJobSchema.concat(
|
||||
@@ -12,5 +12,9 @@ export default baseJobSchema.concat(
|
||||
keystoreAlias: Joi.string(),
|
||||
keystore: Joi.string(),
|
||||
}),
|
||||
config: Joi.object().keys({
|
||||
buildMode: Joi.string().valid(Object.values(ANDROID_BUILD_MODES)).default(ANDROID_BUILD_MODES.RELEASE),
|
||||
buildType: Joi.string().valid(Object.values(ANDROID_BUILD_TYPES)).default(ANDROID_BUILD_TYPES.APK),
|
||||
}),
|
||||
}),
|
||||
);
|
||||
@@ -17,6 +17,7 @@ export default baseJobSchema.concat(
|
||||
teamId: Joi.string().required(),
|
||||
// it's not required for adhoc Expo Client builds
|
||||
provisioningProfile: Joi.string(),
|
||||
provisioningProfileId: Joi.string(),
|
||||
appleSession: Joi.string(),
|
||||
udids: Joi.array().items(Joi.string()),
|
||||
})
|
||||
|
||||
@@ -17,6 +17,7 @@ class Logger {
|
||||
name: 'turtle',
|
||||
level: config.logger.level,
|
||||
platform: config.platform,
|
||||
serializers: bunyan.stdSerializers,
|
||||
...config.deploymentEnv && { environment: config.deploymentEnv },
|
||||
streams: Object.values(streams),
|
||||
});
|
||||
|
||||
@@ -12,7 +12,14 @@ const createModeMetricName = (mode: TurtleModeLabels) => `${createMetricName()}.
|
||||
const createModeTag = (mode: TurtleModeLabels) => `mode:${mode}`;
|
||||
|
||||
export default async function sendConfigToDatadog() {
|
||||
const configuration = await getLabeledConfiguration();
|
||||
let configuration;
|
||||
try {
|
||||
configuration = await getLabeledConfiguration();
|
||||
} catch (err) {
|
||||
logger.warn('Failed to send the builders configuration to Datadog because it couldn\'t be fetched from Redis');
|
||||
return;
|
||||
}
|
||||
|
||||
const replicaCount = await getReplicaCount();
|
||||
const currentReplicaCount = replicaCount === null ? configuration.length : replicaCount;
|
||||
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
|
||||
import { PLATFORMS } from 'turtle/constants';
|
||||
import logger from 'turtle/logger';
|
||||
import {
|
||||
createConfigurationsKey,
|
||||
createDefaultConfigurationKey,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_ONLY_CONFIGURATION,
|
||||
} from 'turtle/utils/priorities';
|
||||
import { connect, RedisClient } from 'turtle/utils/redis';
|
||||
|
||||
const TIMEOUT = 3000;
|
||||
|
||||
// Turtle before doing anything (and after every build) checks for the first config
|
||||
// (an element in config table with key=i) that is not taken (config.i is null/outdated)
|
||||
// or is taken by this process itself.
|
||||
// If Turtle dies unexpectedly the configuration will become free after TTL expires,
|
||||
// so the state (number of HP/NP turtles) should come back to normal soon.
|
||||
|
||||
// For example, if a configuration table looks like this:
|
||||
// [ HIGH_CONFIGURATION, NORMAL_CONFIGURATION, HIGH_CONFIGURATION ]
|
||||
// If there is one turtle it runs with High Priority first.
|
||||
// If there are two turtles, one runs with High Priority first, the second one with Normal Priority first.
|
||||
// If the first dies, and the third is started in his place, it gets 3rd config (again HP-first),
|
||||
// but after some time, because of TTL for config reservations,
|
||||
// they should come back to using configurations no. 1 and 2.
|
||||
// If there are no more available configurations from the table, the default configuration is used.
|
||||
|
||||
const AVAILABLE_CONFIGURATIONS_IOS = [
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_ONLY_CONFIGURATION,
|
||||
HIGH_ONLY_CONFIGURATION,
|
||||
HIGH_ONLY_CONFIGURATION,
|
||||
// there are 5 iOS builders at the moment
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
];
|
||||
|
||||
const AVAILABLE_CONFIGURATIONS_ANDROID = [
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_ONLY_CONFIGURATION,
|
||||
HIGH_ONLY_CONFIGURATION,
|
||||
HIGH_ONLY_CONFIGURATION,
|
||||
HIGH_ONLY_CONFIGURATION,
|
||||
HIGH_ONLY_CONFIGURATION,
|
||||
HIGH_ONLY_CONFIGURATION,
|
||||
HIGH_ONLY_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
// there are 15 Android builders at the moment
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
HIGH_CONFIGURATION,
|
||||
];
|
||||
|
||||
const DEFAULT_CONFIGURATION = HIGH_CONFIGURATION;
|
||||
|
||||
async function run() {
|
||||
const redis = await connect(TIMEOUT, RedisClient.Configuration);
|
||||
|
||||
await redis.set(createConfigurationsKey(PLATFORMS.IOS), JSON.stringify(AVAILABLE_CONFIGURATIONS_IOS));
|
||||
await redis.set(createConfigurationsKey(PLATFORMS.ANDROID), JSON.stringify(AVAILABLE_CONFIGURATIONS_ANDROID));
|
||||
await redis.set(createDefaultConfigurationKey(PLATFORMS.IOS), JSON.stringify(DEFAULT_CONFIGURATION));
|
||||
await redis.set(createDefaultConfigurationKey(PLATFORMS.ANDROID), JSON.stringify(DEFAULT_CONFIGURATION));
|
||||
|
||||
redis.disconnect();
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
run()
|
||||
.then(() => logger.info('All done'))
|
||||
.catch((err) => logger.error('Error:', err));
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
import isNaN from 'lodash/isNaN';
|
||||
|
||||
import { PLATFORMS } from 'turtle/constants';
|
||||
import logger from 'turtle/logger';
|
||||
import { setReplicaCount } from 'turtle/utils/metadata';
|
||||
import { getRedisClient, RedisClient } from 'turtle/utils/redis';
|
||||
|
||||
async function run() {
|
||||
const platform = process.env.SCRIPT_PLATFORM;
|
||||
const replicaCountRaw = process.env.SCRIPT_REPLICA_COUNT;
|
||||
const replicaCount = Number(replicaCountRaw);
|
||||
|
||||
if (!platform || !replicaCountRaw) {
|
||||
throw new Error('You must set both SCRIPT_PLATFORM and SCRIPT_REPLICA_COUNT env variables.');
|
||||
}
|
||||
|
||||
if (!Object.values(PLATFORMS).includes(platform)) {
|
||||
throw new Error(`Unsupported platform: ${platform}`);
|
||||
}
|
||||
|
||||
if (isNaN(replicaCount)) {
|
||||
throw new Error(`Wrong value for replica count: ${replicaCountRaw}`);
|
||||
}
|
||||
|
||||
const redis = await getRedisClient(RedisClient.Configuration);
|
||||
logger.info(`[${platform}] Setting replica count in redis to ${replicaCount}`);
|
||||
await setReplicaCount(platform as PLATFORMS, replicaCount);
|
||||
redis.disconnect();
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
run()
|
||||
.then(() => logger.info('All done'))
|
||||
.catch((err) => {
|
||||
logger.error('Error:', err);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
+14
-5
@@ -1,13 +1,15 @@
|
||||
import { LoggerDetach } from '@expo/xdl';
|
||||
|
||||
import { findSupportedSdkVersions } from 'turtle/builders/utils/version';
|
||||
import config from 'turtle/config';
|
||||
import { doJob } from 'turtle/jobManager';
|
||||
import logger from 'turtle/logger';
|
||||
import setup from 'turtle/setup';
|
||||
import { checkShouldExit, setShouldExit, turtleVersion } from 'turtle/turtleContext';
|
||||
import { getRedisClient, RedisClient } from 'turtle/utils/redis';
|
||||
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,11 +37,18 @@ async function main() {
|
||||
}
|
||||
|
||||
try {
|
||||
const redis = await getRedisClient(RedisClient.Configuration);
|
||||
await redis.set(REDIS_TURTLE_VERSION_KEY, turtleVersion);
|
||||
logger.info(`Register Turtle version ${turtleVersion} in Redis`);
|
||||
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 Turtle version in Redis');
|
||||
logger.error({ err }, 'Failed to set versions in Redis');
|
||||
}
|
||||
|
||||
while (true) {
|
||||
|
||||
@@ -5,14 +5,6 @@ import { getRedisClient, RedisClient } from 'turtle/utils/redis';
|
||||
const createKeyPrefix = (platform: PLATFORMS) => `${config.deploymentEnv}:${platform}`;
|
||||
const createReplicaCountKey = (platform: PLATFORMS) => `${createKeyPrefix(platform)}:replicaCount`;
|
||||
|
||||
export async function setReplicaCount(platform: PLATFORMS, replicaCount: number) {
|
||||
const redis = await getRedisClient(RedisClient.Configuration);
|
||||
await redis.set(
|
||||
createReplicaCountKey(platform),
|
||||
replicaCount,
|
||||
);
|
||||
}
|
||||
|
||||
export async function getReplicaCount(maybePlatform?: PLATFORMS) {
|
||||
const platform = maybePlatform || config.platform;
|
||||
const redis = await getRedisClient(RedisClient.Configuration);
|
||||
|
||||
@@ -49,7 +49,7 @@ export function createDefaultConfigurationKey(platform = config.platform) {
|
||||
}
|
||||
|
||||
export async function getPriorities() {
|
||||
if (config.env === 'test') {
|
||||
if (config.env === 'test' || config.deploymentEnv === 'development') {
|
||||
return NORMAL_CONFIGURATION;
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ export async function getPriorities() {
|
||||
}
|
||||
}
|
||||
|
||||
export async function getConfiguration(currentRedisClient: any) {
|
||||
async function getConfiguration(currentRedisClient: any) {
|
||||
const redis = currentRedisClient || await getRedisClient(RedisClient.Configuration);
|
||||
return JSON.parse(await redis.get(createConfigurationsKey()));
|
||||
}
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@ export async function checkIfCancelled(jobId: string) {
|
||||
return await redis.get(`jobs:cancelled:${jobId}`);
|
||||
} catch (err) {
|
||||
if (config.deploymentEnv === 'development') {
|
||||
logger.warn('Did you turn on redis server? Run `yarn start-docker` in server/www');
|
||||
logger.warn('Did you turn on redis server? Run `yarn start-docker` in $EXPO_UNIVERSE_DIR/server/www');
|
||||
}
|
||||
logger.error({ err });
|
||||
return false;
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
|
||||
[program:turtle]
|
||||
directory=/app/turtle
|
||||
command=node ./build/server.js
|
||||
autorestart=true
|
||||
startretries=5
|
||||
startsecs=600
|
||||
stdout_logfile=/dev/stdout
|
||||
stdout_logfile_maxbytes=0
|
||||
stderr_logfile=/dev/stderr
|
||||
stderr_logfile_maxbytes=0
|
||||
|
||||
[eventlistener:turtle_failure]
|
||||
events=PROCESS_STATE_FATAL
|
||||
command=/app/turtle/scripts/android/supervisordEventListener.sh
|
||||
+2
-1
@@ -18,7 +18,8 @@
|
||||
"allowJs": true,
|
||||
"plugins": [
|
||||
{ "transform": "ts-transformer-imports" }
|
||||
]
|
||||
],
|
||||
"typeRoots": ["node_modules/@expo/babel-preset-cli/ts-declarations", "node_modules/@types"]
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "build", "workingdir"]
|
||||
|
||||
Reference in new issue
Block a user