mirror of
https://github.com/expo/turtle.git
synced 2026-11-14 19:12:55 -10:00
Compare commits
224
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12d2c04211 | ||
|
|
38abc1b915 | ||
|
|
6f6aec53bb | ||
|
|
c126e9d5cf | ||
|
|
fd8e110f38 | ||
|
|
91545a2726 | ||
|
|
18f58cfc87 | ||
|
|
5db06fa07b | ||
|
|
4faf23de16 | ||
|
|
f432a14d2f | ||
|
|
e957ea0b13 | ||
|
|
259dc4827c | ||
|
|
aaea6f80c0 | ||
|
|
2ce4f9f923 | ||
|
|
9cd489a297 | ||
|
|
06f10977aa | ||
|
|
9ba1302bfa | ||
|
|
a166a789fa | ||
|
|
377a8fbcf9 | ||
|
|
e3d685e416 | ||
|
|
2ac41fa82d | ||
|
|
32683d082b | ||
|
|
d629cd439b | ||
|
|
293e49fd00 | ||
|
|
5563d16bda | ||
|
|
6c5209e88f | ||
|
|
54c73dba8e | ||
|
|
81892b8c22 | ||
|
|
cfd704d4b6 | ||
|
|
dd79348228 | ||
|
|
c0eaa0de4f | ||
|
|
fa8576a36b | ||
|
|
ac25927326 | ||
|
|
2a23a4c97f | ||
|
|
42ed532f00 | ||
|
|
68f9d4c7d1 | ||
|
|
c5e0206d29 | ||
|
|
a8ddba34ac | ||
|
|
65f2f9fc67 | ||
|
|
5138ab57e8 | ||
|
|
5f066d14ee | ||
|
|
b307604177 | ||
|
|
6bdcd744df | ||
|
|
9447341b84 | ||
|
|
817653f01d | ||
|
|
eb0f2f5918 | ||
|
|
ba4b53b41a | ||
|
|
ba7b4a1968 | ||
|
|
3cb449f7ff | ||
|
|
b6ba977746 | ||
|
|
1155e26727 | ||
|
|
75ead4d6a1 | ||
|
|
7d5b092adc | ||
|
|
b644f15e43 | ||
|
|
18631f6482 | ||
|
|
85e2408f0c | ||
|
|
e9897054f3 | ||
|
|
6ae5eb1ab2 | ||
|
|
a32799a584 | ||
|
|
6f86b4ac57 | ||
|
|
9f07dbedb5 | ||
|
|
3e579ceeba | ||
|
|
a2913c28bf | ||
|
|
a0f9810320 | ||
|
|
74a3739b6e | ||
|
|
2c36c89ed4 | ||
|
|
099afed72c | ||
|
|
36d1d75544 | ||
|
|
70eca74b9c | ||
|
|
01137526c4 | ||
|
|
4972744a87 | ||
|
|
cbd11f2f4e | ||
|
|
fdd76085c1 | ||
|
|
daedefbca8 | ||
|
|
e7da1a0193 | ||
|
|
85cc6d1b9f | ||
|
|
07679dfbdc | ||
|
|
070485dd09 | ||
|
|
bf3e1feac9 | ||
|
|
fcba536698 | ||
|
|
e77f05ea1d | ||
|
|
819be0056c | ||
|
|
0a3faaf975 | ||
|
|
c38b1b4089 | ||
|
|
5c5de300a6 | ||
|
|
6efa267a1f | ||
|
|
81b7d8d911 | ||
|
|
95a48861e0 | ||
|
|
2bb14a67b6 | ||
|
|
5a1f48335f | ||
|
|
2dd89d2c08 | ||
|
|
5f9d98b1dc | ||
|
|
02833e211d | ||
|
|
ba4f2cc05a | ||
|
|
7f9b7a17d4 | ||
|
|
821e648d67 | ||
|
|
54a6e1910c | ||
|
|
688f970a1a | ||
|
|
9c666d90b4 | ||
|
|
4f351a047f | ||
|
|
7caa13bdda | ||
|
|
1f266f7b72 | ||
|
|
edfa2dbb94 | ||
|
|
1d5075d898 | ||
|
|
64147f0cf7 | ||
|
|
688a961513 | ||
|
|
19ed88150a | ||
|
|
e988fb282e | ||
|
|
16103cebf9 | ||
|
|
be14dca375 | ||
|
|
bf24c86399 | ||
|
|
7fb1e57a40 | ||
|
|
d6fcc6d881 | ||
|
|
525ddf6f04 | ||
|
|
f0416d131d | ||
|
|
2fdeea268c | ||
|
|
a11ed9198c | ||
|
|
2da016e4ce | ||
|
|
8278520474 | ||
|
|
6ab9d99d7c | ||
|
|
c8ad765d5d | ||
|
|
1834f323ce | ||
|
|
8e261a8827 | ||
|
|
d0033c2df1 | ||
|
|
63b7879608 | ||
|
|
cf57eceb6e | ||
|
|
5058cbe8e5 | ||
|
|
4804a3453c | ||
|
|
1d773f35cf | ||
|
|
3daa678540 | ||
|
|
616331b47b | ||
|
|
0b9ab78453 | ||
|
|
3e345ddaf8 | ||
|
|
4866c06a02 | ||
|
|
c36723d96c | ||
|
|
28b0266ba2 | ||
|
|
84a19ee261 | ||
|
|
8f3be65326 | ||
|
|
5d539a1bb2 | ||
|
|
833c9c1de5 | ||
|
|
ce74ab3161 | ||
|
|
62df247645 | ||
|
|
9bc4d75e9b | ||
|
|
b4d4b8a6c3 | ||
|
|
88d75c7581 | ||
|
|
03be505cd0 | ||
|
|
05568676ee | ||
|
|
903e44bd29 | ||
|
|
7697542b44 | ||
|
|
3baf4bcade | ||
|
|
c7e98c5858 | ||
|
|
fc48d27e42 | ||
|
|
fdc702f273 | ||
|
|
9fda74dfa4 | ||
|
|
6bab5f71ef | ||
|
|
3f1e9ce910 | ||
|
|
8fb54f3f27 | ||
|
|
069ef7e1c9 | ||
|
|
c0a742fa21 | ||
|
|
fca72875dc | ||
|
|
15ed26d4cd | ||
|
|
4c7af801f1 | ||
|
|
5012ec669d | ||
|
|
8b77a48b82 | ||
|
|
c6946eca25 | ||
|
|
9627ecb80c | ||
|
|
48c78f386a | ||
|
|
0dc251e023 | ||
|
|
d984061134 | ||
|
|
ff6401ba6b | ||
|
|
b443760699 | ||
|
|
0f0e86d17f | ||
|
|
f6697c0029 | ||
|
|
22f802164d | ||
|
|
aaa6e61061 | ||
|
|
e532e0270c | ||
|
|
bc0718ca7d | ||
|
|
bf63dcea70 | ||
|
|
9551c8773d | ||
|
|
470ff609fd | ||
|
|
addba74b9d | ||
|
|
b63e9e3f34 | ||
|
|
25aaa849f1 | ||
|
|
edc712d820 | ||
|
|
23c3e3509c | ||
|
|
406a3be4f1 | ||
|
|
dd60721270 | ||
|
|
469ead8df8 | ||
|
|
aa0ce81e98 | ||
|
|
dccccb7716 | ||
|
|
57f8404b6d | ||
|
|
ba7309bc4b | ||
|
|
4aec3d5ba7 | ||
|
|
d2eb447ebc | ||
|
|
f177cf4d7f | ||
|
|
59a181dee0 | ||
|
|
f4bf860a9a | ||
|
|
932958ad46 | ||
|
|
2a54b4578a | ||
|
|
7e234d09a3 | ||
|
|
5b22c351bf | ||
|
|
e2020f1ab4 | ||
|
|
c935e53e50 | ||
|
|
14e681f35f | ||
|
|
d3a7ccb582 | ||
|
|
62478de14a | ||
|
|
6594089779 | ||
|
|
11c5d3ee02 | ||
|
|
99b7ac6660 | ||
|
|
46fe34ed9c | ||
|
|
423fc8bbf5 | ||
|
|
4c8408a46b | ||
|
|
032d7c8b1f | ||
|
|
b2a0b3ce14 | ||
|
|
1ee922763e | ||
|
|
c31cd379c1 | ||
|
|
67754eba2a | ||
|
|
351fed00df | ||
|
|
487032b11d | ||
|
|
042dd2ccab | ||
|
|
99ae0d1cea | ||
|
|
ad2c87163b | ||
|
|
b4b9cf362e | ||
|
|
7ea4dac986 |
No files matched your search
+8
-10
@@ -164,7 +164,7 @@ commands:
|
||||
default: ios
|
||||
sdk_version:
|
||||
type: string
|
||||
default: sdk37
|
||||
default: sdk39
|
||||
steps:
|
||||
- restore_cache:
|
||||
key: "workingdir-v2-<< parameters.platform >>-<< parameters.sdk_version >>"
|
||||
@@ -179,7 +179,7 @@ commands:
|
||||
default: ios
|
||||
sdk_version:
|
||||
type: string
|
||||
default: sdk37
|
||||
default: sdk39
|
||||
steps:
|
||||
- save_cache:
|
||||
key: "workingdir-v2-<< parameters.platform >>-<< parameters.sdk_version >>"
|
||||
@@ -238,14 +238,14 @@ jobs:
|
||||
- save_yarn_cache:
|
||||
platform: darwin
|
||||
- restore_workingdir_cache:
|
||||
sdk_version: sdk37
|
||||
sdk_version: sdk39
|
||||
platform: ios
|
||||
- run:
|
||||
name: Run iOS smoke tests
|
||||
command: SDK_VERSION=sdk37 ./scripts/tests/runIOSSmokeTestsCI.sh
|
||||
command: SDK_VERSION=sdk39 ./scripts/tests/runIOSSmokeTestsCI.sh
|
||||
- save_workingdir_cache:
|
||||
workingdir: /Users/distiller/project/workingdir
|
||||
sdk_version: sdk37
|
||||
sdk_version: sdk39
|
||||
platform: ios
|
||||
|
||||
android_smoke_tests:
|
||||
@@ -257,11 +257,11 @@ jobs:
|
||||
- run: yarn
|
||||
- save_yarn_cache
|
||||
- restore_workingdir_cache:
|
||||
sdk_version: sdk37
|
||||
sdk_version: sdk39
|
||||
platform: android
|
||||
- run:
|
||||
name: Fetch Android shell app
|
||||
command: SDK_VERSION=sdk37 ./scripts/android/fetchRemoteAndroidTarball.sh
|
||||
command: SDK_VERSION=sdk39 ./scripts/android/fetchRemoteAndroidTarball.sh
|
||||
- run:
|
||||
name: Run Android smoke tests
|
||||
command: |
|
||||
@@ -269,7 +269,7 @@ jobs:
|
||||
--run "./scripts/tests/runAndroidSmokeTestsCI.sh"
|
||||
- save_workingdir_cache:
|
||||
workingdir: ~/turtle/workingdir
|
||||
sdk_version: sdk37
|
||||
sdk_version: sdk39
|
||||
platform: android
|
||||
|
||||
android_staging_deploy:
|
||||
@@ -307,8 +307,6 @@ workflows:
|
||||
tests:
|
||||
jobs:
|
||||
- unit_tests
|
||||
- ios_smoke_tests
|
||||
- android_smoke_tests
|
||||
deploy:
|
||||
jobs:
|
||||
- android_staging_approve_deploy:
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
---
|
||||
name: "\U0001F41B Bug Report"
|
||||
about: You want to report a reproducible bug or regression in turtle-cli.
|
||||
title: ''
|
||||
labels: 'bug'
|
||||
assignees: ''
|
||||
|
||||
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] -->
|
||||
@@ -13,14 +12,16 @@ assignees: ''
|
||||
|
||||
- [ ] 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 read [docs.expo.dev](https://docs.expo.dev) (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
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
---
|
||||
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: ''
|
||||
|
||||
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 read [docs.expo.dev](https://docs.expo.dev) (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 -->
|
||||
+267
@@ -7,6 +7,273 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## Unreleased
|
||||
|
||||
- Swap out Cloudfront CDN for `classic-assets.eascdn.net`. [#375](https://github.com/expo/turtle/pull/375)
|
||||
|
||||
# [0.24.3] - 2021-12-29
|
||||
|
||||
- Update ios sdk 44 shell tarball with [orientation lock fix](https://github.com/expo/expo/pull/15715)
|
||||
|
||||
# [0.24.2] - 2021-12-16
|
||||
|
||||
- Update Android shell tarball for SDK 44.
|
||||
|
||||
# [0.24.1] - 2021-12-15
|
||||
|
||||
- Update iOS and Android tarballs for SDK 44 RC. [#369](https://github.com/expo/turtle/pull/369).
|
||||
|
||||
# [0.24.0] - 2021-12-10
|
||||
|
||||
- Update iOS and Android tarballs for SDK 44 beta.
|
||||
- Add detection for Expo modules using `expo-module.config.json`, the successor to `unimodule.json`. [#368](https://github.com/expo/turtle/pull/368).
|
||||
- Redirect google bintray url to localhost. [#361](https://github.com/expo/turtle/pull/361)
|
||||
|
||||
# [0.23.6] - 2021-12-08
|
||||
|
||||
- Update android shell tarballs for bintray error fix. [#363](https://github.com/expo/turtle/pull/363)
|
||||
- Update AWS SDK. [#365](https://github.com/expo/turtle/pull/365)
|
||||
|
||||
# [0.23.5] - 2021-11-12
|
||||
|
||||
- Update iOS SDK 43 tarball with expo-updates fix for [#14967](https://github.com/expo/expo/issues/14967)
|
||||
|
||||
# [0.23.4] - 2021-11-09
|
||||
|
||||
- Update Android SDK 43 tarball with expo-updates fix for [#15112](https://github.com/expo/expo/issues/15112)
|
||||
|
||||
# [0.23.3] - 2021-11-04
|
||||
|
||||
- Update iOS and Android SDK 43 tarballs with expo-updates fixes for [#14930](https://github.com/expo/expo/issues/14930)
|
||||
|
||||
# [0.23.2] - 2021-10-29
|
||||
|
||||
- Update Android SDK 43 shell app with proguard fix
|
||||
|
||||
# [0.23.1] - 2021-10-20
|
||||
|
||||
- Add iOS and Android tarballs for SDK 43
|
||||
|
||||
# [0.23.0] - 2021-10-07
|
||||
|
||||
- Add iOS and Android beta tarballs for SDK 43
|
||||
- Bump xdl to fix Android shell app for SDK 43
|
||||
|
||||
# [0.22.6] - 2021-10-01
|
||||
|
||||
- add `ACCESS_MEDIA_LOCATION` to blacklist for android permissions
|
||||
- disable automatic versioning in Xcode 13
|
||||
|
||||
# [0.22.5] - 2021-09-09
|
||||
|
||||
- Fix s3 logger stream close crash.
|
||||
- Update Android tarballs SDK 42, 41, 40, and 39 to include location workaround.
|
||||
- Update Android tarball to include a local assets fix on SDK 42.
|
||||
|
||||
# [0.22.4] - 2021-07-27
|
||||
|
||||
- Update iOS and Android tarballs for SDK 42.
|
||||
|
||||
# [0.22.3] - 2021-07-02
|
||||
|
||||
- Update Android tarball for SDK 42.
|
||||
|
||||
# [0.22.1] - 2021-06-29
|
||||
|
||||
- Update iOS and Android beta tarballs for SDK 42.
|
||||
|
||||
# [0.22.0] - 2021-06-22
|
||||
|
||||
- Add iOS and Android beta tarballs for SDK 42.
|
||||
|
||||
# [0.21.9] - 2021-06-15
|
||||
|
||||
- Update `sharp` package, fixes support for M1 macs.
|
||||
|
||||
# [0.21.8] - 2021-05-25
|
||||
|
||||
- Update Android SDK41 tarball.
|
||||
|
||||
# [0.21.7] - 2021-05-21
|
||||
|
||||
- Update iOS SDK41 tarball.
|
||||
- Update Android SDK41 tarball.
|
||||
|
||||
# [0.21.6] - 2021-04-22
|
||||
|
||||
- Update iOS SDK41 tarball.
|
||||
- Update Android SDK41 tarball.
|
||||
|
||||
# [0.21.5] - 2021-04-15
|
||||
|
||||
- Revert iOS client tarball for SDK 41, use the SDK 40 tarball. No longer supporting this feature in SDK 41+.
|
||||
- Update Android SDK 41 tarball.
|
||||
|
||||
# [0.21.4] - 2021-04-13
|
||||
|
||||
- Update iOS client tarball for SDK 41.
|
||||
|
||||
# [0.21.3] - 2021-04-13
|
||||
|
||||
- Update SDK 41 tarball for iOS and Android.
|
||||
|
||||
# [0.21.2] - 2021-04-07
|
||||
|
||||
- Update SDK 41 beta tarball for Android.
|
||||
|
||||
# [0.21.1] - 2021-04-01
|
||||
|
||||
- Update SDK 41 beta tarball for iOS.
|
||||
|
||||
# [0.21.0] - 2021-03-29
|
||||
|
||||
- Add SDK 41 beta tarballs.
|
||||
- Bump @expo/xdl to 59.1.0.
|
||||
|
||||
# [0.20.7] - 2021-01-26
|
||||
|
||||
- Remove Go suffix from android app name
|
||||
|
||||
# [0.20.6] - 2021-01-25
|
||||
|
||||
- Update tarballs for SDK 40 patch release (3e345dd)
|
||||
|
||||
# [0.20.5] - 2020-12-23
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated SDK 40 Android tarball to fix `expo-location` background permissions on Android <9.
|
||||
|
||||
# [0.20.4] - 2020-12-17
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated SDK 40 iOS tarball to fix `expo-notifications` not emitting initial notification response.
|
||||
|
||||
# [0.20.3] - 2020-12-10
|
||||
|
||||
### Fixed
|
||||
|
||||
- Verify jq installation before proceeding with release ([#281](https://github.com/expo/turtle/pull/281)).
|
||||
- Fixed the iOS build when running offline and user lacks elevated permissions.
|
||||
|
||||
# [0.20.2] - 2020-12-09
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated SDK 40 Android tarball to fix `expo-notifications` installation identifier changing as a bug.
|
||||
|
||||
# [0.20.1] - 2020-12-08
|
||||
|
||||
### Changed
|
||||
|
||||
- Update SDK 40 iOS and Android tarballs for release
|
||||
|
||||
# [0.20.0] - 2020-11-30
|
||||
|
||||
- Add SDK 40 tarballs in preparation for SDK 40 beta
|
||||
|
||||
# [0.19.1] - 2020-11-19
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed the iOS build using Xcode 12.1 by runnig `xcrun simctl list` before the build phase.
|
||||
- Rebuild iOS tarballs (SDK 36, 37, 38, 39, Ad-Hoc Client) with Xcode 12.1 containing iOS 14 image fix.
|
||||
|
||||
# [0.19.0] - 2020-11-13
|
||||
|
||||
### Changed
|
||||
|
||||
- Rebuild iOS tarballs (SDK 36, 37, 38, 39, Ad-Hoc Client) with Xcode 12.1.
|
||||
|
||||
# [0.18.9] - 2020-11-09
|
||||
|
||||
### Fixed
|
||||
|
||||
- Updated xdl to 58.0.20 to fix an issue with updates.checkAutomatically not being applied properly to SDK 39 Android apps.
|
||||
|
||||
# [0.18.8] - 2020-10-27
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix issues with Reanimated v2 in Android SDK 39 tarball.
|
||||
|
||||
# [0.18.7] - 2020-10-23
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix issue with updates in self-hosted Android apps ([#10746](https://github.com/expo/expo/issues/10746)) in the SDK 39 tarball
|
||||
|
||||
# [0.18.6] - 2020-10-22
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix issues with notifications ([10624](https://github.com/expo/expo/pull/10624) and [10608](https://github.com/expo/expo/pull/10608)) in the Android SDK 39 tarball.
|
||||
|
||||
# [0.18.5] - 2020-10-07
|
||||
|
||||
### Fixed
|
||||
|
||||
- Always add expo-notifications for SDK >= 39 projects with android.enableDangerousExperimentalLeanBuilds enabled.
|
||||
|
||||
# [0.18.4] - 2020-10-06
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed an issue with notifications ([expo/expo#10562](https://github.com/expo/expo/issues/10562)) in the Android SDK 39 tarball.
|
||||
|
||||
# [0.18.3] - 2020-10-03
|
||||
|
||||
### Fixed
|
||||
|
||||
- Update @expo/xdl to fix regression in SDK <= 39 splash
|
||||
|
||||
# [0.18.2] - 2020-10-03
|
||||
|
||||
### Fixed
|
||||
|
||||
- Updated SDK 39 Android tarball.
|
||||
- Updated SDK 39 iOS tarball.
|
||||
- Updated iOS client tarball.
|
||||
- Update @expo/config and @expo/xdl. Temporarily bring in type definitions for color-string and xcode.
|
||||
|
||||
## [0.18.1] - 2020-09-22
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix building apps using SDK 39 for Android.
|
||||
|
||||
## [0.18.0] - 2020-09-21
|
||||
|
||||
### Added
|
||||
|
||||
- Added iOS and Android shell apps for SDK 39.
|
||||
|
||||
### Removed
|
||||
|
||||
- Dropped support for SDK 35.
|
||||
|
||||
## [0.17.3] - 2020-09-14
|
||||
|
||||
### Added
|
||||
|
||||
- Added gradle 6.2 to `turtle-android-base`
|
||||
- Added `ANDROID_NDK_HOME` in `turtle-android-base`
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgraded XDL so it processes root `build.gradle` of Android shell apps too
|
||||
|
||||
## [0.17.2] - 2020-08-06
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated iOS shell app for SDK 38 with fixed integer tagging in expo-gl for iOS 14. ([#245](https://github.com/expo/turtle/pull/245))
|
||||
|
||||
## [0.17.1] - 2020-08-05
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated Android shell app for SDK 38 with `targetSdkVersion` bumped to 29. ([#244](https://github.com/expo/turtle/pull/244))
|
||||
|
||||
## [0.17.0] - 2020-07-16
|
||||
|
||||
### Added
|
||||
|
||||
+1
-1
@@ -4,4 +4,4 @@ The Expo team is committed to fostering an open and welcoming environment.
|
||||
|
||||
**Our Community Guidelines can be found here:**
|
||||
|
||||
https://expo.io/guidelines
|
||||
https://expo.dev/guidelines
|
||||
+9
-2
@@ -1,30 +1,37 @@
|
||||
# Contributing to Turtle CLI
|
||||
|
||||
## How to contribute
|
||||
|
||||
You can contribute to Turtle CLI in various ways, including:
|
||||
|
||||
- [Reporting bugs or issues](https://github.com/expo/turtle/issues/new) on GitHub. Please make sure to fill in all the details suggested by the template to make sure the issue can be addressed as quickly as possible.
|
||||
- [Submitting improvements to the documentation](https://github.com/expo/expo/tree/master/docs). Updates, enhancements, new guides, spelling fixes…
|
||||
- Helping other people on [Expo Forums](https://forums.expo.io/) and on [Expo Developers Slack](http://slack.expo.io).
|
||||
- Helping other people on [Expo Forums](https://forums.expo.dev/) and on [Expo Developers Discord](http://chat.expo.dev).
|
||||
- Looking at existing [issues](https://github.com/expo/turtle/issues) and adding more information, particularly helping to reproduce the issues.
|
||||
- [Submitting a pull request](#submitting-a-pull-request) with a bug fix or an improvement.
|
||||
|
||||
## Turtle CLI repository
|
||||
|
||||
### Codebase
|
||||
|
||||
This repository contains the codebase for the `turtle-cli` NPM package. The same codebase is used to run standalone app builders on the Expo servers.
|
||||
|
||||
### Branches
|
||||
|
||||
The `master` branch of the repository should be kept releasable at any time. This way we can continuously release fixes and improvements without costly managing of different branches and issues will be noticed and fixed quickly. This also ensures other contributors can check out the latest version from GitHub and work on it with minimal disruption from other features in progress.
|
||||
|
||||
## Submitting a pull request
|
||||
|
||||
To submit a pull request:
|
||||
|
||||
1. Fork the [repository](https://github.com/expo/turtle) and create a feature branch. (Existing contributors can create feature branches without forking. Prefix the branch name with `@your-github-username/`.)
|
||||
2. Write the description of your pull request. Make sure to include a test plan and test your changes.
|
||||
3. Make sure all tests pass on CircleCI.
|
||||
4. Wait for a review and adjust the code if necessary.
|
||||
|
||||
## Publishing a release
|
||||
|
||||
- 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.
|
||||
- If you wish to release a new _beta_ version of `turtle-cli`, run `yarn release:beta` instead.
|
||||
- Update the [changelog](CHANGELOG.md).
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
## Setup
|
||||
|
||||
- Run `update-local-secrets` to populate the `.secrets*` files. You'll need to run this any time any secret changes (it shouldn't be very often).
|
||||
- Run `EXPO_UNIVERSE_DIR=/path/to/universe/dir yarn secrets:init-private YOUR_SQS_NICKNAME`. Alternatively, you can create `.secrets.local-queue` file with the SQS queues' urls yourself (`AWS_SQS_OUT_QUEUE_URL`, `AWS_SQS_ANDROID_QUEUE_URL`, `AWS_SQS_ANDROID_PRIORITY_QUEUE_URL`, `AWS_SQS_IOS_QUEUE_URL`, `AWS_SQS_IOS_PRIORITY_QUEUE_URL`)
|
||||
- Run `EXPO_UNIVERSE_DIR=/path/to/universe/dir yarn secrets:init-private YOUR_SQS_NICKNAME`. Alternatively, you can create `.secrets.local-queue` file with the SQS queues' urls yourself (`AWS_SQS_ANDROID_QUEUE_URL`, `AWS_SQS_ANDROID_PRIORITY_QUEUE_URL`, `AWS_SQS_IOS_QUEUE_URL`, `AWS_SQS_IOS_PRIORITY_QUEUE_URL`)
|
||||
- Run `yarn set-workingdir:local` or `yarn set-workingdir:remote`:
|
||||
- `:local` creates symlinks to the shell apps in `expo` repository (_unfortunately this is currently broken_)
|
||||
- `:remote` downloads precompiled shell apps
|
||||
|
||||
+5
-4
@@ -1,5 +1,5 @@
|
||||
# see docker-base/Dockerfile to learn what's installed in the turtle-android-base image
|
||||
FROM gcr.io/exponentjs/turtle-android-base:0.4.0
|
||||
FROM gcr.io/exponentjs/turtle-android-base:0.6.0
|
||||
|
||||
ADD . /app/turtle
|
||||
|
||||
@@ -11,12 +11,13 @@ RUN ln -s /app/turtle/workingdir /app/workingdir && \
|
||||
for SDK_VERSION in `ls /app/workingdir/android/`; do \
|
||||
echo "preparing $SDK_VERSION shell app" && \
|
||||
cd /app/workingdir/android/$SDK_VERSION && \
|
||||
mv packages non-workspace-packages && \
|
||||
mv package.json copy_package.json && \
|
||||
jq '.workspaces.packages = ["packages/expo", "packages/expo-modules-autolinking"]' copy_package.json > package.json && \
|
||||
rm -f copy_package.json && \
|
||||
# Keep in sync with src/bin/setup/android/index.ts#_installNodeModules
|
||||
# --prod requires --ignore-scripts (otherwise
|
||||
# expo-yarn-workspaces errors as missing)
|
||||
yarn install --ignore-scripts --prod && \
|
||||
mv non-workspace-packages packages ; \
|
||||
yarn install --ignore-scripts --prod ; \
|
||||
done
|
||||
|
||||
ENV NODE_ENV "production"
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
[](https://npmjs.com/package/turtle-cli)
|
||||
[](https://github.com/expo/turtle/blob/master/LICENSE)
|
||||
|
||||
[](http://slack.expo.io)
|
||||
[](https://forums.expo.io/)
|
||||
[](http://chat.expo.dev)
|
||||
[](https://forums.expo.dev/)
|
||||
|
||||
<hr />
|
||||
|
||||
@@ -21,7 +21,7 @@ You can use it both on your CI and your private computer.
|
||||
|
||||
## Installation
|
||||
|
||||
[Installation instructions and documentation here.](https://docs.expo.io/versions/latest/distribution/turtle-cli)
|
||||
[Installation instructions and documentation here.](https://docs.expo.dev/distribution/turtle-cli/)
|
||||
|
||||
## Usage example
|
||||
|
||||
@@ -29,13 +29,13 @@ See the [expo/turtle-cli-example](https://github.com/expo/turtle-cli-example) re
|
||||
|
||||
## 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.
|
||||
- Make sure you've read [the Expo Docs](https://docs.expo.dev/), especially [Building Standalone Apps on Your CI
|
||||
](https://docs.expo.dev/versions/latest/distribution/turtle-cli) and [Building Standalone Apps](https://docs.expo.dev/versions/latest/distribution/building-standalone-apps) guides.
|
||||
- Search for existing GitHub issues [in this repository](https://github.com/expo/turtle/issues) and in [expo/expo](https://github.com/expo/expo/issues) repository.
|
||||
- Ask for help in **one** of the following ways:
|
||||
* create [a GitHub issue](https://github.com/expo/turtle/issues/new).
|
||||
* create a new topic on [Expo Forums](https://forums.expo.io/).
|
||||
* ask a question on [Expo Developers Slack](http://slack.expo.io).
|
||||
- create [a GitHub issue](https://github.com/expo/turtle/issues/new).
|
||||
- create a new topic on the [Expo Forums](https://forums.expo.dev/).
|
||||
- connect with the community on the [Expo Developers Discord](http://chat.expo.dev).
|
||||
|
||||
## License
|
||||
|
||||
|
||||
+14
-1
@@ -32,7 +32,7 @@ RUN dpkg --add-architecture i386 && \
|
||||
apt-get clean
|
||||
|
||||
ENV NPM_CONFIG_LOGLEVEL warn
|
||||
ENV NODE_VERSION 12.16.1
|
||||
ENV NODE_VERSION 12.22.7
|
||||
|
||||
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 \
|
||||
@@ -57,10 +57,23 @@ ENV PATH ${ANDROID_HOME}/build-tools/28.0.3/:${PATH}
|
||||
|
||||
ADD configureAndroidSdk.sh /tmp/configureAndroidSdk.sh
|
||||
RUN /tmp/configureAndroidSdk.sh --install-all-platforms
|
||||
ENV ANDROID_NDK_HOME /usr/local/android-sdk-linux/ndk/17.2.4988734
|
||||
|
||||
# Support Gradle
|
||||
ENV TERM dumb
|
||||
|
||||
# Install gradle 6.2
|
||||
RUN wget https://services.gradle.org/distributions/gradle-6.2-all.zip
|
||||
RUN unzip -qq gradle-6.2-all.zip
|
||||
RUN cp -r gradle-6.2 /usr/local
|
||||
|
||||
RUN mkdir -p /root/.gradle/wrapper/dists/gradle-6.2-all/dvufqs6kielxeao781pmk5huj
|
||||
RUN mv gradle-6.2-all.zip /root/.gradle/wrapper/dists/gradle-6.2-all/dvufqs6kielxeao781pmk5huj
|
||||
RUN mv gradle-6.2 /root/.gradle/wrapper/dists/gradle-6.2-all/dvufqs6kielxeao781pmk5huj
|
||||
RUN touch /root/.gradle/wrapper/dists/gradle-6.2-all/dvufqs6kielxeao781pmk5huj/gradle-6.2-all.zip.ok
|
||||
RUN touch /root/.gradle/wrapper/dists/gradle-6.2-all/dvufqs6kielxeao781pmk5huj/gradle-6.2-all.zip.lck
|
||||
RUN chmod 755 /root/.gradle/wrapper/dists/gradle-6.2-all/dvufqs6kielxeao781pmk5huj/gradle-6.2/bin/gradle
|
||||
|
||||
# Install gradle 5.6.3
|
||||
RUN wget https://services.gradle.org/distributions/gradle-5.6.3-all.zip
|
||||
RUN unzip -qq gradle-5.6.3-all.zip
|
||||
|
||||
@@ -64,10 +64,7 @@ spec:
|
||||
name: turtle-js-config
|
||||
key: aws_secret_access_key
|
||||
- name: AWS_SQS_REGION
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: turtle-js-config
|
||||
key: aws_sqs_region
|
||||
value: us-west-2
|
||||
- name: AWS_SQS_IOS_QUEUE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
@@ -88,11 +85,6 @@ spec:
|
||||
secretKeyRef:
|
||||
name: turtle-js-config
|
||||
key: aws_sqs_android_priority_queue_url
|
||||
- name: AWS_SQS_OUT_QUEUE_URL
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: turtle-js-config
|
||||
key: aws_sqs_out_queue_url
|
||||
- name: AWS_CLOUDWATCH_REGION
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
@@ -149,15 +141,12 @@ spec:
|
||||
- name: DISABLE_DEX_MAX_HEAP
|
||||
value: "true"
|
||||
- name: JAVA_OPTS
|
||||
value: '-Xms2048m -XX:+HeapDumpOnOutOfMemoryError -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:+UseG1GC'
|
||||
value: '-Xms2048m -Xmx17g -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC'
|
||||
- name: GRADLE_OPTS
|
||||
value: '-Dorg.gradle.parallel=true -Dorg.gradle.configureondemand=true -Dorg.gradle.daemon=false -Dorg.gradle.jvmargs="-Xms2048m -XX:+HeapDumpOnOutOfMemoryError -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:+UseG1GC"'
|
||||
value: '-Dorg.gradle.parallel=true -Dorg.gradle.configureondemand=true -Dorg.gradle.daemon=false -Dorg.gradle.jvmargs="-Xms2048m -Xmx17g -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC"'
|
||||
- name: REDIS_CA_CERTIFICATE
|
||||
value: '/var/run/config/redislabs-tls/redislabs_ca.pem'
|
||||
resources:
|
||||
requests:
|
||||
memory: "8192Mi"
|
||||
cpu: "2000m"
|
||||
limits:
|
||||
memory: "8192Mi"
|
||||
cpu: "2000m"
|
||||
memory: "17Gi" # 17.8 GiB is max value reachable on current nodes
|
||||
cpu: "5000m"
|
||||
+12
-11
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "turtle-cli",
|
||||
"version": "0.17.0",
|
||||
"version": "0.24.3",
|
||||
"description": "The command-line tool for building standalone Expo apps",
|
||||
"preferGlobal": true,
|
||||
"scripts": {
|
||||
@@ -57,7 +57,7 @@
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"author": "Expo <support@expo.io>",
|
||||
"author": "Expo <support@expo.dev>",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/expo/turtle/issues"
|
||||
@@ -68,33 +68,34 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@expo/babel-preset-cli": "^0.1.3",
|
||||
"@types/color-string": "^1.5.0",
|
||||
"@types/decompress": "^4.2.3",
|
||||
"@types/fs-extra": "^5.0.4",
|
||||
"@types/ioredis": "^4.16.6",
|
||||
"@types/jest": "^23.3.9",
|
||||
"@types/joi": "^13.4.3",
|
||||
"@types/lodash": "^4.14.129",
|
||||
"@types/node-forge": "^0.8.6",
|
||||
"@types/node-forge": "^0.10.0",
|
||||
"@types/npm-package-arg": "^6.1.0",
|
||||
"@types/progress": "^2.0.1",
|
||||
"@types/raven": "^2.5.1",
|
||||
"@types/request": "^2.47.1",
|
||||
"@types/request-promise": "^4.1.44",
|
||||
"@types/semver": "^6.0.0",
|
||||
"@types/sharp": "^0.17.8",
|
||||
"@types/sharp": "0.28.3",
|
||||
"@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": "^25.1.0",
|
||||
"jest": "^26.1.0",
|
||||
"lint-staged": "^8.1.5",
|
||||
"nock": "^10.0.1",
|
||||
"nodemon": "^2.0.2",
|
||||
"release-it": "^12.3.4",
|
||||
"rimraf": "^2.6.2",
|
||||
"ts-jest": "^25.2.1",
|
||||
"ts-jest": "^26.1.2",
|
||||
"ts-node": "^8.0.3",
|
||||
"ts-transformer-imports": "^0.4.1",
|
||||
"tsconfig-paths": "^3.8.0",
|
||||
@@ -104,12 +105,12 @@
|
||||
"typescript": "^3.9.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@expo/config": "^3.2.14",
|
||||
"@expo/config": "~3.3.9",
|
||||
"@expo/spawn-async": "^1.4.2",
|
||||
"@expo/xdl": "57.9.25-alpha.1",
|
||||
"@expo/xdl": "59.1.7",
|
||||
"@google-cloud/logging-bunyan": "^2.0.3",
|
||||
"async-retry": "^1.2.1",
|
||||
"aws-sdk": "^2.226.1",
|
||||
"aws-sdk": "^2.1043.0",
|
||||
"bunyan": "^1.8.12",
|
||||
"bunyan-debug-stream": "^1.0.8",
|
||||
"bunyan-sentry-stream": "^1.2.1",
|
||||
@@ -128,7 +129,7 @@
|
||||
"request-progress": "^3.0.0",
|
||||
"request-promise": "^4.2.5",
|
||||
"semver": "^6.0.0",
|
||||
"sharp": "0.24.1",
|
||||
"sharp": "0.28.3",
|
||||
"source-map-support": "^0.5.6",
|
||||
"tar": "^4.4.6",
|
||||
"uuid": "^3.2.1",
|
||||
@@ -138,7 +139,7 @@
|
||||
"@expo/traveling-fastlane-darwin": "1.11.4"
|
||||
},
|
||||
"volta": {
|
||||
"node": "12.16.1",
|
||||
"node": "12.22.7",
|
||||
"yarn": "1.22.0"
|
||||
}
|
||||
}
|
||||
@@ -19,4 +19,8 @@ yes | $SDKMANAGER \
|
||||
"extras;google;m2repository" \
|
||||
"extras;google;google_play_services" | grep -v '='; [[ ${PIPESTATUS[1]} = 0 ]]
|
||||
|
||||
yes | $SDKMANAGER "ndk;17.2.4988734" | grep -v '='; [[ ${PIPESTATUS[1]} = 0 ]]
|
||||
if [[ "$(uname -s)" == "Darwin" ]] && [[ "$(uname -m)" == "arm64" ]]; then
|
||||
echo "Skipping NDK install on M1 macOS"
|
||||
else
|
||||
yes | $SDKMANAGER "ndk;17.2.4988734" | grep -v '='; [[ ${PIPESTATUS[1]} = 0 ]]
|
||||
fi
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ -z "$EXPO_UNIVERSE_DIR" ]; then
|
||||
echo "You need to specify EXPO_UNIVERSE_DIR to use this script. Alternatively you can create .secrets.local-queue file yourself with AWS_SQS_ANDROID_QUEUE_URL, AWS_SQS_IOS_QUEUE_URL and AWS_SQS_OUT_QUEUE_URL variables."
|
||||
echo "You need to specify EXPO_UNIVERSE_DIR to use this script. Alternatively you can create .secrets.local-queue file yourself with AWS_SQS_ANDROID_QUEUE_URL and AWS_SQS_IOS_QUEUE_URL variables."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -17,13 +17,11 @@ ANDROID_NORMAL=`cd $TERRAFORM_DIR; terraform state show module.turtle_queues_loc
|
||||
ANDROID_PRIORITY=`cd $TERRAFORM_DIR; terraform state show module.turtle_queues_local_$1.aws_sqs_queue.jobs_android_in_priority | head -1 | cut -d"=" -f2 | xargs`
|
||||
IOS_NORMAL=`cd $TERRAFORM_DIR; terraform state show module.turtle_queues_local_$1.aws_sqs_queue.jobs_ios_in | head -1 | cut -d"=" -f2 | xargs`
|
||||
IOS_PRIORITY=`cd $TERRAFORM_DIR; terraform state show module.turtle_queues_local_$1.aws_sqs_queue.jobs_ios_in_priority | head -1 | cut -d"=" -f2 | xargs`
|
||||
OUT=`cd $TERRAFORM_DIR; terraform state show module.turtle_queues_local_$1.aws_sqs_queue.jobs_out | head -1 | cut -d"=" -f2 | xargs`
|
||||
|
||||
cat << EOF > $TURTLE_DIR/.secrets.local-queue
|
||||
AWS_SQS_ANDROID_QUEUE_URL="$ANDROID_NORMAL"
|
||||
AWS_SQS_ANDROID_PRIORITY_QUEUE_URL="$ANDROID_PRIORITY"
|
||||
AWS_SQS_IOS_QUEUE_URL="$IOS_NORMAL"
|
||||
AWS_SQS_IOS_PRIORITY_QUEUE_URL="$IOS_PRIORITY"
|
||||
AWS_SQS_OUT_QUEUE_URL="$OUT"
|
||||
EOF
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
if ! command -v jq &> /dev/null
|
||||
then
|
||||
echo "jq is not installed and is required by the release script. Install it through homebrew or your package manager of choice."
|
||||
exit
|
||||
fi
|
||||
|
||||
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/.. && pwd )"
|
||||
|
||||
if [[ -z "$GITHUB_TOKEN" || -z "$CIRCLE_API_USER_TOKEN" ]]; then
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
if ! command -v jq &> /dev/null
|
||||
then
|
||||
echo "jq is not installed and is required by the release script. Install it through homebrew or your package manager of choice."
|
||||
exit
|
||||
fi
|
||||
|
||||
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/.. && pwd )"
|
||||
|
||||
$ROOT_DIR/node_modules/.bin/release-it -c $ROOT_DIR/.release-it.beta.json --preRelease=beta
|
||||
@@ -7,7 +7,7 @@ DOWNLOAD_DIR="${EXPO_DOWNLOAD_DIR:-$HOME/Downloads}"
|
||||
mkdir -p $DOWNLOAD_DIR
|
||||
|
||||
if [ ! -f "$ROOT_DIR/.secrets.local-queue" ]; then
|
||||
echo "You need to run \"yarn secrets:init-private [SQS_NAME]\" or create the .secrets.local-queue file yourself with AWS_SQS_ANDROID_QUEUE_URL, AWS_SQS_ANDROID_PRIORITY_QUEUE_URL, AWS_SQS_IOS_QUEUE_URL, AWS_SQS_IOS_PRIORITY_QUEUE_URL and AWS_SQS_OUT_QUEUE_URL variables."
|
||||
echo "You need to run \"yarn secrets:init-private [SQS_NAME]\" or create the .secrets.local-queue file yourself with AWS_SQS_ANDROID_QUEUE_URL, AWS_SQS_ANDROID_PRIORITY_QUEUE_URL, AWS_SQS_IOS_QUEUE_URL, and AWS_SQS_IOS_PRIORITY_QUEUE_URL variables."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
@@ -13,20 +13,19 @@ export AWS_SQS_ANDROID_QUEUE_URL="https://sqs.us-west-2.amazonaws.com/2742511416
|
||||
export AWS_SQS_ANDROID_PRIORITY_QUEUE_URL="https://sqs.us-west-2.amazonaws.com/274251141632/turtle_jobs_local_dominik_android_in_priority.fifo"
|
||||
export AWS_SQS_IOS_QUEUE_URL="https://sqs.us-west-2.amazonaws.com/274251141632/turtle_jobs_local_dominik_ios_in.fifo"
|
||||
export AWS_SQS_IOS_PRIORITY_QUEUE_URL="https://sqs.us-west-2.amazonaws.com/274251141632/turtle_jobs_local_dominik_ios_in_priority.fifo"
|
||||
export AWS_SQS_OUT_QUEUE_URL="https://sqs.us-west-2.amazonaws.com/274251141632/turtle_jobs_local_dominik_out.fifo"
|
||||
export AWS_SQS_REGION="aws.west2"
|
||||
export AWS_S3_BUCKET="exp-shell-app-assets"
|
||||
export AWS_S3_REGION="us-west-1"
|
||||
export AWS_CLOUDWATCH_REGION="us-west-1"
|
||||
export API_PROTOCOL="http"
|
||||
export API_HOSTNAME="staging.expo.io"
|
||||
export API_HOSTNAME="staging.exp.host"
|
||||
export API_PORT="443"
|
||||
export REDIS_URL="noop"
|
||||
export REDIS_CONFIG_URL="noop"
|
||||
export DATADOG_DISABLED="true"
|
||||
export TURTLE_SDK_VERSIONS_SECRET_TOKEN="noop"
|
||||
|
||||
pushd $ROOT_DIR/workingdir/android/${SDK_VERSION:-sdk37} >/dev/null 2>&1
|
||||
pushd $ROOT_DIR/workingdir/android/${SDK_VERSION:-sdk39} >/dev/null 2>&1
|
||||
yarn
|
||||
popd >/dev/null 2>&1
|
||||
|
||||
|
||||
@@ -9,13 +9,12 @@ export AWS_SQS_ANDROID_QUEUE_URL="https://sqs.us-west-2.amazonaws.com/2742511416
|
||||
export AWS_SQS_ANDROID_PRIORITY_QUEUE_URL="https://sqs.us-west-2.amazonaws.com/274251141632/turtle_jobs_local_dominik_android_in_priority.fifo"
|
||||
export AWS_SQS_IOS_QUEUE_URL="https://sqs.us-west-2.amazonaws.com/274251141632/turtle_jobs_local_dominik_ios_in.fifo"
|
||||
export AWS_SQS_IOS_PRIORITY_QUEUE_URL="https://sqs.us-west-2.amazonaws.com/274251141632/turtle_jobs_local_dominik_ios_in_priority.fifo"
|
||||
export AWS_SQS_OUT_QUEUE_URL="https://sqs.us-west-2.amazonaws.com/274251141632/turtle_jobs_local_dominik_out.fifo"
|
||||
export AWS_SQS_REGION="aws.west2"
|
||||
export AWS_S3_BUCKET="exp-shell-app-assets"
|
||||
export AWS_S3_REGION="us-west-1"
|
||||
export AWS_CLOUDWATCH_REGION="us-west-1"
|
||||
export API_PROTOCOL="https"
|
||||
export API_HOSTNAME="staging.expo.io"
|
||||
export API_HOSTNAME="staging.exp.host"
|
||||
export API_PORT="443"
|
||||
export REDIS_URL="noop"
|
||||
export REDIS_CONFIG_URL="noop"
|
||||
|
||||
@@ -9,7 +9,6 @@ export AWS_SQS_IOS_QUEUE_URL="noop"
|
||||
export AWS_SQS_ANDROID_QUEUE_URL="noop"
|
||||
export AWS_SQS_IOS_PRIORITY_QUEUE_URL="noop"
|
||||
export AWS_SQS_ANDROID_PRIORITY_QUEUE_URL="noop"
|
||||
export AWS_SQS_OUT_QUEUE_URL="noop"
|
||||
export AWS_ACCESS_KEY_ID="noop"
|
||||
export AWS_SECRET_ACCESS_KEY="noop"
|
||||
export AWS_SQS_REGION="noop"
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
if ! command -v jq &> /dev/null
|
||||
then
|
||||
echo "jq is not installed and is required by the release script. Install it through homebrew or your package manager of choice."
|
||||
exit
|
||||
fi
|
||||
|
||||
DEPLOY_ENDPOINT_URL="https://circleci.com/api/v1.1/project/github/expo/turtle-cli-example/tree/updates-do-not-remove-me"
|
||||
|
||||
curl -X POST \
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/android-shell-builder-7ce098f40cc82a2f61fed9f1f515d695a83c55b2.tar.gz
|
||||
@@ -1 +1 @@
|
||||
s3://exp-artifacts/android-shell-builder-076a13fd8b4ee84a59eb6d2777f6db0a2c71fb6d.tar.gz
|
||||
s3://exp-artifacts/android-shell-builder-6cde8e00cd7bdf7a933cd8aad7f8e86981ea68a2.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
s3://exp-artifacts/android-shell-builder-3fe600781956ce0823143d747a51afec5f9afe4f.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
s3://exp-artifacts/android-shell-builder-da0e85b79332cb8e93178aefcd90f7450e6e923e.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
s3://exp-artifacts/android-shell-builder-a7bb029adbc5636ac738759d70d80cc0f90dd757.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
s3://exp-artifacts/android-shell-builder-8725597cdf885f3d34cbbd7f74c6d1e0b9c31c93.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
s3://exp-artifacts/android-shell-builder-fe8aed82dd482644ed51d0dc45ae82c4c40a55c1.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
s3://exp-artifacts/android-shell-builder-6c4b7564ec3fe33100e80f5c9da065a678499b17.tar.gz
|
||||
@@ -1 +1 @@
|
||||
s3://exp-artifacts/ios-expo-client-18a58afe742e63f1d2ac71ba21404d8b84e6563e.tar.gz
|
||||
s3://exp-artifacts/ios-expo-client-dd6b6b4840c7a99725f1ec9a9a3970de91e90b1d.tar.gz
|
||||
@@ -1 +0,0 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-0115c48ddac4f63e5215541dff804871ef8c1e03.tar.gz
|
||||
@@ -1 +1 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-661a51216c2241dcfdd930517968cd1d0e0ee237.tar.gz
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-0983415327f49592d81f0bd3dc8c46a3572c19b0.tar.gz
|
||||
@@ -1 +1 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-30eb0558ff6a77acf56bb045e98b84f6a5e1478a.tar.gz
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-df407aadb7208fc389564aed400c39263294eb76.tar.gz
|
||||
@@ -1 +1 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-b0acfb129b4526f771bd0b363f2896b35f007e83.tar.gz
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-ba6ec1974977bebf8fd2db22a1c87f6a0b36ffa5.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-4a9a038998f6be13e8a2900a95afbb9f96dd023d.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-dd6b6b4840c7a99725f1ec9a9a3970de91e90b1d.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-2b9ea15e13f36c120c257039cf76e14573760570.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-1bdbf48b083ef475c294128074a4149b276062ff.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-2726b3298180818910646966bd82b7efc8936b5a.tar.gz
|
||||
@@ -0,0 +1 @@
|
||||
s3://exp-artifacts/ios-shell-builder-sdk-latest-088e13d4a4a77f952256bf2c361cbd3c20160821.tar.gz
|
||||
@@ -1 +1 @@
|
||||
[{"scope":"https://sqs.us-west-2.amazonaws.com:443","method":"POST","path":"/","body":"Action=ReceiveMessage&MaxNumberOfMessages=1&QueueUrl=https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F274251141632%2Fturtle_jobs_local_dominik_android_in.fifo&Version=2012-11-05&VisibilityTimeout=30","status":200,"response":"<?xml version=\"1.0\"?><ReceiveMessageResponse xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\"><ReceiveMessageResult/><ResponseMetadata><RequestId>2f9926f3-9db4-588e-a00a-71f445522996</RequestId></ResponseMetadata></ReceiveMessageResponse>","rawHeaders":["x-amzn-RequestId","2f9926f3-9db4-588e-a00a-71f445522996","Date","Wed, 08 Apr 2020 13:50:35 GMT","Content-Type","text/xml","Content-Length","240"]},{"scope":"https://sqs.us-west-2.amazonaws.com:443","method":"POST","path":"/","body":"Action=ReceiveMessage&MaxNumberOfMessages=1&QueueUrl=https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F274251141632%2Fturtle_jobs_local_dominik_android_in_priority.fifo&Version=2012-11-05&VisibilityTimeout=30","status":200,"response":"<?xml version=\"1.0\"?><ReceiveMessageResponse xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\"><ReceiveMessageResult/><ResponseMetadata><RequestId>e42b6179-9846-5d83-9209-367e40aa9c02</RequestId></ResponseMetadata></ReceiveMessageResponse>","rawHeaders":["x-amzn-RequestId","e42b6179-9846-5d83-9209-367e40aa9c02","Date","Wed, 08 Apr 2020 13:50:41 GMT","Content-Type","text/xml","Content-Length","240"]},{"scope":"https://sqs.us-west-2.amazonaws.com:443","method":"POST","path":"/","body":"Action=ReceiveMessage&MaxNumberOfMessages=1&QueueUrl=https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F274251141632%2Fturtle_jobs_local_dominik_android_in.fifo&Version=2012-11-05&VisibilityTimeout=30","status":200,"response":"<?xml version=\"1.0\"?><ReceiveMessageResponse xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\"><ReceiveMessageResult><Message><MessageId>093d5a52-932c-4141-958a-4ee8146dadab</MessageId><ReceiptHandle>AQEBq2BDKWkc+YFuyL+qBVQ6RCqne9ndyzDri6BeHTv+HhCU3kOlINEzzqbgrGJXh49AB6lVInGNsI+uc5uMhC61UscDKfFeqgfhDDUftovz6RXwiIj+xRalgP5fPZn94LbY4KmUoCuGCpXu9UlGxOoorYTkLft9AVY6kabCRlXA8SJzzYjUb1s+rtBoWS3Trj/AOIxOy0EqxeEWpBsNKc1yWc9RNbZ8/qABFLMjOzdmr5gaLEDoRJTUZZUEu9TVOxrC54ES+UaCmgVY17Ubmwo884GbHLoyUA+xqSD0Cvify5GCv3xzB+wjB4gGdGUFdOjj</ReceiptHandle><MD5OfBody>f0cb57fa399d2c8e81f8423e93127bdc</MD5OfBody><Body>{"id":"1b148a0a-4a5e-4572-b28a-c31aa018351a","experienceId":"0128bca1-78cf-4cb8-ac00-c07600500254","experienceName":"@dsokal-local/turtle-cli-example","platform":"android","config":{"releaseChannel":"default","buildType":"apk"},"status":"sent-to-queue","sdkVersion":"37.0.0","accountId":"9b473c78-6d0e-4b69-88a8-1c0960287b2f","priority":"normal","credentials":{"keystore":"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 truncated
|
||||
[{"scope":"https://sqs.us-west-2.amazonaws.com:443","method":"POST","path":"/","body":"Action=ReceiveMessage&MaxNumberOfMessages=1&QueueUrl=https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F274251141632%2Fturtle_jobs_local_dominik_android_in.fifo&Version=2012-11-05&VisibilityTimeout=30","status":200,"response":"<?xml version=\"1.0\"?><ReceiveMessageResponse xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\"><ReceiveMessageResult/><ResponseMetadata><RequestId>8de5bfc7-bc8e-5ee3-9e04-e787ff880c47</RequestId></ResponseMetadata></ReceiveMessageResponse>","rawHeaders":["x-amzn-RequestId","8de5bfc7-bc8e-5ee3-9e04-e787ff880c47","Date","Tue, 01 Dec 2020 13:10:35 GMT","Content-Type","text/xml","Content-Length","240"]},{"scope":"https://sqs.us-west-2.amazonaws.com:443","method":"POST","path":"/","body":"Action=ReceiveMessage&MaxNumberOfMessages=1&QueueUrl=https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F274251141632%2Fturtle_jobs_local_dominik_android_in_priority.fifo&Version=2012-11-05&VisibilityTimeout=30","status":200,"response":"<?xml version=\"1.0\"?><ReceiveMessageResponse xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\"><ReceiveMessageResult/><ResponseMetadata><RequestId>0bb998bb-3156-5159-b16f-c0fb725a5d65</RequestId></ResponseMetadata></ReceiveMessageResponse>","rawHeaders":["x-amzn-RequestId","0bb998bb-3156-5159-b16f-c0fb725a5d65","Date","Tue, 01 Dec 2020 13:10:41 GMT","Content-Type","text/xml","Content-Length","240"]},{"scope":"https://sqs.us-west-2.amazonaws.com:443","method":"POST","path":"/","body":"Action=ReceiveMessage&MaxNumberOfMessages=1&QueueUrl=https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F274251141632%2Fturtle_jobs_local_dominik_android_in.fifo&Version=2012-11-05&VisibilityTimeout=30","status":200,"response":"<?xml version=\"1.0\"?><ReceiveMessageResponse xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\"><ReceiveMessageResult/><ResponseMetadata><RequestId>feef69fc-27a3-5af5-83af-31bc64b1b9d7</RequestId></ResponseMetadata></ReceiveMessageResponse>","rawHeaders":["x-amzn-RequestId","feef69fc-27a3-5af5-83af-31bc64b1b9d7","Date","Tue, 01 Dec 2020 13:10:47 GMT","Content-Type","text/xml","Content-Length","240"]},{"scope":"https://sqs.us-west-2.amazonaws.com:443","method":"POST","path":"/","body":"Action=ReceiveMessage&MaxNumberOfMessages=1&QueueUrl=https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F274251141632%2Fturtle_jobs_local_dominik_android_in_priority.fifo&Version=2012-11-05&VisibilityTimeout=30","status":200,"response":"<?xml version=\"1.0\"?><ReceiveMessageResponse xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\"><ReceiveMessageResult><Message><MessageId>f39aaec9-47e0-4d02-bdb7-cf467fe2ea19</MessageId><ReceiptHandle>AQEBBI8nzAywIPCH57h1Iptt39uq60E5dzlj+Er50gtGqH+esoJ6iFdxoPDxvtD0xfT0qlyKSqlmoBDkQwh36tqsfqdT5FcFF8ejmPMRVIE8hexofzEbacxxw+3cBfgra2EFAik49TJbMT5pwxyaf42y+qwyWKOZ5N62VzRgGtnpj5ilNw1dt0lUzCdsfhCu7sne+dfJ8oMpbuy6T+ttoEYUS6VVKmv8f1BzuujHoKMy0kJip8r3zFoaigWE2p1bpFby9b9oBFTFT1ycD618YTu+Un5S9Q7Q6/nqJ7RPM2BfK2iPxBMk+UWmGfJ/otX11Zc0p8qx/MyKuYY/480Zta//xQ==</ReceiptHandle><MD5OfBody>1942fb5be12b59fc93b8052cf960f7d8</MD5OfBody><Body>{"id":"686530e4-c025-4a01-b84b-041e6d4f7fb3","experienceId":"4d928c1c-5be9-4380-8fd5-48a6a4805839","experienceName":"@testtest2/sdk-39-test","platform":"android","config":{"releaseChannel":"default","buildType":"apk"},"status":"sent-to-queue","sdkVersion":"39.0.0","accountId":"1ecd48ee-e393-4f6b-9f77-311f2e0d2b39","priority":"high","credentials":{"keystore":"/u3+7QAAAAIAAAABAAAAAQAgcWhybGMzcjB6eG4wbWk5enpnc3Rtemt0ZGd2emRhPT0AAAF2HlYoCQAABQEwggT9MA4GCisGAQQBKgIRAQEFAASCBOmzIBnRnHGBLgRUOJ1GGYiLjktnTeq/GXR/h4KZSSQ67PoiJqJnhrHLvj35Sr1swSL78q4j52IRV/a1mFbqQT4JFFy1ZdH2XgKUptY+kVc+ZrBI/awC8akIeYofWmKTNcS0Bc9IDT1VwIzwxxRrlnK/36Gh2m1vRuwVUdBChHjB4SHgC91F8wB0opY+RmiRhZqQevd8PBvZyqKenR5IWgZDXhsUYvvby4U4zMzvEgV3zNv7YGYM1Bb2ehJ8HdsW6O/58zFL3ufJ3+H2VonLxSn9YayninHoqkyMP40/mmnaFPz5jNItDkCQIeuudgQc8mrZlv4X0lM2ZjT4ZJDLdN4FCXV5iYDe4hopF8iF+DZmhMaZ1xFJ57boEaZ+WUcwsTkKOawusOGqW2JsvZbDMehOYLc8aqM2t28PrdYf3c7zspJALi6+tar2mwN66TX/AteeJRAk3r7HAiYPyle5gOffGgpmy0klLb5MEStkLQNNNsVMLJ7XSYrewzI6jXyAbMVc6PzbiVnCRPtoSy0TMUD7qQWMUGdePL1jxDlwhOVS3jgwOwHIFhUaLBbQOPROm1bF4hY3p25+LHFu954aDsYC3JlT6k9EOKIacKbJThq14r2Lb4EekfQlYTO/yst6ncVJcawWHYS1f93xWUlIjcpFnqJrLq2QVQfhafPWJmTS3K0lcYgFpfxvoU8RVn+ySaLOiy9J86l5YPmtpH/nFqr6BkqROy6dXps5x+D9vi3jVfYlYHnmqHxq7vyX5X+IMIMLvJ28SviuMKWb8Ikqmm7FSzlewJfF4xy/NLgQrQY6VxUahy92PZf3uR02ENolnj5nPSnh/B1FnIfrG46xFqlPg8imzen7hjKk1yXrdUjOT4WcjLdD/K/heVVHKUnsn3QCBt6eOgB8MpG9XzGRD+PAwloklASQx8iVSD67EauU2y1yayf4lNaQzdfnF3iFXSF25BU9XLJIRTtdRsTwmLRuLTmQcctLYD8hQCDQ2/njZtTkdY/AJeVlm44CdDaTLJpP8mVVscAOgH/S0DPi/oGGie8AYeKr8ZmBO1lQSN6l2LBJcAq2fh6AaUF5By21lT9FfR9KQd5WM87iUZk41nBIHQXcQSSt7H+vETEfm/8T9tOOwY5dMyf5QAYNCZuBoIFNCr0MOxe/Dcrsvd46KVbftR4HsJsQl53MnZoh4eLine truncated
|
||||
@@ -1 +1 @@
|
||||
[{"scope":"https://sqs.us-west-2.amazonaws.com:443","method":"POST","path":"/","body":"Action=ReceiveMessage&MaxNumberOfMessages=1&QueueUrl=https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F274251141632%2Fturtle_jobs_local_dominik_ios_in.fifo&Version=2012-11-05&VisibilityTimeout=30","status":200,"response":"<?xml version=\"1.0\"?><ReceiveMessageResponse xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\"><ReceiveMessageResult/><ResponseMetadata><RequestId>8bea4e96-2dc5-572c-9898-1991f406b911</RequestId></ResponseMetadata></ReceiveMessageResponse>","rawHeaders":["x-amzn-RequestId","8bea4e96-2dc5-572c-9898-1991f406b911","Date","Wed, 08 Apr 2020 13:54:16 GMT","Content-Type","text/xml","Content-Length","240"]},{"scope":"https://sqs.us-west-2.amazonaws.com:443","method":"POST","path":"/","body":"Action=ReceiveMessage&MaxNumberOfMessages=1&QueueUrl=https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F274251141632%2Fturtle_jobs_local_dominik_ios_in_priority.fifo&Version=2012-11-05&VisibilityTimeout=30","status":200,"response":"<?xml version=\"1.0\"?><ReceiveMessageResponse xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\"><ReceiveMessageResult/><ResponseMetadata><RequestId>a995b5e8-7f64-5567-baf9-e2efa6add8fe</RequestId></ResponseMetadata></ReceiveMessageResponse>","rawHeaders":["x-amzn-RequestId","a995b5e8-7f64-5567-baf9-e2efa6add8fe","Date","Wed, 08 Apr 2020 13:54:22 GMT","Content-Type","text/xml","Content-Length","240"]},{"scope":"https://sqs.us-west-2.amazonaws.com:443","method":"POST","path":"/","body":"Action=ReceiveMessage&MaxNumberOfMessages=1&QueueUrl=https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F274251141632%2Fturtle_jobs_local_dominik_ios_in.fifo&Version=2012-11-05&VisibilityTimeout=30","status":200,"response":"<?xml version=\"1.0\"?><ReceiveMessageResponse xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\"><ReceiveMessageResult/><ResponseMetadata><RequestId>8871c5eb-cb40-5a57-a611-92ec128fccd4</RequestId></ResponseMetadata></ReceiveMessageResponse>","rawHeaders":["x-amzn-RequestId","8871c5eb-cb40-5a57-a611-92ec128fccd4","Date","Wed, 08 Apr 2020 13:54:28 GMT","Content-Type","text/xml","Content-Length","240"]},{"scope":"https://sqs.us-west-2.amazonaws.com:443","method":"POST","path":"/","body":"Action=ReceiveMessage&MaxNumberOfMessages=1&QueueUrl=https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F274251141632%2Fturtle_jobs_local_dominik_ios_in_priority.fifo&Version=2012-11-05&VisibilityTimeout=30","status":200,"response":"<?xml version=\"1.0\"?><ReceiveMessageResponse xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\"><ReceiveMessageResult/><ResponseMetadata><RequestId>5c49f623-617a-531c-bbf8-a124b8af2bfd</RequestId></ResponseMetadata></ReceiveMessageResponse>","rawHeaders":["x-amzn-RequestId","5c49f623-617a-531c-bbf8-a124b8af2bfd","Date","Wed, 08 Apr 2020 13:54:34 GMT","Content-Type","text/xml","Content-Length","240"]},{"scope":"https://sqs.us-west-2.amazonaws.com:443","method":"POST","path":"/","body":"Action=ReceiveMessage&MaxNumberOfMessages=1&QueueUrl=https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F274251141632%2Fturtle_jobs_local_dominik_ios_in.fifo&Version=2012-11-05&VisibilityTimeout=30","status":200,"response":"<?xml version=\"1.0\"?><ReceiveMessageResponse xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\"><ReceiveMessageResult/><ResponseMetadata><RequestId>68b706ef-2dce-505b-a0d6-51e8f412e6f9</RequestId></ResponseMetadata></ReceiveMessageResponse>","rawHeaders":["x-amzn-RequestId","68b706ef-2dce-505b-a0d6-51e8f412e6f9","Date","Wed, 08 Apr 2020 13:54:41 GMT","Content-Type","text/xml","Content-Length","240"]},{"scope":"https://sqs.us-west-2.amazonaws.com:443","method":"POST","path":"/","body":"Action=ReceiveMessage&MaxNumberOfMessages=1&QueueUrl=https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F274251141632%2Fturtle_jobs_local_dominik_ios_in_priority.fifo&Version=2012-11-05&VisibilityTimeout=30","status":200,"response":"<?xml version=\"1.0\"?><ReceiveMessageResponse xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\"><ReceiveMessageResult/><ResponseMetadata><RequestId>c1e6a3e3-8d97-57cd-884c-f4e454757fcd</RequestId></ResponseMetadata></ReceiveMessageResponse>","rawHeaders":["x-amzn-RequestId","c1e6a3e3-8d97-57cd-884c-f4e454757fcd","Date","Wed, 08 Apr 2020 13:54:47 GMT","Content-Type","text/xml","Content-Length","240"]},{"scope":"https://sqs.us-west-2.amazonaws.com:443","method":"POST","path":"/","body":"Action=ReceiveMessage&MaxNumberOfMessages=1&QueueUrl=https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F274251141632%2Fturtle_jobs_local_dominik_ios_in.fifo&Version=2012-11-05&VisibilityTimeout=30","status":200,"response":"<?xml version=\"1.0\"?><ReceiveMessageResponse xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\"><ReceiveMessageResult/><ResponseMetadata><RequestId>a68dea4b-2de4-5000-b718-bd4cf40ca8fa</RequestId></ResponseMetadata></ReceiveMessageResponse>","rawHeaders":["x-amzn-RequestId","a68dea4b-2de4-5000-b718-bd4cf40ca8fa","Date","Wed, 08 Apr 2020 13:54:53 GMT","Content-Type","text/xml","Content-Length","240"]},{Line truncated
|
||||
[{"scope":"https://sqs.us-west-2.amazonaws.com:443","method":"POST","path":"/","body":"Action=ReceiveMessage&MaxNumberOfMessages=1&QueueUrl=https%3A%2F%2Fsqs.us-west-2.amazonaws.com%2F274251141632%2Fturtle_jobs_local_dominik_ios_in.fifo&Version=2012-11-05&VisibilityTimeout=30","status":200,"response":"<?xml version=\"1.0\"?><ReceiveMessageResponse xmlns=\"http://queue.amazonaws.com/doc/2012-11-05/\"><ReceiveMessageResult><Message><MessageId>99e0e5ee-90ef-494e-a275-3c1d55b58d9c</MessageId><ReceiptHandle>AQEB73473140rmgRe58W4T81ev8RJFQ0PvS6vOcHcSVdAV9D+bmP66k8qIqGuc0LJqR4bE9GLWG+QnM7N8rRW1tjIB74Gt9Co3PD7KFwrdgjZ3eys3fjK9nMfOj7BI0DMIP2xWi3YC90300dr/tTgJhVxfDh+Y0nYWleN9qEmttJoRqlJdSMgokqBR5VBFbhAmoNfsbSQnLzwU7fe/g2gjarImBRaCYpNWHYmS9CLozP5RBGKCddzQLvaNxDwORZXzHbYPZha5eFIDfXa3ncBtK2XdbOiquCmEB1tMt9ziIEOObSt/Vu7CD+ANhRqdqEFL/x</ReceiptHandle><MD5OfBody>ebe1f299d094649b2f3857bbd6f380ec</MD5OfBody><Body>{"id":"883f68d1-398a-4327-83da-6de1f288456d","experienceId":"2945b084-8989-4a02-b781-2a620034a172","experienceName":"@dsokal/turtle-cli-example","platform":"ios","config":{"releaseChannel":"default","usesNonExemptEncryption":false,"buildType":"archive","bundleIdentifier":"com.expo.turtle.cli.example"},"status":"sent-to-queue","sdkVersion":"39.0.0","accountId":"07eb1118-80a9-4769-a9b5-9f429cab29e2","priority":"normal","credentials":{"apnsKeyId":"54G5NV49UY","apnsKeyP8":"-----BEGIN PRIVATE KEY-----\\nMIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgBtkLIodAlsdUmV1L\\nxirn9Erof29278yzTaR/NNlvF0igCgYIKoZIzj0DAQehRANCAAS5jlfFX2KmTFi/\\ng+aohp77kCfYRZNYYmn4cgn4dKkXu5YOGbTJlzW6384xDpX6uWcXXytKD9cO00uN\\n8v9j4MT6\\n-----END PRIVATE KEY-----","teamId":"QL76XYH73P","teamName":"Alicja Warchał (Individual)","certP12":"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 truncated
|
||||
@@ -83,7 +83,7 @@
|
||||
],
|
||||
"description": "A very interesting project.",
|
||||
"icon": "./assets/images/icon.png",
|
||||
"iconUrl": "https://d1wp6m56sqw74a.cloudfront.net/~assets/fa6577fecc0a7838f15a254577639984",
|
||||
"iconUrl": "https://classic-assets.eascdn.net/~assets/fa6577fecc0a7838f15a254577639984",
|
||||
"ios": {
|
||||
"bundleIdentifier": "com.niech.to.zadziala",
|
||||
"supportsTablet": true
|
||||
@@ -101,7 +101,7 @@
|
||||
"splash": {
|
||||
"backgroundColor": "#ffffff",
|
||||
"image": "./assets/images/splash.png",
|
||||
"imageUrl": "https://d1wp6m56sqw74a.cloudfront.net/~assets/43ec0dcbe5a156bf9e650bb8c15e7af6",
|
||||
"imageUrl": "https://classic-assets.eascdn.net/~assets/43ec0dcbe5a156bf9e650bb8c15e7af6",
|
||||
"resizeMode": "contain"
|
||||
},
|
||||
"updates": {
|
||||
@@ -112,7 +112,7 @@
|
||||
"revisionId": "1.0.0-r.zV1W89wn23",
|
||||
"publishedTime": "2018-10-16T08:44:05.362Z",
|
||||
"commitTime": "2018-10-16T08:44:05.403Z",
|
||||
"bundleUrl": "https://d1wp6m56sqw74a.cloudfront.net/%40admin%2FtestApp%2F1.0.0%2Fb8678e2be7cd5bb9e240db0dd3c691c0-29.0.0-ios.js",
|
||||
"bundleUrl": "https://classic-assets.eascdn.net/%40admin%2FtestApp%2F1.0.0%2Fb8678e2be7cd5bb9e240db0dd3c691c0-29.0.0-ios.js",
|
||||
"releaseChannel": "default",
|
||||
"hostUri": "exp.host/@admin/testApp"
|
||||
},
|
||||
|
||||
+1
-18
@@ -2,9 +2,8 @@ import retry from 'async-retry';
|
||||
import AWS from 'aws-sdk';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { OUTPUT_QUEUE_URL, QUEUE_URL } from 'turtle/aws/utils';
|
||||
import { QUEUE_URL } from 'turtle/aws/utils';
|
||||
import config from 'turtle/config';
|
||||
import { JOB_UPDATE_TYPE } from 'turtle/constants/build';
|
||||
import logger from 'turtle/logger';
|
||||
import { getCurrentJobId } from 'turtle/turtleContext';
|
||||
|
||||
@@ -73,19 +72,3 @@ export function changeMessageVisibilityRecurring(priority: string, receiptHandle
|
||||
}
|
||||
}, (VISIBILITY_TIMEOUT_SEC * 1000) / 3);
|
||||
}
|
||||
|
||||
export async function sendMessage(jobId: string, status: JOB_UPDATE_TYPE, data = {}) {
|
||||
const params = {
|
||||
MessageBody: JSON.stringify({ jobId, status, ...data }),
|
||||
QueueUrl: OUTPUT_QUEUE_URL(),
|
||||
DelaySeconds: 0,
|
||||
MessageGroupId: jobId,
|
||||
};
|
||||
try {
|
||||
return await retry(async () => {
|
||||
return await sqs.sendMessage(params).promise();
|
||||
});
|
||||
} catch (err) {
|
||||
logger.error({ err }, `Error sending SQS message: ${JSON.stringify(params)}}`);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
import config from 'turtle/config';
|
||||
|
||||
export const QUEUE_URL = (priority: string) => (config.sqs.queues as any)[priority][config.platform];
|
||||
export const OUTPUT_QUEUE_URL = () => config.sqs.queues.out;
|
||||
@@ -42,7 +42,7 @@ export default async function ensureAndroidSDKIsPresent() {
|
||||
}
|
||||
}
|
||||
return {
|
||||
envVars: _createEnvVars(androidSdkDir),
|
||||
envVars: await _createEnvVars(androidSdkDir),
|
||||
path: _createPaths(androidSdkDir),
|
||||
};
|
||||
}
|
||||
@@ -63,10 +63,16 @@ async function _configureSdk(androidSdkDir: string) {
|
||||
});
|
||||
}
|
||||
|
||||
function _createEnvVars(androidSdkDir: string) {
|
||||
async function _createEnvVars(androidSdkDir: string) {
|
||||
const ndkPath = path.join(androidSdkDir, 'ndk/17.2.4988734');
|
||||
const ndkPathExists = await fs.pathExists(ndkPath);
|
||||
if (!ndkPathExists) {
|
||||
l.warn('Skipping NDK installation');
|
||||
}
|
||||
return {
|
||||
ANDROID_HOME: androidSdkDir,
|
||||
ANDROID_SDK: androidSdkDir,
|
||||
...(ndkPathExists ? { ANDROID_NDK_HOME: ndkPath } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,15 @@ import config from 'turtle/config';
|
||||
import { IAndroidCredentials, IJob, IJobResult } from 'turtle/job';
|
||||
import logger from 'turtle/logger';
|
||||
|
||||
// temporary solution until we can rebuild shellapps
|
||||
const blockGoogleBintrayAsync = _.once(async () => {
|
||||
if (config.builder.mode === 'online') {
|
||||
await fs.appendFile('/etc/hosts', '\n127.0.0.1\tdl.bintray.com\n127.0.0.1\tgoogle.bintray.com\n');
|
||||
}
|
||||
});
|
||||
|
||||
export default async function buildAndroid(jobData: IJob): Promise<IJobResult> {
|
||||
await blockGoogleBintrayAsync();
|
||||
await ensureCanBuildSdkVersion(jobData);
|
||||
const credentials = await getOrCreateCredentials(jobData);
|
||||
const outputFilePath = await runShellAppBuilder(jobData, credentials);
|
||||
@@ -84,7 +92,7 @@ async function runShellAppBuilder(
|
||||
logger.info({ buildPhase: 'resolve native modules' }, 'Resolving universal modules dependencies');
|
||||
const packageJsonDependecies = _.get(manifest, 'dependencies');
|
||||
const enabledModules = _.get(manifest, 'android.enableDangerousExperimentalLeanBuilds')
|
||||
? await resolveNativeModules(workingDir, packageJsonDependecies)
|
||||
? await resolveNativeModules(workingDir, sdkVersion, packageJsonDependecies)
|
||||
: await resolveExplicitOptIn(workingDir, packageJsonDependecies);
|
||||
|
||||
try {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import fs from 'fs-extra';
|
||||
import pick from 'lodash/pick';
|
||||
|
||||
import spawnAsync from '@expo/spawn-async';
|
||||
import buildArchive from 'turtle/builders/ios/archive';
|
||||
import { createBuilderContext, IContext } from 'turtle/builders/ios/context';
|
||||
import buildSimulator from 'turtle/builders/ios/simulator';
|
||||
@@ -51,6 +52,13 @@ async function initBuilder(ctx: IContext) {
|
||||
await fs.ensureDir(dir);
|
||||
await fs.chmod(dir, 0o755);
|
||||
}
|
||||
|
||||
if (config.builder.mode === 'online') {
|
||||
await spawnAsync('sudo', ['xcrun', 'simctl', 'list']);
|
||||
} else {
|
||||
// sudo not needed for CLI builds
|
||||
await spawnAsync('xcrun', ['simctl', 'list']);
|
||||
}
|
||||
}
|
||||
|
||||
async function cleanup(ctx: IContext) {
|
||||
|
||||
@@ -5,11 +5,10 @@ import fs from 'fs-extra';
|
||||
import get from 'lodash/get';
|
||||
import uuidv4 from 'uuid/v4';
|
||||
|
||||
import * as sqs from 'turtle/aws/sqs';
|
||||
import { UPDATE_CREDENTIALS } from 'turtle/constants/build';
|
||||
import { IAndroidCredentials, IJob } from 'turtle/job';
|
||||
import logger from 'turtle/logger';
|
||||
import { isOffline } from 'turtle/turtleContext';
|
||||
import { sendCredentialsUpdate } from 'turtle/utils/www';
|
||||
|
||||
async function getOrCreateCredentials(jobData: IJob): Promise<IAndroidCredentials> {
|
||||
if (!jobData.credentials) {
|
||||
@@ -50,9 +49,7 @@ async function getOrCreateCredentials(jobData: IJob): Promise<IAndroidCredential
|
||||
l.info(`Key password: ${credentials.keyPassword}`);
|
||||
l.info(`Please keep these credentials safe`);
|
||||
} else {
|
||||
await sqs.sendMessage(jobData.id, UPDATE_CREDENTIALS, {
|
||||
...credentials,
|
||||
});
|
||||
await sendCredentialsUpdate(jobData.id, 'android', credentials);
|
||||
l.info('Keystore sent to storage successfully');
|
||||
}
|
||||
await fs.unlink(keystoreFilename);
|
||||
|
||||
@@ -4,12 +4,11 @@ import spawnAsync from '@expo/spawn-async';
|
||||
import { IosCodeSigning } from '@expo/xdl';
|
||||
import fs from 'fs-extra';
|
||||
|
||||
import * as sqs from 'turtle/aws/sqs';
|
||||
import BuildError, { BuildErrorReason } from 'turtle/builders/BuildError';
|
||||
import { UPDATE_CREDENTIALS } from 'turtle/constants/build';
|
||||
import { IJob } from 'turtle/job';
|
||||
import logger from 'turtle/logger';
|
||||
import { isOffline } from 'turtle/turtleContext';
|
||||
import { sendCredentialsUpdate } from 'turtle/utils/www';
|
||||
|
||||
// tslint:disable-next-line:no-var-requires
|
||||
const travelingFastlane = process.platform === 'darwin' ? require('@expo/traveling-fastlane-darwin')() : null;
|
||||
@@ -64,7 +63,7 @@ async function prepareAdHocBuildCredentials(job: IJob) {
|
||||
await fs.writeFile(provisioningProfilePath, Buffer.from(credentials.provisioningProfile, 'base64'));
|
||||
logger.info(`Saved provisioning profile to ${provisioningProfilePath}`);
|
||||
} else {
|
||||
await sqs.sendMessage(job.id, UPDATE_CREDENTIALS, {
|
||||
await sendCredentialsUpdate(job.id, 'ios', {
|
||||
provisioningProfileId: credentials.provisioningProfileId,
|
||||
provisioningProfile: credentials.provisioningProfile,
|
||||
});
|
||||
|
||||
@@ -4,6 +4,7 @@ import keys from 'lodash/keys';
|
||||
import merge from 'lodash/merge';
|
||||
import values from 'lodash/values';
|
||||
import path from 'path';
|
||||
import semver from 'semver';
|
||||
import logger from 'turtle/logger';
|
||||
|
||||
export interface IUnimoduleEntry {
|
||||
@@ -19,21 +20,37 @@ interface IPackageInfo {
|
||||
dependencies: string[];
|
||||
}
|
||||
|
||||
export async function resolveExplicitOptIn(workingdir: string, packages?: string[]): Promise<IUnimoduleEntry[]> {
|
||||
export async function resolveExplicitOptIn(
|
||||
workingdir: string,
|
||||
packages?: string[],
|
||||
): Promise<IUnimoduleEntry[]> {
|
||||
const resolver = new Resolver(workingdir);
|
||||
await resolver.init();
|
||||
|
||||
const optionalModules = ['expo-branch'];
|
||||
resolver.addAll();
|
||||
const modules = packages
|
||||
? resolver.getModules().filter((mod) => !optionalModules.includes(mod.name) || packages.includes(mod.name))
|
||||
: resolver.getModules().filter((mod) => !optionalModules.includes(mod.name));
|
||||
? resolver
|
||||
.getModules()
|
||||
.filter(
|
||||
(mod) =>
|
||||
!optionalModules.includes(mod.name) || packages.includes(mod.name),
|
||||
)
|
||||
: resolver
|
||||
.getModules()
|
||||
.filter((mod) => !optionalModules.includes(mod.name));
|
||||
|
||||
modules.forEach(({ name, version }) => { logger.info(`Adding ${name}:${version}`); });
|
||||
modules.forEach(({ name, version }) => {
|
||||
logger.info(`Adding ${name}:${version}`);
|
||||
});
|
||||
return modules;
|
||||
}
|
||||
|
||||
export async function resolveNativeModules(workingdir: string, packages?: string[]): Promise<IUnimoduleEntry[]> {
|
||||
export async function resolveNativeModules(
|
||||
workingdir: string,
|
||||
sdkVersion: string,
|
||||
packages?: string[],
|
||||
): Promise<IUnimoduleEntry[]> {
|
||||
const resolver = new Resolver(workingdir);
|
||||
await resolver.init();
|
||||
|
||||
@@ -41,6 +58,13 @@ export async function resolveNativeModules(workingdir: string, packages?: string
|
||||
resolver.addAll();
|
||||
} else {
|
||||
const corePackages = await readCorePackages(workingdir);
|
||||
|
||||
// expo-notifications is required for shell apps in SDK >= 39
|
||||
// https://github.com/expo/expo/issues/10569
|
||||
if (semver.gte(sdkVersion, '39.0.0')) {
|
||||
resolver.addModule('expo-notifications');
|
||||
}
|
||||
|
||||
for (const pkg of corePackages) {
|
||||
if (resolver.isUnimodule(pkg)) {
|
||||
resolver.addModule(pkg);
|
||||
@@ -53,17 +77,36 @@ export async function resolveNativeModules(workingdir: string, packages?: string
|
||||
}
|
||||
}
|
||||
const modules = resolver.getModules();
|
||||
modules.forEach(({ name, version }) => { logger.info(`Adding ${name}:${version}`); });
|
||||
modules.forEach(({ name, version }) => {
|
||||
logger.info(`Adding ${name}:${version}`);
|
||||
});
|
||||
return modules;
|
||||
}
|
||||
|
||||
async function readCorePackages(workingdir: string) {
|
||||
const pkgJsonPath = path.join(workingdir, 'node_modules', 'react-native-unimodules', 'package.json');
|
||||
const expoPkgJsonPath = path.join(workingdir, 'packages', 'expo', 'package.json');
|
||||
if (await fs.pathExists(pkgJsonPath) && await fs.pathExists(expoPkgJsonPath)) {
|
||||
const pkgJsonPath = path.join(
|
||||
workingdir,
|
||||
'node_modules',
|
||||
'react-native-unimodules',
|
||||
'package.json',
|
||||
);
|
||||
const expoPkgJsonPath = path.join(
|
||||
workingdir,
|
||||
'packages',
|
||||
'expo',
|
||||
'package.json',
|
||||
);
|
||||
if (
|
||||
(await fs.pathExists(pkgJsonPath)) &&
|
||||
(await fs.pathExists(expoPkgJsonPath))
|
||||
) {
|
||||
const packageJson = JSON.parse(await fs.readFile(pkgJsonPath, 'utf-8'));
|
||||
const expoPackageJson = JSON.parse(await fs.readFile(expoPkgJsonPath, 'utf-8'));
|
||||
return keys(packageJson.dependencies).concat(keys(expoPackageJson.dependencies));
|
||||
const expoPackageJson = JSON.parse(
|
||||
await fs.readFile(expoPkgJsonPath, 'utf-8'),
|
||||
);
|
||||
return keys(packageJson.dependencies).concat(
|
||||
keys(expoPackageJson.dependencies),
|
||||
);
|
||||
} else {
|
||||
logger.warn('No core packages detected');
|
||||
return [];
|
||||
@@ -76,7 +119,7 @@ interface IDependencyInfo {
|
||||
|
||||
class Resolver {
|
||||
private workingdir: string;
|
||||
private modulesMap: {[key: string]: IUnimoduleEntry};
|
||||
private modulesMap: { [key: string]: IUnimoduleEntry };
|
||||
private dependencyMap: IDependencyInfo;
|
||||
|
||||
constructor(workingdir: string) {
|
||||
@@ -108,7 +151,7 @@ class Resolver {
|
||||
}
|
||||
|
||||
public getModules(): IUnimoduleEntry[] {
|
||||
return values(this.modulesMap);
|
||||
return values(this.modulesMap);
|
||||
}
|
||||
|
||||
private async resolveModule(moduleName: string) {
|
||||
@@ -127,7 +170,9 @@ class Resolver {
|
||||
}
|
||||
}
|
||||
|
||||
async function generateDependenciesInfo(workingdir: string): Promise<IDependencyInfo> {
|
||||
async function generateDependenciesInfo(
|
||||
workingdir: string,
|
||||
): Promise<IDependencyInfo> {
|
||||
const dir = await fs.readdir(path.join(workingdir, 'packages'));
|
||||
const map: IDependencyInfo = {};
|
||||
|
||||
@@ -140,7 +185,9 @@ async function generateDependenciesInfo(workingdir: string): Promise<IDependency
|
||||
}
|
||||
|
||||
// handle @unimodules directory
|
||||
const unimodulesDir = await fs.readdir(path.join(workingdir, 'packages', '@unimodules'));
|
||||
const unimodulesDir = await fs.readdir(
|
||||
path.join(workingdir, 'packages', '@unimodules'),
|
||||
);
|
||||
for (const pkgName of unimodulesDir) {
|
||||
const pkg = await getPackage(workingdir, path.join('@unimodules', pkgName));
|
||||
if (pkg) {
|
||||
@@ -155,19 +202,29 @@ async function generateDependenciesInfo(workingdir: string): Promise<IDependency
|
||||
return map;
|
||||
}
|
||||
|
||||
async function getPackage(workingdir: string, pkgName: string): Promise<IPackageInfo | null> {
|
||||
async function getPackage(
|
||||
workingdir: string,
|
||||
pkgName: string,
|
||||
): Promise<IPackageInfo | null> {
|
||||
const pkgPath = path.join(workingdir, 'packages', pkgName);
|
||||
const isAndroid = await fs.pathExists(path.join(pkgPath, 'android'));
|
||||
const isIos = await fs.pathExists(path.join(pkgPath, 'ios'));
|
||||
const isUnimodule = await fs.pathExists(path.join(pkgPath, 'unimodule.json'));
|
||||
const hasPackageJson = await fs.pathExists(path.join(pkgPath, 'package.json'));
|
||||
const isUnimodule =
|
||||
(await fs.pathExists(path.join(pkgPath, 'unimodule.json'))) ||
|
||||
(await fs.pathExists(path.join(pkgPath, 'expo-module.config.json')));
|
||||
const hasPackageJson = await fs.pathExists(
|
||||
path.join(pkgPath, 'package.json'),
|
||||
);
|
||||
if (!isUnimodule || !hasPackageJson || (!isAndroid && !isIos)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const packageJson = JSON.parse(await fs.readFile(path.join(pkgPath, 'package.json'), 'utf-8'));
|
||||
const packageJson = JSON.parse(
|
||||
await fs.readFile(path.join(pkgPath, 'package.json'), 'utf-8'),
|
||||
);
|
||||
|
||||
const pkgDeps = merge({}, // reading everything to make sure
|
||||
const pkgDeps = merge(
|
||||
{}, // reading everything to make sure
|
||||
packageJson.dependencies,
|
||||
packageJson.peerDependencies,
|
||||
packageJson.unimodulePeerDependencies,
|
||||
|
||||
+5
-2
@@ -29,7 +29,6 @@ export default {
|
||||
ios: env('AWS_SQS_IOS_PRIORITY_QUEUE_URL'),
|
||||
android: env('AWS_SQS_ANDROID_PRIORITY_QUEUE_URL'),
|
||||
},
|
||||
out: env('AWS_SQS_OUT_QUEUE_URL'),
|
||||
},
|
||||
},
|
||||
cloudwatch: {
|
||||
@@ -100,6 +99,10 @@ export default {
|
||||
),
|
||||
},
|
||||
www: {
|
||||
sdkVersionsSecretToken: env('TURTLE_SDK_VERSIONS_SECRET_TOKEN'),
|
||||
secretToken: env('TURTLE_SDK_VERSIONS_SECRET_TOKEN'),
|
||||
},
|
||||
leader: {
|
||||
redisKey: env('LEADER_REDIS_KEY', 'turtle-v1:leader'),
|
||||
redisKeyTTLSec: envNum('LEADER_REDIS_KEY_TTL', 30),
|
||||
},
|
||||
};
|
||||
+26
-10
@@ -12,6 +12,7 @@ import * as buildStatusMetric from 'turtle/metrics/buildStatus';
|
||||
import { checkShouldExit, setCurrentJobId, turtleVersion } from 'turtle/turtleContext';
|
||||
import { getPriorities, labelConfiguration, TurtleMode } from 'turtle/utils/priorities';
|
||||
import * as redis from 'turtle/utils/redis';
|
||||
import { sendBuildStatusUpdate } from 'turtle/utils/www';
|
||||
import { sanitizeJob } from 'turtle/validator';
|
||||
|
||||
function _maybeExit() {
|
||||
@@ -73,7 +74,8 @@ async function processJob(jobData: any, turtleMode: TurtleMode) {
|
||||
logger.error({ err, ...rawJob && { buildJobId: rawJob.id } }, 'The build job is invalid');
|
||||
// send message only if we've managed to parse the job json
|
||||
if (rawJob) {
|
||||
await sqs.sendMessage(rawJob.id, BUILD.JOB_STATES.ERRORED, {
|
||||
await sendBuildStatusUpdate(rawJob.id, {
|
||||
status: BUILD.JOB_STATES.ERRORED,
|
||||
turtleVersion,
|
||||
buildDuration: 0,
|
||||
reason: 'The build job is invalid',
|
||||
@@ -128,7 +130,7 @@ async function processJob(jobData: any, turtleMode: TurtleMode) {
|
||||
function failAfterMaxJobTime(priority: string, receiptHandle: string, job: any) {
|
||||
return setTimeout(async () => {
|
||||
try {
|
||||
sqs.sendMessage(job.id, BUILD.JOB_STATES.ERRORED, { turtleVersion });
|
||||
sendBuildStatusUpdate(job.id, { status: BUILD.JOB_STATES.ERRORED, turtleVersion });
|
||||
await deleteMessage(priority, receiptHandle);
|
||||
} finally {
|
||||
logger.error('Build timed out. Going to terminate turtle agent.');
|
||||
@@ -143,16 +145,28 @@ async function build(job: any, turtleMode: TurtleMode) {
|
||||
const s3Url = await logger.initForJob(job);
|
||||
const calculateBuildDuration = () => Math.ceil((Date.now() - startTimestamp) / 1000);
|
||||
|
||||
try {
|
||||
await sqs.sendMessage(job.id, BUILD.JOB_STATES.IN_PROGRESS, {
|
||||
logUrl: s3Url,
|
||||
logFormat: 'json',
|
||||
const commonPayload = {
|
||||
logs: {
|
||||
url: s3Url,
|
||||
format: 'json',
|
||||
},
|
||||
extraData: {
|
||||
turtleMode,
|
||||
},
|
||||
};
|
||||
try {
|
||||
await sendBuildStatusUpdate(job.id, {
|
||||
...commonPayload,
|
||||
status: BUILD.JOB_STATES.IN_PROGRESS,
|
||||
});
|
||||
const result = await (builders as any)[job.platform](job);
|
||||
const { artifactUrl } = await (builders as any)[job.platform](job);
|
||||
const buildDuration = calculateBuildDuration();
|
||||
sqs.sendMessage(job.id, BUILD.JOB_STATES.FINISHED, {
|
||||
...result,
|
||||
sendBuildStatusUpdate(job.id, {
|
||||
...commonPayload,
|
||||
artifacts: {
|
||||
url: artifactUrl,
|
||||
},
|
||||
status: BUILD.JOB_STATES.FINISHED,
|
||||
turtleVersion,
|
||||
buildDuration,
|
||||
});
|
||||
@@ -164,7 +178,9 @@ async function build(job: any, turtleMode: TurtleMode) {
|
||||
if (err instanceof BuildError) {
|
||||
reason = err.reason;
|
||||
}
|
||||
sqs.sendMessage(job.id, BUILD.JOB_STATES.ERRORED, {
|
||||
sendBuildStatusUpdate(job.id, {
|
||||
...commonPayload,
|
||||
status: BUILD.JOB_STATES.ERRORED,
|
||||
turtleVersion,
|
||||
buildDuration,
|
||||
...reason && { reason },
|
||||
|
||||
+2
-2
@@ -29,13 +29,13 @@ class Logger {
|
||||
jobID: job.id,
|
||||
experienceName: job.experienceName,
|
||||
});
|
||||
const s3Url = await streams.s3.stream.init(job);
|
||||
const s3Url = await streams.s3?.stream.init(job);
|
||||
return s3Url;
|
||||
}
|
||||
|
||||
public async cleanup() {
|
||||
this.currentLogger = this.parentLogger;
|
||||
await streams.s3.stream.cleanup();
|
||||
await streams.s3?.stream.cleanup();
|
||||
}
|
||||
|
||||
public trace(...all: any[]) {
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
import pickBy from 'lodash/pickBy';
|
||||
|
||||
import { pickBy } from 'lodash';
|
||||
import createGCloudStream from 'turtle/logger/streams/gcloud';
|
||||
import createOfflineStream from 'turtle/logger/streams/offline';
|
||||
import createS3Stream from 'turtle/logger/streams/s3';
|
||||
import createS3Stream, { S3Stream } from 'turtle/logger/streams/s3';
|
||||
import createSentryStream from 'turtle/logger/streams/sentry';
|
||||
import { isOffline } from 'turtle/turtleContext';
|
||||
|
||||
interface IStream {
|
||||
stream: any;
|
||||
interface IStream<T> {
|
||||
stream: T;
|
||||
type?: string;
|
||||
level?: string;
|
||||
reemitErrorEvents?: boolean;
|
||||
}
|
||||
|
||||
interface IStreamMap {
|
||||
[key: string]: IStream;
|
||||
stdout: IStream<any>;
|
||||
gcloud?: IStream<any>;
|
||||
s3?: IStream<S3Stream>;
|
||||
sentry?: IStream<any>;
|
||||
}
|
||||
|
||||
function prepareStreams(): IStreamMap {
|
||||
@@ -29,7 +31,7 @@ function prepareStreams(): IStreamMap {
|
||||
s3: createS3Stream(),
|
||||
sentry: createSentryStream(),
|
||||
};
|
||||
return pickBy(allStreams) as IStreamMap;
|
||||
return pickBy(allStreams) as any as IStreamMap;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ export default function create() {
|
||||
};
|
||||
}
|
||||
|
||||
class S3Stream extends EventEmitter {
|
||||
export class S3Stream extends EventEmitter {
|
||||
private s3Url: string | null = null;
|
||||
private lastFlush: number | null = null;
|
||||
private filePath: string | null = null;
|
||||
@@ -44,7 +44,11 @@ class S3Stream extends EventEmitter {
|
||||
|
||||
public async cleanup() {
|
||||
await this.flush(true);
|
||||
await fs.close(this.fileHandle as number);
|
||||
|
||||
if (this.fileHandle) {
|
||||
await fs.close(this.fileHandle);
|
||||
}
|
||||
|
||||
this.fileHandle = null;
|
||||
this.waitingOnPromise = false;
|
||||
}
|
||||
@@ -64,7 +68,7 @@ class S3Stream extends EventEmitter {
|
||||
return;
|
||||
}
|
||||
fs
|
||||
.write(this.fileHandle as number, `${JSON.stringify(rec)}\n`)
|
||||
.write(this.fileHandle, `${JSON.stringify(rec)}\n`)
|
||||
.then(() => {
|
||||
this.flush();
|
||||
});
|
||||
|
||||
@@ -6,6 +6,8 @@ import { doJob } from 'turtle/jobManager';
|
||||
import logger from 'turtle/logger';
|
||||
import setup from 'turtle/setup';
|
||||
import { checkShouldExit, setShouldExit, turtleVersion } from 'turtle/turtleContext';
|
||||
import { synchronizeFailedUpdates } from 'turtle/updatesManager';
|
||||
import Leader, { LeaderEvent } from 'turtle/utils/leader';
|
||||
import { setSupportedSdkVersions, setTurtleVersion } from 'turtle/utils/versions';
|
||||
|
||||
process.on('unhandledRejection', (err) => logger.error({ err }, 'Unhandled promise rejection'));
|
||||
@@ -33,6 +35,8 @@ async function main() {
|
||||
await setup[config.platform]();
|
||||
}
|
||||
|
||||
await electLeaderAndSynchronize();
|
||||
|
||||
try {
|
||||
await setTurtleVersion(turtleVersion);
|
||||
logger.info(`Registered Turtle version (${turtleVersion}) in www`);
|
||||
@@ -52,6 +56,28 @@ async function main() {
|
||||
}
|
||||
}
|
||||
|
||||
async function electLeaderAndSynchronize() {
|
||||
if (config.env === 'test') {
|
||||
return;
|
||||
|
||||
}
|
||||
const l = new Leader({
|
||||
key: config.leader.redisKey,
|
||||
id: config.hostname,
|
||||
ttl: config.leader.redisKeyTTLSec,
|
||||
});
|
||||
let intervalId: NodeJS.Timeout;
|
||||
l.on(LeaderEvent.elected, async () => {
|
||||
intervalId = await synchronizeFailedUpdates();
|
||||
});
|
||||
l.on(LeaderEvent.revoked, () => {
|
||||
if (intervalId) {
|
||||
clearInterval(intervalId);
|
||||
}
|
||||
});
|
||||
await l.elect();
|
||||
}
|
||||
|
||||
main()
|
||||
.then(() => logger.error('This should never happen...'))
|
||||
.catch((err) => logger.error({ err }, 'Something went terribly wrong'))
|
||||
|
||||
Vendored
+472
@@ -0,0 +1,472 @@
|
||||
interface pbxFile {
|
||||
basename: string;
|
||||
lastKnownFileType?: string;
|
||||
group?: string;
|
||||
path?: string;
|
||||
fileEncoding?: number;
|
||||
defaultEncoding?: number;
|
||||
sourceTree: string;
|
||||
includeInIndex?: number;
|
||||
explicitFileType?: unknown;
|
||||
settings?: object;
|
||||
uuid?: string;
|
||||
fileRef: string;
|
||||
target?: string;
|
||||
}
|
||||
|
||||
declare module 'xcode' {
|
||||
/**
|
||||
* UUID that is a key to each fragment of PBXProject.
|
||||
*/
|
||||
type UUID = string;
|
||||
|
||||
/**
|
||||
* if has following format `${UUID}_comment`
|
||||
*/
|
||||
type UUIDComment = string;
|
||||
|
||||
type XCObjectType =
|
||||
| 'PBXBuildFile'
|
||||
| 'PBXFileReference'
|
||||
| 'PBXFrameworksBuildPhase'
|
||||
| 'PBXGroup'
|
||||
| 'PBXNativeTarget'
|
||||
| 'PBXProject'
|
||||
| 'PBXResourcesBuildPhase'
|
||||
| 'PBXShellScriptBuildPhase'
|
||||
| 'PBXSourcesBuildPhase'
|
||||
| 'PBXVariantGroup'
|
||||
| 'XCBuildConfiguration'
|
||||
| 'XCConfigurationList';
|
||||
|
||||
type PBXFile = pbxFile;
|
||||
|
||||
interface PBXProject {
|
||||
isa: 'PBXProject';
|
||||
attributes: {
|
||||
LastUpgradeCheck: number;
|
||||
TargetAttributes: Record<
|
||||
UUID,
|
||||
{
|
||||
CreatedOnToolsVersion?: string;
|
||||
TestTargetID?: UUID;
|
||||
LastSwiftMigration?: number;
|
||||
ProvisioningStyle?: string;
|
||||
} & Record<string, undefined | number | string>
|
||||
>;
|
||||
};
|
||||
buildConfigurationList: UUID;
|
||||
buildConfigurationList_comment: string;
|
||||
compatibilityVersion: string;
|
||||
developmentRegion: string;
|
||||
hasScannedForEncodings: number;
|
||||
knownRegions: string[];
|
||||
mainGroup: UUID;
|
||||
productRefGroup: UUID;
|
||||
productRefGroup_comment: string;
|
||||
projectDirPath: string;
|
||||
projectRoot: string;
|
||||
targets: Array<{
|
||||
value: UUID;
|
||||
comment: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
interface PBXNativeTarget {
|
||||
isa: 'PBXNativeTarget';
|
||||
buildConfigurationList: UUID;
|
||||
buildConfigurationList_comment: string;
|
||||
buildPhases: Array<{
|
||||
value: UUID;
|
||||
comment: string;
|
||||
}>;
|
||||
buildRules: [];
|
||||
dependencies: [];
|
||||
name: string;
|
||||
productName: string;
|
||||
productReference: UUID;
|
||||
productReference_comment: string;
|
||||
productType: string;
|
||||
}
|
||||
|
||||
interface PBXBuildFile {
|
||||
isa: 'PBXBuildFile';
|
||||
fileRef: UUID;
|
||||
// "AppDelegate.m"
|
||||
fileRef_comment: string;
|
||||
}
|
||||
|
||||
interface XCConfigurationList {
|
||||
isa: 'XCConfigurationList';
|
||||
buildConfigurations: Array<{
|
||||
value: UUID;
|
||||
comment: string | 'Release' | 'Debug';
|
||||
}>;
|
||||
defaultConfigurationIsVisible: number;
|
||||
defaultConfigurationName: string;
|
||||
}
|
||||
|
||||
interface XCBuildConfiguration {
|
||||
isa: 'XCBuildConfiguration';
|
||||
baseConfigurationReference: UUID;
|
||||
baseConfigurationReference_comment: string;
|
||||
buildSettings: Record<string, string | undefined | number | Array<unknown>> & {
|
||||
// '"$(TARGET_NAME)"',
|
||||
PRODUCT_NAME?: string;
|
||||
// '"io.expo.demo.$(PRODUCT_NAME:rfc1034identifier)"',
|
||||
PRODUCT_BUNDLE_IDENTIFIER?: string;
|
||||
PROVISIONING_PROFILE_SPECIFIER?: string;
|
||||
// '"$(BUILT_PRODUCTS_DIR)/rni.app/rni"'
|
||||
TEST_HOST?: any;
|
||||
DEVELOPMENT_TEAM?: string;
|
||||
CODE_SIGN_IDENTITY?: string;
|
||||
CODE_SIGN_STYLE?: string;
|
||||
// '"$(TEST_HOST)"'
|
||||
BUNDLE_LOADER?: string;
|
||||
GCC_PREPROCESSOR_DEFINITIONS?: Array<unknown>;
|
||||
INFOPLIST_FILE?: string;
|
||||
IPHONEOS_DEPLOYMENT_TARGET?: string;
|
||||
LD_RUNPATH_SEARCH_PATHS?: string;
|
||||
OTHER_LDFLAGS?: Array<unknown>;
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME?: string;
|
||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME?: string;
|
||||
CLANG_ANALYZER_NONNULL?: string;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS?: string;
|
||||
CLANG_WARN_INFINITE_RECURSION?: string;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE?: string;
|
||||
DEBUG_INFORMATION_FORMAT?: string;
|
||||
ENABLE_TESTABILITY?: string;
|
||||
GCC_NO_COMMON_BLOCKS?: string;
|
||||
// 'appletvos'
|
||||
SDKROOT?: string;
|
||||
TARGETED_DEVICE_FAMILY?: number | string;
|
||||
// '10.0'
|
||||
TVOS_DEPLOYMENT_TARGET?: string;
|
||||
};
|
||||
name: string;
|
||||
}
|
||||
|
||||
type ProductType =
|
||||
| 'com.apple.product-type.application'
|
||||
| 'com.apple.product-type.app-extension'
|
||||
| 'com.apple.product-type.bundle'
|
||||
| 'com.apple.product-type.tool'
|
||||
| 'com.apple.product-type.library.dynamic'
|
||||
| 'com.apple.product-type.framework'
|
||||
| 'com.apple.product-type.library.static'
|
||||
| 'com.apple.product-type.bundle.unit-test'
|
||||
| 'com.apple.product-type.application.watchapp'
|
||||
| 'com.apple.product-type.application.watchapp2'
|
||||
| 'com.apple.product-type.watchkit-extension'
|
||||
| 'com.apple.product-type.watchkit2-extension';
|
||||
|
||||
interface PBXGroup {
|
||||
isa: 'PBXGroup';
|
||||
children: Array<{
|
||||
value: UUID;
|
||||
comment?: string;
|
||||
}>;
|
||||
name: string;
|
||||
path?: string;
|
||||
sourceTree: '"<group>"' | unknown;
|
||||
}
|
||||
|
||||
export class XcodeProject {
|
||||
|
||||
/**
|
||||
* `.pbxproj` file path.
|
||||
*/
|
||||
public filepath: string;
|
||||
|
||||
// Ex: '$(TARGET_NAME)'
|
||||
public productName: string;
|
||||
|
||||
public hash: {
|
||||
headComment: string;
|
||||
project: {
|
||||
archiveVersion: number;
|
||||
objectVersion: number;
|
||||
objects: {
|
||||
[T in XCObjectType]: Record<
|
||||
string,
|
||||
{
|
||||
isa: T;
|
||||
name: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
>;
|
||||
};
|
||||
rootObject: string;
|
||||
rootObject_comment: string;
|
||||
};
|
||||
};
|
||||
constructor(pbxprojPath: string);
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
//
|
||||
// `.pbxproj` related operation - starting & ending point.
|
||||
//
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* First step to be executed while working with `.pbxproj` file.
|
||||
*/
|
||||
public parse(callback?: (err: Error | null, results?: string) => void): this;
|
||||
|
||||
public parseSync(): void;
|
||||
|
||||
/**
|
||||
* @returns Content of .pbxproj file.
|
||||
*/
|
||||
public writeSync(options?: { omitEmptyValues?: boolean }): string;
|
||||
|
||||
public allUuids(): UUID[];
|
||||
public generateUuid(): UUID;
|
||||
|
||||
public addPluginFile(path: unknown, opt: unknown): unknown;
|
||||
public removePluginFile(path: unknown, opt: unknown): unknown;
|
||||
public addProductFile(targetPath: unknown, opt: unknown): unknown;
|
||||
public removeProductFile(path: unknown, opt: unknown): unknown;
|
||||
public addSourceFile(path: string, opt: unknown, group: string): unknown;
|
||||
public removeSourceFile(path: string, opt: unknown, group: string): unknown;
|
||||
public addHeaderFile(path: string, opt: unknown, group: string): unknown;
|
||||
public removeHeaderFile(path: string, opt: unknown, group: string): unknown;
|
||||
public addResourceFile(path: string, opt: unknown, group: string): unknown;
|
||||
public removeResourceFile(path: string, opt: unknown, group: string): unknown;
|
||||
public addFramework(fpath: unknown, opt: unknown): unknown;
|
||||
public removeFramework(fpath: unknown, opt: unknown): unknown;
|
||||
public addCopyfile(fpath: unknown, opt: unknown): unknown;
|
||||
public pbxCopyfilesBuildPhaseObj(target: unknown): unknown;
|
||||
public addToPbxCopyfilesBuildPhase(file: unknown): void;
|
||||
public removeCopyfile(fpath: unknown, opt: unknown): unknown;
|
||||
public removeFromPbxCopyfilesBuildPhase(file: unknown): void;
|
||||
public addStaticLibrary(path: unknown, opt: unknown): unknown;
|
||||
/**
|
||||
* Adds to `PBXBuildFile` section
|
||||
*/
|
||||
public addToPbxBuildFileSection(file: PBXFile): void;
|
||||
public removeFromPbxBuildFileSection(file: unknown): void;
|
||||
public addPbxGroup(
|
||||
filePathsArray: string[],
|
||||
name: string,
|
||||
path: string,
|
||||
sourceTree?: string,
|
||||
): { uuid: UUID; pbxGroup: PBXGroup };
|
||||
public removePbxGroup(groupName: unknown): void;
|
||||
public addToPbxProjectSection(target: unknown): void;
|
||||
public addToPbxNativeTargetSection(target: unknown): void;
|
||||
public addToPbxFileReferenceSection(file: any): void;
|
||||
public removeFromPbxFileReferenceSection(file: unknown): unknown;
|
||||
public addToXcVersionGroupSection(file: unknown): void;
|
||||
public addToPluginsPbxGroup(file: unknown): void;
|
||||
public removeFromPluginsPbxGroup(file: unknown): unknown;
|
||||
public addToResourcesPbxGroup(file: unknown): void;
|
||||
public removeFromResourcesPbxGroup(file: unknown): unknown;
|
||||
public addToFrameworksPbxGroup(file: unknown): void;
|
||||
public removeFromFrameworksPbxGroup(file: unknown): unknown;
|
||||
public addToPbxEmbedFrameworksBuildPhase(file: unknown): void;
|
||||
public removeFromPbxEmbedFrameworksBuildPhase(file: unknown): void;
|
||||
public addToProductsPbxGroup(file: unknown): void;
|
||||
public removeFromProductsPbxGroup(file: unknown): unknown;
|
||||
public addToPbxSourcesBuildPhase(file: unknown): void;
|
||||
public removeFromPbxSourcesBuildPhase(file: unknown): void;
|
||||
/**
|
||||
* Adds to PBXResourcesBuildPhase` section
|
||||
* @param resourcesBuildPhaseSectionKey Because there's might more than one `Resources` build phase we need to ensure file is placed under correct one.
|
||||
*/
|
||||
public addToPbxResourcesBuildPhase(file: PBXFile): void;
|
||||
public removeFromPbxResourcesBuildPhase(file: unknown): void;
|
||||
public addToPbxFrameworksBuildPhase(file: unknown): void;
|
||||
public removeFromPbxFrameworksBuildPhase(file: unknown): void;
|
||||
public addXCConfigurationList(
|
||||
configurationObjectsArray: unknown,
|
||||
defaultConfigurationName: unknown,
|
||||
comment: unknown,
|
||||
): {
|
||||
uuid: unknown;
|
||||
xcConfigurationList: {
|
||||
isa: string;
|
||||
buildConfigurations: Array<unknown>;
|
||||
defaultConfigurationIsVisible: number;
|
||||
defaultConfigurationName: unknown;
|
||||
};
|
||||
};
|
||||
public addTargetDependency(
|
||||
target: unknown,
|
||||
dependencyTargets: unknown,
|
||||
): {
|
||||
uuid: unknown;
|
||||
target: unknown;
|
||||
};
|
||||
public addBuildPhase(
|
||||
filePathsArray: unknown,
|
||||
buildPhaseType: unknown,
|
||||
comment: unknown,
|
||||
target: unknown,
|
||||
optionsOrFolderType: unknown,
|
||||
subfolderPath: unknown,
|
||||
): {
|
||||
uuid: unknown;
|
||||
buildPhase: {
|
||||
isa: unknown;
|
||||
buildActionMask: number;
|
||||
files: Array<unknown>;
|
||||
runOnlyForDeploymentPostprocessing: number;
|
||||
};
|
||||
};
|
||||
/**
|
||||
* Retrieves main part describing PBXProjects that are available in `.pbxproj` file.
|
||||
*/
|
||||
public pbxProjectSection(): Record<UUID, PBXProject> & Record<UUIDComment, string>;
|
||||
public pbxBuildFileSection(): Record<UUID, PBXBuildFile> & Record<UUIDComment, string>;
|
||||
public pbxXCBuildConfigurationSection(): Record<UUID, XCBuildConfiguration> &
|
||||
Record<UUIDComment, string>;
|
||||
public pbxFileReferenceSection(): Record<UUID, PBXFile> & Record<UUIDComment, string>;
|
||||
public pbxNativeTargetSection(): Record<UUID, PBXNativeTarget> & Record<UUIDComment, string>;
|
||||
public xcVersionGroupSection(): unknown;
|
||||
public pbxXCConfigurationList(): Record<UUID, XCConfigurationList> & Record<UUIDComment, string>;
|
||||
public pbxGroupByName(name: string): PBXGroup | undefined;
|
||||
/**
|
||||
* @param targetName in most cases it's the name of the application
|
||||
*/
|
||||
public pbxTargetByName(targetName: string): PBXNativeTarget | undefined;
|
||||
public findTargetKey(name: string): string;
|
||||
public pbxItemByComment(name: string, pbxSectionName: unknown): unknown;
|
||||
public pbxSourcesBuildPhaseObj(target: unknown): unknown;
|
||||
public pbxResourcesBuildPhaseObj(target: unknown): unknown;
|
||||
public pbxFrameworksBuildPhaseObj(target: unknown): unknown;
|
||||
public pbxEmbedFrameworksBuildPhaseObj(target: unknown): unknown;
|
||||
public buildPhase(group: unknown, target: unknown): string;
|
||||
public buildPhaseObject(name: string, group: unknown, target: unknown): unknown;
|
||||
public addBuildProperty(prop: unknown, value: unknown, build_name: unknown): void;
|
||||
public removeBuildProperty(prop: unknown, build_name: unknown): void;
|
||||
public updateBuildProperty(prop: string, value: unknown, build: string): void;
|
||||
public updateProductName(name: string): void;
|
||||
public removeFromFrameworkSearchPaths(file: unknown): void;
|
||||
public addToFrameworkSearchPaths(file: unknown): void;
|
||||
public removeFromLibrarySearchPaths(file: unknown): void;
|
||||
public addToLibrarySearchPaths(file: unknown): void;
|
||||
public removeFromHeaderSearchPaths(file: unknown): void;
|
||||
public addToHeaderSearchPaths(file: unknown): void;
|
||||
public addToOtherLinkerFlags(flag: unknown): void;
|
||||
public removeFromOtherLinkerFlags(flag: unknown): void;
|
||||
public addToBuildSettings(buildSetting: unknown, value: unknown): void;
|
||||
public removeFromBuildSettings(buildSetting: unknown): void;
|
||||
/**
|
||||
* Checks whether there is a file with given `filePath` in the project.
|
||||
*/
|
||||
public hasFile(filePath: string): PBXFile | false;
|
||||
public addTarget(
|
||||
name: unknown,
|
||||
type: unknown,
|
||||
subfolder: unknown,
|
||||
): {
|
||||
uuid: unknown;
|
||||
pbxNativeTarget: {
|
||||
isa: string;
|
||||
name: string;
|
||||
productName: string;
|
||||
productReference: unknown;
|
||||
productType: string;
|
||||
buildConfigurationList: unknown;
|
||||
buildPhases: Array<unknown>;
|
||||
buildRules: Array<unknown>;
|
||||
dependencies: Array<unknown>;
|
||||
};
|
||||
};
|
||||
/**
|
||||
* Get First PBXProject that can be found in `.pbxproj` file.
|
||||
*/
|
||||
public getFirstProject(): { uuid: UUID; firstProject: PBXProject };
|
||||
public getFirstTarget(): {
|
||||
uuid: UUID;
|
||||
firstTarget: unknown;
|
||||
};
|
||||
/**
|
||||
* Retrieves PBXNativeTarget by the type
|
||||
*/
|
||||
public getTarget(productType: ProductType): { uuid: UUID; target: PBXNativeTarget } | null;
|
||||
public addToPbxGroupType(file: unknown, groupKey: unknown, groupType: unknown): void;
|
||||
public addToPbxVariantGroup(file: unknown, groupKey: unknown): void;
|
||||
public addToPbxGroup(file: PBXFile, groupKey: UUID): void;
|
||||
public pbxCreateGroupWithType(name: unknown, pathName: unknown, groupType: unknown): unknown;
|
||||
public pbxCreateVariantGroup(name: unknown): unknown;
|
||||
public pbxCreateGroup(name: string, pathName: string): UUID;
|
||||
public removeFromPbxGroupAndType(file: unknown, groupKey: unknown, groupType: unknown): void;
|
||||
public removeFromPbxGroup(file: unknown, groupKey: unknown): void;
|
||||
public removeFromPbxVariantGroup(file: unknown, groupKey: unknown): void;
|
||||
public getPBXGroupByKeyAndType(key: unknown, groupType: unknown): unknown;
|
||||
/**
|
||||
* @param groupKey UUID.
|
||||
*/
|
||||
public getPBXGroupByKey(groupKey: string): PBXGroup | undefined;
|
||||
public getPBXVariantGroupByKey(key: unknown): unknown;
|
||||
public findPBXGroupKeyAndType(criteria: unknown, groupType: unknown): string;
|
||||
/**
|
||||
* @param criteria Params that should be used to locate desired PBXGroup.
|
||||
*/
|
||||
public findPBXGroupKey(criteria: { name?: string; path?: string }): UUID | undefined;
|
||||
public findPBXVariantGroupKey(criteria: unknown): string;
|
||||
public addLocalizationVariantGroup(
|
||||
name: unknown,
|
||||
): {
|
||||
uuid: unknown;
|
||||
fileRef: unknown;
|
||||
basename: unknown;
|
||||
};
|
||||
public addKnownRegion(name: string): void;
|
||||
public removeKnownRegion(name: string): void;
|
||||
public hasKnownRegion(name: string): boolean;
|
||||
public getPBXObject(name: string): unknown;
|
||||
/**
|
||||
* - creates `PBXFile`
|
||||
* - adds to `PBXFileReference` section
|
||||
* - adds to `PBXGroup` or `PBXVariantGroup` if applicable
|
||||
* @returns `null` if file is already in `pbxproj`.
|
||||
*/
|
||||
public addFile(
|
||||
path: string,
|
||||
group?: string,
|
||||
opt?: {
|
||||
plugin?: string;
|
||||
target?: string;
|
||||
variantGroup?: string;
|
||||
lastKnownFileType?: string;
|
||||
defaultEncoding?: 4;
|
||||
customFramework?: true;
|
||||
explicitFileType?: number;
|
||||
weak?: true;
|
||||
compilerFLags?: string;
|
||||
embed?: boolean;
|
||||
sign?: boolean;
|
||||
},
|
||||
): PBXFile | null;
|
||||
public removeFile(path: unknown, group: unknown, opt: unknown): unknown;
|
||||
public getBuildProperty(prop: unknown, build: unknown): unknown;
|
||||
public getBuildConfigByName(name: unknown): object;
|
||||
public addDataModelDocument(filePath: unknown, group: unknown, opt: unknown): unknown;
|
||||
public addTargetAttribute(prop: unknown, value: unknown, target: unknown): void;
|
||||
public removeTargetAttribute(prop: unknown, target: unknown): void;
|
||||
}
|
||||
|
||||
export function project(projectPath: string): XcodeProject;
|
||||
}
|
||||
|
||||
declare module 'xcode/lib/pbxFile' {
|
||||
export default class PBXFile implements pbxFile {
|
||||
public basename: string;
|
||||
public lastKnownFileType?: string;
|
||||
public group?: string;
|
||||
public path?: string;
|
||||
public fileEncoding?: number;
|
||||
public defaultEncoding?: number;
|
||||
public sourceTree: string;
|
||||
public includeInIndex?: number;
|
||||
public explicitFileType?: unknown;
|
||||
public settings?: object;
|
||||
public uuid?: string;
|
||||
public fileRef: string;
|
||||
public target?: string;
|
||||
constructor(file: string);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
import Redis from 'ioredis';
|
||||
import chunk from 'lodash/chunk';
|
||||
|
||||
import config from 'turtle/config';
|
||||
import { getRedisClient, RedisClient } from 'turtle/utils/redis';
|
||||
import { sendBuildStatusUpdate, sendCredentialsUpdate } from 'turtle/utils/www';
|
||||
|
||||
const RETRY_COUNT = 5;
|
||||
|
||||
type UpdateType = 'build' | 'credentials';
|
||||
interface IUpdate {
|
||||
type: UpdateType;
|
||||
buildId: string;
|
||||
updateBody: any;
|
||||
retried: number;
|
||||
}
|
||||
|
||||
export async function saveUpdateFailure(buildId: string, type: UpdateType, updateBody: object): Promise<void> {
|
||||
if (config.env === 'test') {
|
||||
return;
|
||||
}
|
||||
const redis = await getRedisClient(RedisClient.Configuration) as Redis.Redis;
|
||||
const update: IUpdate = {
|
||||
type,
|
||||
buildId,
|
||||
updateBody,
|
||||
retried: 0,
|
||||
};
|
||||
await redis.set(getFailedUpdateKey(buildId), JSON.stringify(update));
|
||||
}
|
||||
|
||||
export async function synchronizeFailedUpdates(intervalMs = 3 * 60 * 1000): Promise<NodeJS.Timeout> {
|
||||
try {
|
||||
await _synchronizeFailedUpdates();
|
||||
} catch (err) {
|
||||
// don't do anything
|
||||
}
|
||||
return setInterval(() => _synchronizeFailedUpdates(), intervalMs);
|
||||
}
|
||||
|
||||
async function _synchronizeFailedUpdates(): Promise<void> {
|
||||
const redis = await getRedisClient(RedisClient.Configuration) as Redis.Redis;
|
||||
const keys = await redis.keys(getFailedUpdateKey('*'));
|
||||
const keyChunks = chunk(keys, 20);
|
||||
for (const keyChunk of keyChunks) {
|
||||
await Promise.all(keyChunk.map((key: string) => resendUpdateForKey(key)));
|
||||
}
|
||||
}
|
||||
|
||||
async function resendUpdateForKey(key: string): Promise<void> {
|
||||
try {
|
||||
const redis = await getRedisClient(RedisClient.Configuration) as Redis.Redis;
|
||||
const updateRaw = await redis.get(key);
|
||||
if (updateRaw) {
|
||||
const update = JSON.parse(updateRaw) as IUpdate;
|
||||
try {
|
||||
await resendUpdateToWWW(update);
|
||||
await redis.del(key);
|
||||
} catch (err) {
|
||||
update.retried += 1;
|
||||
if (update.retried >= RETRY_COUNT) {
|
||||
await redis.del(key);
|
||||
} else {
|
||||
await redis.set(key, JSON.stringify(update));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
// don't do anything
|
||||
}
|
||||
}
|
||||
|
||||
async function resendUpdateToWWW(update: IUpdate): Promise<void> {
|
||||
const { type, buildId, updateBody } = update;
|
||||
if (type === 'build') {
|
||||
await sendBuildStatusUpdate(buildId, updateBody);
|
||||
} else if (type === 'credentials') {
|
||||
const { platform, ...rest } = updateBody;
|
||||
await sendCredentialsUpdate(buildId, platform, rest);
|
||||
}
|
||||
}
|
||||
|
||||
const getFailedUpdateKey = (buildId: string) => `${config.deploymentEnv}:failed-update:${buildId}`;
|
||||
@@ -0,0 +1,164 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import Redis from 'ioredis';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import { getRedisClient, RedisClient } from 'turtle/utils/redis';
|
||||
|
||||
interface ILeaderParams {
|
||||
key: string;
|
||||
id?: string;
|
||||
ttl?: number;
|
||||
wait?: number;
|
||||
}
|
||||
|
||||
const RENEW_LEADER_SCRIPT = `
|
||||
local leader_key = KEYS[1]
|
||||
local leader_id = KEYS[2]
|
||||
local leader_ttl = KEYS[3]
|
||||
|
||||
local current_leader
|
||||
|
||||
current_leader = redis.call("get", leader_key)
|
||||
if (current_leader == leader_id) then
|
||||
redis.call("pexpire", leader_key, leader_ttl)
|
||||
return "ok"
|
||||
else
|
||||
return "you_are_not_the_leader"
|
||||
end
|
||||
`;
|
||||
|
||||
const STOP_BEING_LEADER_SCRIPT = `
|
||||
local leader_key = KEYS[1]
|
||||
local leader_id = KEYS[2]
|
||||
|
||||
local current_leader
|
||||
|
||||
current_leader = redis.call("get", leader_key)
|
||||
if (current_leader == leader_id) then
|
||||
redis.call("del", leader_key)
|
||||
return "ok"
|
||||
else
|
||||
return "you_are_not_the_leader"
|
||||
end
|
||||
`;
|
||||
|
||||
interface IRedisCustom extends Redis.Redis {
|
||||
renewLeader(key: string, id: string, ttl: number): Promise<string>;
|
||||
stopBeingLeader(key: string, id: string): Promise<string>;
|
||||
}
|
||||
|
||||
enum LeaderEvent {
|
||||
elected = 'elected',
|
||||
revoked = 'revoked',
|
||||
error = 'error',
|
||||
}
|
||||
|
||||
class Leader extends EventEmitter {
|
||||
private key: string;
|
||||
private id: string;
|
||||
private ttl: number;
|
||||
private wait: number;
|
||||
private waitId?: NodeJS.Timeout;
|
||||
private redisClientValue?: IRedisCustom;
|
||||
private renewId?: NodeJS.Timeout;
|
||||
private started = false;
|
||||
|
||||
constructor({ key, id, ttl = 30, wait = 1000 }: ILeaderParams) {
|
||||
super();
|
||||
|
||||
this.key = key;
|
||||
this.id = id || uuid();
|
||||
this.ttl = ttl * 1000;
|
||||
this.wait = wait;
|
||||
}
|
||||
public async elect(): Promise<void> {
|
||||
if (!this.redisClientValue) {
|
||||
await this.init();
|
||||
}
|
||||
|
||||
if (!this.started) {
|
||||
this.started = true;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await this.redisClient.set(this.key, this.id, 'PX', this.ttl, 'NX');
|
||||
if (res === null) {
|
||||
this.waitId = setTimeout(() => {
|
||||
this.elect();
|
||||
}, this.wait);
|
||||
} else {
|
||||
this.emit(LeaderEvent.elected);
|
||||
this.renewId = setInterval(() => {
|
||||
this.renew();
|
||||
}, this.ttl / 2);
|
||||
}
|
||||
} catch (err) {
|
||||
this.emit(LeaderEvent.error, err);
|
||||
}
|
||||
}
|
||||
|
||||
public async stop(): Promise<void> {
|
||||
if (!this.started) {
|
||||
throw new Error('You should start the election first!');
|
||||
}
|
||||
try {
|
||||
const res = await this.redisClient.stopBeingLeader(this.key, this.id);
|
||||
if (res === 'ok') {
|
||||
this.emit(LeaderEvent.revoked);
|
||||
}
|
||||
if (this.renewId) {
|
||||
clearInterval(this.renewId);
|
||||
}
|
||||
if (this.waitId) {
|
||||
clearTimeout(this.waitId);
|
||||
}
|
||||
this.redisClientValue?.disconnect();
|
||||
this.redisClientValue = undefined;
|
||||
} catch (err) {
|
||||
this.emit(LeaderEvent.error, err);
|
||||
}
|
||||
}
|
||||
|
||||
private get redisClient(): IRedisCustom {
|
||||
if (!this.redisClientValue) {
|
||||
throw new Error('Please run the init method first!');
|
||||
}
|
||||
return this.redisClientValue as IRedisCustom;
|
||||
}
|
||||
|
||||
private async init(): Promise<void> {
|
||||
if (this.redisClientValue) {
|
||||
return;
|
||||
}
|
||||
this.redisClientValue = await getRedisClient(RedisClient.Configuration);
|
||||
const redisClient = this.redisClient as IRedisCustom;
|
||||
redisClient.defineCommand('renewLeader', {
|
||||
numberOfKeys: 3,
|
||||
lua: RENEW_LEADER_SCRIPT,
|
||||
});
|
||||
redisClient.defineCommand('stopBeingLeader', {
|
||||
numberOfKeys: 2,
|
||||
lua: STOP_BEING_LEADER_SCRIPT,
|
||||
});
|
||||
}
|
||||
|
||||
private async renew(): Promise<void> {
|
||||
try {
|
||||
const result = await this.redisClient.renewLeader(this.key, this.id, this.ttl);
|
||||
if (result === 'you_are_not_the_leader') {
|
||||
if (this.renewId) {
|
||||
clearInterval(this.renewId);
|
||||
}
|
||||
this.waitId = setTimeout(() => {
|
||||
this.elect();
|
||||
}, this.wait);
|
||||
this.emit(LeaderEvent.revoked);
|
||||
}
|
||||
} catch (err) {
|
||||
this.emit(LeaderEvent.error, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Leader;
|
||||
export { LeaderEvent };
|
||||
@@ -10,7 +10,7 @@ async function setSupportedSdkVersions(platform: string, sdkVersions: string[])
|
||||
method: 'POST',
|
||||
uri: href,
|
||||
headers: {
|
||||
'secret-token': config.www.sdkVersionsSecretToken,
|
||||
'secret-token': config.www.secretToken,
|
||||
},
|
||||
body: {
|
||||
platform,
|
||||
@@ -26,7 +26,7 @@ async function setTurtleVersion(version: string) {
|
||||
method: 'POST',
|
||||
uri: href,
|
||||
headers: {
|
||||
'secret-token': config.www.sdkVersionsSecretToken,
|
||||
'secret-token': config.www.secretToken,
|
||||
},
|
||||
body: {
|
||||
version,
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import { URL } from 'url';
|
||||
|
||||
import request from 'request-promise';
|
||||
|
||||
import config from 'turtle/config';
|
||||
import { saveUpdateFailure } from 'turtle/updatesManager';
|
||||
|
||||
async function sendBuildStatusUpdate(buildId: string, updateParams: object) {
|
||||
const { href } = new URL(`/--/api/v2/turtle-legacy-builds/${buildId}`, resolveWWWEndpoint());
|
||||
try {
|
||||
await request({
|
||||
method: 'PUT',
|
||||
uri: href,
|
||||
headers: {
|
||||
'secret-token': config.www.secretToken,
|
||||
},
|
||||
body: updateParams,
|
||||
json: true,
|
||||
});
|
||||
} catch (err) {
|
||||
await saveUpdateFailure(buildId, 'build', updateParams);
|
||||
}
|
||||
}
|
||||
|
||||
async function sendCredentialsUpdate(buildId: string, platform: 'android' | 'ios', updateParams: object) {
|
||||
const { href } = new URL(`/--/api/v2/turtle-legacy-builds/${buildId}/credentials`, resolveWWWEndpoint());
|
||||
try {
|
||||
await request({
|
||||
method: 'PUT',
|
||||
uri: href,
|
||||
headers: {
|
||||
'secret-token': config.www.secretToken,
|
||||
},
|
||||
body: {
|
||||
platform,
|
||||
...updateParams,
|
||||
},
|
||||
json: true,
|
||||
});
|
||||
} catch (err) {
|
||||
await saveUpdateFailure(buildId, 'credentials', updateParams);
|
||||
}
|
||||
}
|
||||
|
||||
function resolveWWWEndpoint() {
|
||||
const currentEnv = config.deploymentEnv;
|
||||
if (currentEnv === 'production') {
|
||||
return 'https://exp.host';
|
||||
} else if (currentEnv === 'staging') {
|
||||
return 'https://staging.exp.host';
|
||||
} else {
|
||||
return 'http://127.0.0.1:3000';
|
||||
}
|
||||
}
|
||||
|
||||
export { sendBuildStatusUpdate, sendCredentialsUpdate };
|
||||
+6
-1
@@ -10,5 +10,10 @@
|
||||
},
|
||||
"rulesDirectory": [
|
||||
"node_modules/tslint-eslint-rules/dist/rules"
|
||||
]
|
||||
],
|
||||
"linterOptions": {
|
||||
"exclude": [
|
||||
"src/types/xcode.d.ts"
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user