Compare commits

...
Author SHA1 Message Date
Quinlan Jung 2be2536654 Temporary Commit at 6/25/2024, 10:08:24 AM 2024-06-25 10:08:24 -07:00
Szymon Dziedzic bd0a696b4e [eas-cli] remove old Xcode images entirerly (#2438)
* [eas-cli] remove old Xcode images entirerly

* add changelog
2024-06-18 10:53:18 +02:00
dependabot[bot] 230e364379 Bump ws from 5.2.3 to 5.2.4 (#2440)
Bumps [ws](https://github.com/websockets/ws) from 5.2.3 to 5.2.4.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/5.2.3...5.2.4)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-18 10:42:49 +02:00
Expo CI eaebb72813 update CHANGELOG.md 2024-06-17 14:39:38 +00:00
Szymon Dziedzic cf39201de3 v10.0.2 2024-06-17 16:34:24 +02:00
Szymon Dziedzic bb3e815716 [eas-cli] make sure we filter out any comments in build.gradle file before passing to to gradle-to-js parser (#2435)
* [eas-cli] make sure we filter out any comments in `build.gradle` file before passing to to `gradle-to-js` parser

* use trim

* add test

* add changelog
2024-06-17 16:30:19 +02:00
Expo CI beec6ad305 update CHANGELOG.md 2024-06-17 12:28:19 +00:00
Szymon Dziedzic 84b47924b7 v10.0.1 2024-06-17 14:23:43 +02:00
Szymon Dziedzic 3ff62a9c79 upgrade eas-cli-local-build-plugin to 1.0.118 2024-06-17 14:10:32 +02:00
Expo Bot 2751a7e0de Upgrade eas-build dependencies (#2436) 2024-06-17 14:09:41 +02:00
Quinlan Jung 7139e4f576 [eas-cli] add clarification for codesigning private key flag (#2432)
* Temporary Commit at 6/14/2024, 3:59:20 PM

* pr feedback

* Temporary Commit at 6/14/2024, 5:11:26 PM
2024-06-14 17:35:00 -07:00
dependabot[bot] ecbe49abaa Bump braces from 3.0.2 to 3.0.3 (#2428)
Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3.
- [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3)

---
updated-dependencies:
- dependency-name: braces
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-13 12:15:57 +02:00
Expo CI 6af86b545f update CHANGELOG.md 2024-06-13 10:01:58 +00:00
Szymon Dziedzic a9a77b6fcb v10.0.0 2024-06-13 11:56:32 +02:00
Szymon Dziedzic 82fccc8193 upgrade eas-cli-local-build-plugin to 1.0.117 2024-06-13 11:56:16 +02:00
Szymon Dziedzic 5f800b5be6 [eas-cli] resolve correct submit profile configuration for eas build --auto-submit-with-profile (#2425)
* set `specifiedProfile` in submission context when triggering a submission from build profile

* add changelog
2024-06-12 18:43:01 +02:00
Expo BotandSzymon Dziedzic 3817e2d387 Upgrade eas-build dependencies (#2416)
* Upgrade eas-build dependencies

* add changelog entry

* fix changelog

---------

Co-authored-by: Szymon Dziedzic <[email protected]>
2024-06-10 13:14:37 +02:00
Cedric van Putten eb4c5e073d chore!: drop support for Node 16 (#2413)
* chore: update node versions to test with to 18, 20, 22

* update CHANGELOG.md

* chore(eas-cli)!: bump minimum supported Node version to 18

This makes the PR a breaking change.

* docs(eas-cli): add breaking change(log) entry

* chore: update `engines.node` to 18 everywhere
2024-06-08 15:37:56 +02:00
Cedric van Putten eefc133eda fix: update lockfile to only include @types/[email protected] (#2412)
* fix: update lockfile to only include `@types/[email protected].0`

* update CHANGELOG.md
2024-06-07 18:55:21 +02:00
Szymon Dziedzic 7f9969429d fix changelog 2024-06-07 13:53:56 +02:00
louix 26ff083b7c fix looking up process.env[process.env.EXPO_APPLE_PROVIDER_ID] (#2349) 2024-06-07 13:52:24 +02:00
Expo CI 6414361d4c update CHANGELOG.md 2024-06-06 16:58:05 +00:00
Szymon Dziedzic 28ce6b7dc7 v9.2.0 2024-06-06 18:53:10 +02:00
Szymon Dziedzic 4772f1aea5 upgrade eas-cli-local-build-plugin to 1.0.116 2024-06-06 18:53:02 +02:00
Szymon Dziedzic 2a1fd290b9 [eas-cli] add target-profile and source-profile flags to eas build:resign (#2410)
* [eas-cli] add `target-profile` and `source-profile` flags to `eas build:resign`

* update CHANGELOG.md

* fix target profile description
2024-06-06 18:47:11 +02:00
Szymon Dziedzic e83565c518 [eas-cli] make flags for eas build:list command more aligned with flags for rest of the commands (#2409)
* [eas-cli] make flags for `eas build:list` command more aligned with flags for rest of the commands

* update CHANGELOG.md
2024-06-06 18:30:29 +02:00
Szymon Dziedzic f38a739858 [eas-cli] display build profile in eas build:list command details (#2408)
* [eas-cli] display build profile in `eas build:list` command details

* update CHANGELOG.md
2024-06-06 15:06:05 +02:00
Szymon Dziedzic 3fcbcf5f6b [eas-cli] print network error message if present (#2407)
* [eas-cli] print network error message if present

* update CHANGELOG.md
2024-06-05 12:41:50 +02:00
Stanisław Chmiela 30936911ad Fix expiration date check for build list source (#2406) 2024-06-04 16:08:29 +02:00
Piotr Szeremeta a0606adde9 Remove logging of metadata file upload (#2394) 2024-06-03 14:42:42 +02:00
Szymon Dziedzic f0e3b648a1 [eas-cli] use BuildMode.REPACK for --repack builds (#2390) 2024-05-28 11:52:24 +02:00
Szymon Dziedzic 3ed5e7821e [eas-cli] use correct app config for no gh init:onboarding flow (#2397)
* [eas-cli] use correct app config for no gh `init:onboarding` flow

* update CHANGELOG.md
2024-05-28 11:51:41 +02:00
Expo CI 466339b90e update CHANGELOG.md 2024-05-23 17:20:14 +00:00
Szymon Dziedzic 1d07e08a70 v9.1.0 2024-05-23 19:15:26 +02:00
Szymon Dziedzic c21270e062 [eas-cli] make init:onboarding command public (#2399)
* [eas-cli] make `init:onboarding` command public

* update CHANGELOG.md
2024-05-23 19:11:41 +02:00
Expo CI afb548599e update CHANGELOG.md 2024-05-22 19:23:20 +00:00
Szymon Dziedzic 0b54169631 v9.0.10 2024-05-22 21:14:53 +02:00
Szymon Dziedzic af13f3987e [eas-cli] pass cwd to findProjectRootAsync in onboarding (#2398) 2024-05-22 21:13:57 +02:00
Expo CI 3ea71e57cb update CHANGELOG.md 2024-05-22 16:57:47 +00:00
Szymon Dziedzic 261dbb4be4 v9.0.9 2024-05-22 18:51:46 +02:00
Szymon Dziedzic 5dd02e2b40 log detected onboarding clone method 2024-05-22 18:50:53 +02:00
Szymon Dziedzic 9447cbc478 [eas-cli] auto detect preferred git clone method (#2396)
* [eas-cli] ask user for prefered `git clone` method when running onboarding

* use `git ls-remote` to detect whether one has ssh auth set up
2024-05-22 18:49:28 +02:00
Stanisław Chmiela 562bd3fe9c [eas-cli] Update default onboarding eas.json (#2393) 2024-05-22 11:34:18 +02:00
Expo CI d6840de401 update CHANGELOG.md 2024-05-21 13:49:48 +00:00
Szymon Dziedzic d9bd20a47b v9.0.8 2024-05-21 15:42:39 +02:00
Szymon Dziedzic 13da8d4bfc [eas-cli] display device registration qr code better (#2391)
* [eas-cli] display device registration qr code better

* update CHANGELOG.md
2024-05-21 15:06:56 +02:00
Expo BotandSzymon Dziedzic a99fe9aef5 Upgrade eas-build dependencies (#2387)
* Upgrade eas-build dependencies

* update CHANGELOG.md

* fix types

---------

Co-authored-by: Szymon Dziedzic <[email protected]>
2024-05-21 01:46:37 +02:00
Expo CI 61109ea2c1 update CHANGELOG.md 2024-05-17 07:32:39 +00:00
Szymon Dziedzic f889929f5f v9.0.7 2024-05-17 09:27:12 +02:00
Szymon Dziedzic 4bb314192e upgrade eas-cli-local-build-plugin to 1.0.112 2024-05-17 09:27:05 +02:00
Szymon Dziedzic 1a170283db [eas-cli] add --repack flag to eas build command (#2384)
* [eas-cli] add `--repack` flag to `eas build` command

* update Android prepare job
2024-05-17 09:18:38 +02:00
Expo CI ca803eed3f update CHANGELOG.md 2024-05-15 10:57:34 +00:00
Stanisław Chmiela 4b26472975 v9.0.6 2024-05-15 12:52:40 +02:00
Stanisław Chmiela 70b854abb1 [eas-cli] Add turtleJobRunId to UpdatePublishMutation input (#2381)
<!-- If this PR requires a changelog entry, add it by commenting the PR with the command `/changelog-entry [breaking-change|new-feature|bug-fix|chore] [message]`. -->
<!-- You can skip the changelog check by labeling the PR with "no changelog". -->

# Why

We want to save the relationship between a job run and an update.

# How

See https://github.com/expo/universe/pull/15329.

# Test Plan

Tested with staging.
2024-05-15 12:51:49 +02:00
Expo CI 2576a97704 update CHANGELOG.md 2024-05-13 15:59:00 +00:00
Szymon Dziedzic 15e50b1536 v9.0.5 2024-05-13 17:53:24 +02:00
Szymon Dziedzic d6f3784cc0 [eas-cli] install dependencies before resolving expo config (#2380) 2024-05-13 17:52:23 +02:00
Expo CI a6f7d37d71 update CHANGELOG.md 2024-05-13 14:54:54 +00:00
Szymon Dziedzic 675c36a157 v9.0.4 2024-05-13 16:49:55 +02:00
Bartosz Kaszubowski b2961a275b [eas-cli] diagnostics: add loader and progress information (#2378)
* [eas-cli] diagnostics: add loader and progress information

* add changelog entry
2024-05-13 16:47:13 +02:00
Szymon Dziedzic 57928d1fd6 [eas-cli] create keystore for Android emulator builds in init:onboarding (#2379)
* [eas-cli] create keystore for Android emulator builds in `init:onboarding`

* use correct build profile
2024-05-13 16:46:32 +02:00
Szymon Dziedzic ff9d533248 [eas-cli] add init:onboarding flow for no gh repo connected (#2373)
* [eas-cli] add `init:onboarding` flow for no gh repo connected

* fix types

* don't wait
2024-05-13 16:43:13 +02:00
Expo CI e1ebcc0b8a update CHANGELOG.md 2024-05-10 17:38:09 +00:00
Stanisław Chmiela 628a7262cf v9.0.3 2024-05-10 19:33:08 +02:00
Stanisław Chmiela 05be162ec1 [eas-cli] Prevent ora flooding logs (#2375)
<!-- If this PR requires a changelog entry, add it by commenting the PR with the command `/changelog-entry [breaking-change|new-feature|bug-fix|chore] [message]`. -->
<!-- You can skip the changelog check by labeling the PR with "no changelog". -->

# Why

I noticed logs look off in CI when running `eas update --auto`.

<img width="1000" alt="Zrzut ekranu 2024-05-10 o 17 50 10" src="https://github.com/expo/eas-cli/assets/1151041/ed50d014-62f1-4342-bde2-0673f49d52b4">

# How

I pinpointed it to Ora being restarted on every log.

# Test Plan

Ran `CI=1 easd update --auto` and got ⬇️ which I think is much more readable.

```
CI=1 easd update --auto
- Exporting...
[expo-cli] Starting Metro Bundler
[expo-cli] Android Bundling complete 3492ms
[expo-cli] iOS Bundling complete 3493ms
[expo-cli] iOS Building Hermes bytecode for the bundle
[expo-cli] Android Building Hermes bytecode for the bundle
[expo-cli] 
[expo-cli] Bundle                      Size
[expo-cli] ┌ index.ios.hbc           858 kB
[expo-cli] ├ index.android.hbc       864 kB
[expo-cli] ├ index.ios.hbc.map      3.45 MB
[expo-cli] └ index.android.hbc.map  3.48 MB
[expo-cli] 
[expo-cli] 💡 JavaScript bundle sizes affect startup time. Learn more: https://expo.fyi/javascript-bundle-sizes
[expo-cli] Finished saving JS Bundles
[expo-cli] Dumping asset map
[expo-cli] Dumping source maps
[expo-cli] Preparing additional debugging files
[expo-cli] Export was successful. Your exported files can be found in dist
✔ Exported bundle(s)
- Uploading...
✔ Uploaded 2 app bundles
✔ Uploading assets skipped - no new assets found
ℹ 1 iOS asset, 1 Android asset (maximum: 20000 total per update). Learn more about asset limits: https://expo.fyi/eas-update-asset-limits
- Publishing...
✔ Published!
```
2024-05-10 19:31:55 +02:00
Bartosz Kaszubowski ff2fa425bd [eas-cli] fix typo in onboarding commit message (#2376) 2024-05-10 19:19:13 +02:00
Expo Bot a621e395fc Upgrade eas-build dependencies (#2372) 2024-05-10 17:53:25 +02:00
Stanisław Chmiela 2260f74434 s/Website link/EAS Dashboard when displaying update info (#2374)
<!-- If this PR requires a changelog entry, add it by commenting the PR with the command `/changelog-entry [breaking-change|new-feature|bug-fix|chore] [message]`. -->
<!-- You can skip the changelog check by labeling the PR with "no changelog". -->

# Why

Implementing @tchayen's suggestion.

# How

Changed wording

# Test Plan

None.
2024-05-10 17:47:31 +02:00
Szymon Dziedzic 6dc9253d2d [eas-cli] improve prompt asking user to specify target clone dir in eas init:onboarding (#2371) 2024-05-10 14:56:51 +02:00
Expo CI b6570bdfcf update CHANGELOG.md 2024-05-09 17:44:21 +00:00
Szymon Dziedzic 4d1675c96f v9.0.2 2024-05-09 19:39:29 +02:00
Szymon Dziedzic 00d9009967 [eas-cli] make sure that spinner is not used for interactive git clone command in inint:onboarding and fallback to cloning via https (#2368)
* [eas-cli] make sure that spinner is not used for interactive `git clone` command in `inint:onboarding`

* fallback to https
2024-05-09 19:38:48 +02:00
Szymon Dziedzic b68840b76b fix eas-json bump workflow 2024-05-09 18:47:49 +02:00
Expo CI 6d8be295bf update CHANGELOG.md 2024-05-09 14:12:44 +00:00
Piotr Szeremeta 40c1cbe9f6 v9.0.1 2024-05-09 16:07:32 +02:00
Szymon Dziedzic efae679089 [eas-cli] improvements to eas onboarding after dogfooding (#2367) 2024-05-09 15:05:32 +02:00
Szymon Dziedzic 6a2a3fe037 [eas-json] update image tags in eas.schema.json (#2363)
* [eas-json] update image tags in `eas.schema.json`

* update CHANGELOG.md

* [eas-json] delete detailed image descriptions for `sdk-xy` tags
2024-05-09 14:55:35 +02:00
Tomasz Czajęcki 917987a41e [eas-cli] fix onboarding mutation (#2365)
* fix onboarding mutation

* Skip passing __typename
2024-05-09 14:48:09 +03:00
Bartosz Kaszubowski bbe8fb9698 [eas-cli] onboarding logs content tweaks (#2366) 2024-05-09 13:09:59 +02:00
Szymon Dziedzic d656103357 fix update eas-json in universe workflow 2024-05-08 17:04:42 +02:00
Expo CI 4b7ad9f23a update CHANGELOG.md 2024-05-08 15:01:08 +00:00
Szymon Dziedzic 4db3979ab5 v9.0.0 2024-05-08 16:56:18 +02:00
Szymon Dziedzic 63e0bf2a24 upgrade eas-cli-local-build-plugin to 1.0.107 2024-05-08 16:55:54 +02:00
Szymon Dziedzic a740aa174b [ENG-12115][eas-cli] add eas onboarding flow (#2338)
* [eas-cli] add eas onboarding flow

* mark command as hidden and prompt user before starting any action

* add gql queries

* regenerate gql schema

* fix type issues

* mark isCLIDone as true

* apply suggested changes

* improvements after cr

* more improvements
2024-05-08 16:52:14 +02:00
Szymon Dziedzic f9ef83ba52 [eas-cli] don't allow to specify custom global version of deprecated expo-cli (#2361)
* [eas-cli] don't allow to specify custom global version of deprecated `expo-cli`

* update CHANGELOG.md

* update dependencies

* print a warning vs throwing an error

* mark as deprecated

* print warning nicer

* fix changelog entry

* fix changelog
2024-05-08 12:48:26 +02:00
Expo BotandStanisław Chmiela de8956c2ec Upgrade eas-build dependencies (#2360)
* Upgrade eas-build dependencies

* update CHANGELOG.md

* Fix typecheck

---------

Co-authored-by: Stanisław Chmiela <[email protected]>
2024-05-08 10:21:20 +02:00
Will Schurman 41622c0cd3 [eas-cli] Pass env from process.env and build profile to expo-updates CLI calls where applicable (#2359) 2024-05-06 09:06:27 -07:00
Quinlan Jung d54abee7c3 [ENG-8801][eas-cli] allow modification of provisioning profile in CI, add --freeze-credentials flag (#2347)
* freeze creds flag

* allow profile to be modified in non interactive mode

* Temporary Commit at 4/24/2024, 4:15:30 PM

* Temporary Commit at 4/25/2024, 4:33:46 PM

* Temporary Commit at 4/25/2024, 5:24:12 PM

* update CHANGELOG.md

* Temporary Commit at 4/25/2024, 6:30:26 PM

* Temporary Commit at 5/2/2024, 1:10:17 PM
2024-05-02 13:38:42 -07:00
Will Schurman cdd046b647 [eas-cli] Remove more classic updates code (#2357) 2024-05-02 11:01:48 -07:00
dependabot[bot] 4577cf957d Bump ejs from 3.1.8 to 3.1.10 (#2356)
Bumps [ejs](https://github.com/mde/ejs) from 3.1.8 to 3.1.10.
- [Release notes](https://github.com/mde/ejs/releases)
- [Commits](https://github.com/mde/ejs/compare/v3.1.8...v3.1.10)

---
updated-dependencies:
- dependency-name: ejs
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-01 13:48:50 +02:00
Expo CI 84b56f86eb update CHANGELOG.md 2024-05-01 10:24:12 +00:00
Szymon Dziedzic b2580d0cc2 v8.0.0 2024-05-01 12:19:32 +02:00
Szymon Dziedzic 0f18ea01a9 upgrade eas-cli-local-build-plugin to 1.0.102 2024-05-01 12:19:22 +02:00
Szymon Dziedzic fe9927862c [ENG-12122][eas-cli] don't prompt users to set push notifications by default if they don't have the expo-notifications installed (#2343)
* [eas-cli] don't prompt to set up push notifications if `promptToConfigurePushNotifications` is `undefined` and `expo-notifications` is not present

* update eas.schema.json

* update CHANGELOG.md
2024-05-01 10:23:48 +02:00
lzkb bc2f6e60f4 [eas-cli] Show the -s, --sso option in the login command help. (#2353)
* Show the -s, --sso option in the login command help.

* Update CHANGELOG
2024-04-29 19:54:03 -07:00
Will Schurman 6ac1e54f67 [eas-cli] Improve login info message for other login options (#2352) 2024-04-29 08:56:10 -07:00
Expo Bot 479e8d0b5d Upgrade eas-build dependencies (#2351)
* Upgrade eas-build dependencies

* update CHANGELOG.md
2024-04-29 16:45:27 +02:00
Quinlan Jung 7ed62ec7f1 [ENG-11658][eas-cli] dont generate channel on eas update without flag (#2346)
* Temporary Commit at 4/25/2024, 2:50:35 PM

* update CHANGELOG.md
2024-04-26 11:23:26 -07:00
Expo CI 87000c36c1 update CHANGELOG.md 2024-04-26 16:40:41 +00:00
Szymon Dziedzic a9d08f39ad v7.8.5 2024-04-26 18:35:33 +02:00
Szymon Dziedzic 55c156dd00 Revert "v7.8.5"
This reverts commit 85de580d84.
2024-04-26 18:33:59 +02:00
Szymon Dziedzic 736d414cd6 [ci] fix build macos workflow (#2348) 2024-04-26 18:33:00 +02:00
Szymon Dziedzic 85de580d84 v7.8.5 2024-04-26 17:07:23 +02:00
Szymon Dziedzic 1a65b2cc4e [ENG-12118][eas-cli] improve error message if server returns UNAUTHORIZED_ERROR (#2345)
* [eas-cli] improve error message if server returns `UNAUTHORIZED_ERROR`

* update CHANGELOG.md
2024-04-26 12:35:26 +02:00
Will Schurman b3fca978d0 [eas-cli] Fill in min expo-updates version for expo-updates CLI (#2344) 2024-04-25 09:18:13 -07:00
Szymon Dziedzic ba4c4e5954 fix changelog 2024-04-24 18:38:13 +02:00
Will Schurman 383caa0354 [eas-cli] Add explicit workflow arg to expo-update CLI calls (#2340) 2024-04-24 09:15:37 -07:00
Szymon Dziedzic 2e43d4bba0 v7.8.4 2024-04-24 18:13:54 +02:00
Szymon Dziedzic b995d1d713 upgrade eas-cli-local-build-plugin to 1.0.101 2024-04-24 18:13:47 +02:00
Szymon Dziedzic d307f2343b [ENG-12120][eas-cli] make multi-select for revoking distribution certificates more readable (#2342)
* [eas-cli] make multi-select for revoking distribution certificates more readable

* update CHANGELOG.md
2024-04-24 18:03:07 +02:00
Szymon Dziedzic 9eeaee544a [ENG-12116][eas-cli] improve error message displayed when EAS CLI version doesn't satisfy minimal version required specified in eas.json (#2341)
* [eas-cli] improve error message displayed when EAS CLI version doesn't satisfy minimal version required specified in `eas.json`

* fix typo

* update CHANGELOG.md
2024-04-24 17:58:55 +02:00
Radosław Krzemień d9092e15f2 [eas-cli] [ENG-11602] Update eas.schema.json (#2337)
* [eas-cli] Update eas.schema.json

Updated the eas.schema.json with the current image values for Android images

See: https://linear.app/expo/issue/ENG-11310/fix-warnings-errors-that-come-up-when-adding-eas-to-a-react-native-cli

* [eas-cli] Update eas.schema.json

Updated the eas.schema.json with the current image values for Android images

See: https://linear.app/expo/issue/ENG-11602/preinstall-gradle-and-ndks-used-in-the-3-latests-sdks-on-android

* [eas-cli] Update eas.schema.json

Returned the auto option

See: https://linear.app/expo/issue/ENG-11602/preinstall-gradle-and-ndks-used-in-the-3-latests-sdks-on-android

* [eas-cli] Update eas.schema.json

Updated descriptions

See: https://linear.app/expo/issue/ENG-11602/preinstall-gradle-and-ndks-used-in-the-3-latests-sdks-on-android

* [eas-cli] Update eas.schema.json

Removed stable option

See: https://linear.app/expo/issue/ENG-11602/preinstall-gradle-and-ndks-used-in-the-3-latests-sdks-on-android

* update CHANGELOG.md
2024-04-23 20:17:30 +02:00
Expo CI f90f085dcc update CHANGELOG.md 2024-04-23 15:33:25 +00:00
Szymon Dziedzic 61bb001059 v7.8.3 2024-04-23 17:25:28 +02:00
Szymon Dziedzic 9ef86f51fa [ENG-12057][eas-cli] don't prompt user to set android.package and ios.bundleIdentifier value when runing in non-interactive mode (#2336)
* [eas-cli] don't prompt user to set `android.package` and `ios.bundleIdentifier` value when runing in non-interactive mode

* update CHANGELOG.md

* rename test
2024-04-23 17:16:29 +02:00
Quinlan Jung 44cd3b2669 [eas-cli] amend credential removal wording (#2334)
* Temporary Commit at 4/18/2024, 8:40:55 PM

* update CHANGELOG.md
2024-04-19 10:41:18 -07:00
Szymon Dziedzic 0c706048be [ENG-9817][ci] bump @expo/eas-json version in universe after the release (#2142)
* [ci] bump `@expo/eas-json` version in universe after the release

* Update .github/workflows/release.yml

* test

* edit eas.json

* Revert "edit eas.json"

This reverts commit 3979a1b1fb.

* Revert "test"

This reverts commit 69db39f548.
2024-04-19 10:22:44 +02:00
Expo CI 211a3fb6bf update CHANGELOG.md 2024-04-15 18:29:07 +00:00
Szymon Dziedzic baeb88f5be v7.8.2 2024-04-15 20:23:12 +02:00
Szymon Dziedzic ec3c27f744 upgrade eas-cli-local-build-plugin to 1.0.100 2024-04-15 20:21:47 +02:00
Szymon Dziedzic 054732c245 Revert "v7.8.2"
This reverts commit 0f45f938b1.
2024-04-15 20:18:21 +02:00
Szymon Dziedzic 70c876776d [ci] use correct workingdir for getting x86 macos build (#2331) 2024-04-15 20:12:05 +02:00
Quinlan Jung 0f45f938b1 v7.8.2 2024-04-15 10:32:58 -07:00
Quinlan Jung c8313f36e7 [ENG-11823][2/2] move credentials endpoints to paginated (#2327)
* [eas-cli] move credentials endpoints to paginated

* switch over android creds to paginated endpoints

* update CHANGELOG.md
2024-04-15 10:19:15 -07:00
Quinlan Jung a8cde5e81d [1/2][eas-cli] paginated progress bar (#2326)
* [eas-cli] paginated progress bar

* update CHANGELOG.md
2024-04-15 10:11:29 -07:00
Will Schurman d05142f9fc [eas-cli] Fix display of errors when expo-updates CLI command fails (#2324) 2024-04-12 13:36:54 -07:00
Szymon Dziedzic 8e26c7c508 [ci] build darwin-arm64 executable as well when releasing new EAS CLI version (#2323) 2024-04-12 18:43:58 +02:00
Expo CI c29018df20 update CHANGELOG.md 2024-04-11 10:04:02 +00:00
Szymon Dziedzic 8b7d977b5b v7.8.1 2024-04-11 11:56:23 +02:00
Szymon Dziedzic 12f98c2471 upgrade eas-cli-local-build-plugin to 1.0.97 2024-04-11 11:56:17 +02:00
Szymon Dziedzic d6186edb69 [eas-cli] stop querying Build.resourceClass (#2320)
* [eas-cli] stop querying `Build.resourceClass`

* update CHANGELOG.md
2024-04-11 11:45:20 +02:00
dependabot[bot] b20cf472bf Bump tar from 6.2.0 to 6.2.1 (#2319)
Bumps [tar](https://github.com/isaacs/node-tar) from 6.2.0 to 6.2.1.
- [Release notes](https://github.com/isaacs/node-tar/releases)
- [Changelog](https://github.com/isaacs/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/isaacs/node-tar/compare/v6.2.0...v6.2.1)

---
updated-dependencies:
- dependency-name: tar
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-11 11:42:01 +02:00
Szymon Dziedzic 0ab64d5eaa [eas-cli] fix README.md command files URLs (#2318)
* [eas-cli] fix `README.md` command files URLs

* update CHANGELOG.md
2024-04-11 11:41:36 +02:00
Expo Bot 40afed198f Upgrade eas-build dependencies (#2316)
* Upgrade eas-build dependencies

* update CHANGELOG.md
2024-04-08 21:13:53 +02:00
Expo CI 5337929696 update CHANGELOG.md 2024-04-08 12:37:01 +00:00
Szymon Dziedzic 4c97fc31f8 v7.8.0 2024-04-08 14:29:06 +02:00
Szymon Dziedzic 42252cd355 upgrade eas-cli-local-build-plugin to 1.0.96 2024-04-08 14:28:59 +02:00
Szymon Dziedzic 784b52bddb [eas-cli] add --build-logger-level flag to eas build command (#2313)
* [eas-cli] add `--build-logger-level` flag to `eas build` command

* update CHANGELOG.md

* fix types

* fix changelog

* apply suggestions from cr

* fix changelog
2024-04-08 14:11:47 +02:00
Szymon Dziedzic d85b3283f0 [eas-cli] mark default image tag and old images as deprecated and add new image tags to eas.schema.json (#2298)
* [eas-cli] mark `default` image tag as deprecated

* add new image tags to `eas.schema.json`

* update CHANGELOG.md

* update CHANGELOG.md

* deprecate JDK 8 and NDK r19c images

* update CHANGELOG.md

* use better warn message for Xcode < 14 images and link to our changelog post

* update warn message

* don't deprecate Androdi images in this PR

* fix changelog

* use correct latest image
2024-04-08 12:15:03 +02:00
Expo CI 0c332eb6d3 update CHANGELOG.md 2024-04-05 19:24:01 +00:00
Szymon Dziedzic 26bb7052ef v7.7.0 2024-04-05 21:16:01 +02:00
Szymon Dziedzic 8333d3361a upgrade eas-cli-local-build-plugin to 1.0.95 2024-04-05 21:15:52 +02:00
Szymon Dziedzic f62a8cad27 [eas-json] add Xcode 15.3 image (#2312)
* [eas-json] add Xcode 15.3 image

* update CHANGELOG.md

* fix changelog
2024-04-05 20:30:22 +02:00
Piotr Szeremeta b52145c0a7 Fix project metadata spinner persisting after upload (#2311) 2024-04-03 17:18:01 +02:00
Piotr SzeremetaandSzymon Dziedzic e06fc189aa [ENG-11445] Add '--verbose-fastlane' flag for verbose fastlane logs (#2276)
* [ENG-11445] Add verbose-fastlane flag for verbose fastlane logs

Make isVerboseFastlaneEnabled required parameter

Co-authored-by: Szymon Dziedzic <[email protected]>

* update CHANGELOG.md

* [ENG-11445] Add verbose-fastlane for android builds

* [ENG-11445] Update graphql

* [ENG-11445] Fix tests

---------

Co-authored-by: Szymon Dziedzic <[email protected]>
2024-04-03 12:05:12 +02:00
Piotr Szeremeta b346f96c63 [ENG-10412] Upload projectMetadata file (#2149)
* [ENG-10412] Upload projectMetadata file

* Lint

* [ENG-10412] Apply review suggestions

* update graphql
2024-04-03 11:47:44 +02:00
Juwan Wheatley 26ba0719ce [eas-cli] add a credentials:configure-build subcommand that prepares a project for EAS Build without executing the build from the CLI (#2282)
* [eas-cli] create new `init-build` command under the `credentials` topic

* get hacky version of cli command working

* add all option to flag

* extend the Manage<Platform> actions to reduce code duplication

* prompt user for platform if it doesn't exist

* prompt the user to choose a profile

* add a changelog entry

* call SetUpBuildCredentials for android
2024-03-28 15:55:19 -04:00
dependabot[bot] c33dff99d2 Bump express from 4.18.2 to 4.19.2 (#2302)
Bumps [express](https://github.com/expressjs/express) from 4.18.2 to 4.19.2.
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/master/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.18.2...4.19.2)

---
updated-dependencies:
- dependency-name: express
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-28 08:48:50 +01:00
Expo BotandStanisław Chmiela 3d7d851d07 Upgrade eas-build dependencies (#2304)
Co-authored-by: Stanisław Chmiela <[email protected]>
2024-03-27 21:29:08 +01:00
Expo CI fad3f1346c update CHANGELOG.md 2024-03-27 16:02:19 +00:00
Stanisław Chmiela dece2e5242 v7.6.2 2024-03-27 16:55:26 +01:00
Expo Bot f579441e05 Upgrade eas-build dependencies (#2301) 2024-03-27 16:53:41 +01:00
Expo CI e40634297b update CHANGELOG.md 2024-03-25 14:02:09 +00:00
Szymon Dziedzic 17ea5d4f01 v7.6.1 2024-03-25 14:55:03 +01:00
Szymon Dziedzic d803e52085 upgrade eas-cli-local-build-plugin to 1.0.89 2024-03-25 14:54:43 +01:00
Expo Bot e400515fa7 Upgrade eas-build dependencies (#2293)
* Upgrade eas-build dependencies

* update CHANGELOG.md
2024-03-22 17:04:55 +01:00
Szymon Dziedzic e6233b3028 [eas-cli] use GitNoCommitClient for eas build:internal command (#2295)
* [eas-cli] use `GitNoCommitClient` for `eas build:internal` command

* Revert "[eas-cli] use `GitNoCommitClient` for `eas build:internal` command"

This reverts commit d83a9a5a5e.

* fix resolving vcs client in context

* update CHANGELOG.md

* fix tests
2024-03-22 16:55:49 +01:00
Quinlan Jung eec975c171 [eas-cli] fix asset limit punctuation (#2296)
* Temporary Commit at 3/21/2024, 12:10:10 PM

* update CHANGELOG.md
2024-03-21 13:08:55 -07:00
Expo Bot 08ea07bf5c Upgrade eas-build dependencies (#2291)
* Upgrade eas-build dependencies

* update CHANGELOG.md
2024-03-18 17:52:07 +01:00
Expo CI e5d94ad15c update CHANGELOG.md 2024-03-18 16:23:58 +00:00
Szymon Dziedzic a51fbd37ca v7.6.0 2024-03-18 17:16:25 +01:00
Szymon Dziedzic 1c78e09676 upgrade eas-cli-local-build-plugin to 1.0.86 2024-03-18 17:16:11 +01:00
Szymon Dziedzic d1edec6549 [eas-cli] bump @expo/apple-utils to switch between developer.apple.com and developer-mdn.apple.com domains when one of them doesn't work (#2290)
* [eas-cli] bump `@expo/apple-utils` to switch between `developer.apple.com` and `developer-mdn.apple.com` domains when one of them is not working

* update CHANGELOG.md

* bump version
2024-03-18 17:12:06 +01:00
Szymon Dziedzic ab6483f7a5 [eas-cli] send a path to custom build config to EAS Build server with posix separator for Windows (#2285)
* [eas-cli] send a path to custom build config to EAS Build server with posix separator for Windows

* add process.platform to if statement

* update CHANGELOG.md

* apply suggestions from cr

* remove unnecessary check

* apply suggested change
2024-03-18 17:00:49 +01:00
Stanisław Chmiela 32848f6255 Log dirty files in non-interactive when bailing (#2288) 2024-03-18 13:03:42 +01:00
dependabot[bot] 7e2aae333d Bump follow-redirects from 1.15.4 to 1.15.6 (#2284)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.4 to 1.15.6.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.4...v1.15.6)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-15 10:29:05 +01:00
Expo Bot 191cb2396c Upgrade eas-build dependencies (#2283) 2024-03-14 21:54:34 +01:00
Expo Bot 33fb5fad03 Upgrade eas-build dependencies (#2277)
* Upgrade eas-build dependencies

* update CHANGELOG.md
2024-03-12 10:59:51 +01:00
Expo CI 3ec6e5dd14 update CHANGELOG.md 2024-03-11 11:38:53 +00:00
Szymon Dziedzic b6acbf05d8 v7.5.0 2024-03-11 12:31:11 +01:00
Szymon Dziedzic 957874d8cc upgrade eas-cli-local-build-plugin to 1.0.83 2024-03-11 12:31:01 +01:00
Expo Bot 1a5fbc2342 Upgrade eas-build dependencies (#2274)
* Upgrade eas-build dependencies

* update CHANGELOG.md
2024-03-11 12:29:22 +01:00
Szymon Dziedzic 68cd7e6fba [ENG-11416][eas-cli] add --auto-submit flag to eas build:internal command (#2271)
* [eas-cli] add `--auto-submit` option to `eas build:internal` command

fix types

revert unnecessary changes

one more revert

* update CHANGELOG.md

* try to fix changelog

* try again

* fix changelog
2024-03-10 17:24:50 +01:00
Expo CI 628a3f708a update CHANGELOG.md 2024-03-10 02:57:28 +00:00
Brent Vatne 3ac45f08ba v7.4.0 2024-03-09 18:50:50 -08:00
Brent Vatne 73ba19de66 [eas-cli] Bump @expo/apple-utils 2024-03-09 18:50:16 -08:00
Will Schurman ef6623cd15 [eas-cli] Use new expo-updates configuration:syncnative for versioned native sync (#2269) 2024-03-08 14:27:12 -08:00
Will Schurman d78917b947 Revert "Revert "[eas-cli] Use expo-updates runtime version CLI to generate runtime ve…" (#2264)" (#2265) 2024-03-07 08:55:53 -08:00
Will Schurman 2b59a5e2ee Revert "[eas-cli] Use expo-updates runtime version CLI to generate runtime ve…" (#2264)
This reverts commit 561e3bbb5a.
2024-03-06 09:13:20 -08:00
Expo Bot e6465cd3e5 Upgrade eas-build dependencies (#2259)
* Upgrade eas-build dependencies

* update CHANGELOG.md
2024-03-05 15:07:24 +01:00
Will Schurman 561e3bbb5a [eas-cli] Use expo-updates runtime version CLI to generate runtime versions (#2251) 2024-02-28 09:27:14 -08:00
dependabot[bot] 64a6e3a0f7 Bump es5-ext from 0.10.53 to 0.10.63 (#2255)
Bumps [es5-ext](https://github.com/medikoo/es5-ext) from 0.10.53 to 0.10.63.
- [Release notes](https://github.com/medikoo/es5-ext/releases)
- [Changelog](https://github.com/medikoo/es5-ext/blob/main/CHANGELOG.md)
- [Commits](https://github.com/medikoo/es5-ext/compare/v0.10.53...v0.10.63)

---
updated-dependencies:
- dependency-name: es5-ext
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-27 09:07:36 +01:00
Will Schurman 33c965b236 [vscode] Include src/**/build directories in search and replace (#2250) 2024-02-26 10:19:35 -08:00
Expo Bot 831e69e5c6 Upgrade eas-build dependencies (#2253)
* Upgrade eas-build dependencies

* update CHANGELOG.md
2024-02-26 17:09:09 +01:00
Stanisław Chmiela 7d47060b12 Add config property to eas.schema.json (#2248)
# Why

We want users to feel like they're adding something we support.

# How

Added `config` property to build profile level and platform-specific profile properties levels.

Also prettified the file according to my JSON Tools VS Code extension. Let me know if it should be deprettified.

# Test Plan

None.
2024-02-23 17:24:35 +01:00
Will Schurman b6b22b79c3 [eas-cli] Fix expo-updates package version detection for canaries (#2243) 2024-02-22 08:14:24 -08:00
Expo Bot 6770cd99c9 Upgrade eas-build dependencies (#2240)
* Upgrade eas-build dependencies

* update CHANGELOG.md
2024-02-21 11:48:12 +01:00
dependabot[bot] 704745b829 Bump ip from 1.1.5 to 1.1.9 (#2238)
Bumps [ip](https://github.com/indutny/node-ip) from 1.1.5 to 1.1.9.
- [Commits](https://github.com/indutny/node-ip/compare/v1.1.5...v1.1.9)

---
updated-dependencies:
- dependency-name: ip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-20 21:37:49 +01:00
Quinlan Jung 3780e2ae1c [eas-cli] reword the update configure instruction (#2234)
* [eas-cli] reword the update configure instruction

* nits

* update CHANGELOG.md
2024-02-20 10:58:11 -07:00
Expo Bot e93854d039 Upgrade eas-build dependencies (#2237)
⬆️ Upgrades [`eas-build`](https://github.com/expo/eas-build) dependencies.
2024-02-20 14:23:24 +01:00
Expo CI 89354f5932 update CHANGELOG.md 2024-02-19 16:25:41 +00:00
Szymon Dziedzic a074ce0cff v7.3.0 2024-02-19 17:18:11 +01:00
Szymon Dziedzic 31f583442a upgrade eas-cli-local-build-plugin to 1.0.71 2024-02-19 17:18:03 +01:00
Radosław Krzemień 9bf1f383e5 [eas-cli] [ENG-11310] Don't require expo on fresh react-native project (#2235)
* [eas-cli] Don't require expo

Do not require expo to be installed and configured for a fresh react-native project

See: https://linear.app/expo/issue/ENG-11310/fix-warnings-errors-that-come-up-when-adding-eas-to-a-react-native-cli

* update CHANGELOG.md

* [eas-cli] Throw other errors

Forgot to rethrow other types of errors

See: https://linear.app/expo/issue/ENG-11310/fix-warnings-errors-that-come-up-when-adding-eas-to-a-react-native-cli
2024-02-19 16:44:07 +01:00
Will Schurman e157473f41 [eas-cli] fix expo-updates fingerprinting during update (#2231) 2024-02-16 14:09:40 -08:00
Expo Bot ba87bb6e29 Upgrade eas-build dependencies (#2230)
* Upgrade eas-build dependencies

* update CHANGELOG.md
2024-02-16 11:12:42 +01:00
Expo Bot efd9213fab Upgrade eas-build dependencies (#2229) 2024-02-14 17:33:56 +01:00
Expo CI a3d9bc0eca update CHANGELOG.md 2024-02-11 04:48:40 +00:00
Brent Vatne 39dc6299d2 v7.2.0 2024-02-10 20:42:08 -08:00
Brent Vatne 37573bed50 Bump @xpo/apple-utils 2024-02-10 20:40:58 -08:00
Will Schurman 2e49f6348e Revert "feat(eas-cli): expose expo export dev flag as an option in eas update (#2050)" (#2214) 2024-02-08 12:38:16 -08:00
Expo BotandSzymon Dziedzic 3a7ddbd025 Upgrade eas-build dependencies (#2223)
* Upgrade eas-build dependencies

* update CHANGELOG.md

* fix type errors

---------

Co-authored-by: Szymon Dziedzic <[email protected]>
2024-02-08 10:40:58 +01:00
Chris Walter a5c1100ce1 [fcmv1] Manage FCM V1 Google Service Account Key in CLI (#2197)
* [fcmv1] Manage FCM V1 Google Service Account Key in CLI

# Why
NOTE: DO NOT LAND THIS UNTIL GRAPHQL CHANGES LAND IN WWW

We're adding support for FCM V1 credentials, as Google is shutting down
the FCM Legacy API for sending Android notifications in June.

# How
Add new prompts and refactor existing prompts to match this schematic:

# Test Plan
Verified all functionality e2e:

* update CHANGELOG.md
2024-02-07 15:26:56 -08:00
Expo CI 0b71812694 update CHANGELOG.md 2024-02-07 12:34:16 +00:00
Stanisław Chmiela caf2403dfd v7.1.3 2024-02-07 13:24:16 +01:00
Expo Bot 09fe5dd1a3 Upgrade eas-build dependencies (#2220) 2024-02-07 12:39:31 +01:00
Stanisław Chmiela 048460f323 Add workflow for bumping eas-build dependencies (#2216)
<!-- If this PR requires a changelog entry, add it by commenting the PR with the command `/changelog-entry [breaking-change|new-feature|bug-fix|chore] [message]`. -->
<!-- You can skip the changelog check by labeling the PR with "no changelog". -->

# Why

It is currently not possible to use `if: ${ always() }` in Custom Build workflows due to outdated `@expo/steps` dependency.

# How

Added a GitHub workflow, similar to the one we have in `turtle-v2`, which will automatically upgrade all dependencies from the `eas-build` repo.

# Test Plan

https://github.com/expo/eas-cli/pull/2220
2024-02-07 12:39:19 +01:00
Radosław Krzemień 69b0edae8d [eas-cli] [ENG-9957] Reapply changes after fixing query in www (#2209)
* Revert "Revert "[eas-cli] [ENG-9957] Don't overwrite distribution for simulator build…" (#2207)"

This reverts commit a6e281b6

* [eas-cli] Generate schema

Re-generated gql schema

See: https://linear.app/expo/issue/ENG-11247/fix-console-output-when-creating-asc-key
2024-02-05 11:37:39 +01:00
Szymon Dziedzic 9ee9ea39bb [ci] auto update EAS CLI version used on production for builds triggered using GitHub trigger (#2211)
* [ci] add update eas cli used on production for builds triggered with GitHub trigger once new version is published

* remove unnecessary docs from releasing
2024-02-01 23:26:17 +01:00
Radosław Krzemień 204a8b7eb4 [eas-cli] [ENG-11247] Remove duplicate log (#2208)
* [eas-cli] Remove duplicate log

Information about App Store Connect API key being created was displayed twice to the user. This removes the duplicate

See: https://linear.app/expo/issue/ENG-11247/fix-console-output-when-creating-asc-key

* update CHANGELOG.md
2024-02-01 12:28:45 +01:00
Szymon Dziedzic a6e281b6c8 Revert "[eas-cli] [ENG-9957] Don't overwrite distribution for simulator build…" (#2207)
This reverts commit 315b5b23f8.
2024-01-31 21:06:37 +01:00
Radosław Krzemień 315b5b23f8 [eas-cli] [ENG-9957] Don't overwrite distribution for simulator builds (#2073)
* [eas-cli] Update dependencies

Updated eas-build-job to new version

See: https://linear.app/expo/issue/ENG-9957/fix-internal-distribution-pages-for-simulator-builds

* [eas-cli] Don't overwrite distribution

Stops overwriting distribution type for simulator builds, and sets simulator field in metadata instead

See: https://linear.app/expo/issue/ENG-9957/fix-internal-distribution-pages-for-simulator-builds

* [eas-cli] Merge main

Merged changes from main branch

See: https://linear.app/expo/issue/ENG-9957/fix-internal-distribution-pages-for-simulator-builds

* [eas-cli] Check for simulator flag

Updated build:run command to use simulator flag instead of overwritten distribution type

See: https://linear.app/expo/issue/ENG-9957/fix-internal-distribution-pages-for-simulator-builds

* [eas-cli] Update schema

Update graphql schema with simulator fields

See: https://linear.app/expo/issue/ENG-9957/fix-internal-distribution-pages-for-simulator-builds

* [eas-cli] Add flag

Add simulator flag to build:list command

See: https://linear.app/expo/issue/ENG-9957/fix-internal-distribution-pages-for-simulator-builds

* [eas-cli] Fix check

Fixed check function with correct field name

See: https://linear.app/expo/issue/ENG-9957/fix-internal-distribution-pages-for-simulator-builds

* [eas-cli] Fix tests

Fixed failing tests after BuildFragment structure changed

See: https://linear.app/expo/issue/ENG-9957/fix-internal-distribution-pages-for-simulator-builds

* [eas-cli] Add warning

Added warning to build:list command that the distribution=simulator is deprecated

See: https://linear.app/expo/issue/ENG-9957/fix-internal-distribution-pages-for-simulator-builds

* [eas-cli] Add description

Added description to the new simulator flag

See: https://linear.app/expo/issue/ENG-9957/fix-internal-distribution-pages-for-simulator-builds

* [eas-cli] Add validation

Added validation so the simulator flag can only be used with --platofrm=ios

See: https://linear.app/expo/issue/ENG-9957/fix-internal-distribution-pages-for-simulator-builds

* [eas-cli] Change message

Updated the warning displayed when using deprecated --distribution=simulator flag value

See: https://linear.app/expo/issue/ENG-9957/fix-internal-distribution-pages-for-simulator-builds

* [eas-cli] Replace string

Replaced hardcoded string with variable

See: https://linear.app/expo/issue/ENG-9957/fix-internal-distribution-pages-for-simulator-builds

* [eas-cli] Remove redundant check

Removed no longer necessary check for simulator build

See: https://linear.app/expo/issue/ENG-9957/fix-internal-distribution-pages-for-simulator-builds

* [eas-cli] Update schema

Updated graphql schema after recent changes

See: https://linear.app/expo/issue/ENG-9957/fix-internal-distribution-pages-for-simulator-builds

* [eas-cli] Update schema

Updated graphql schema after recent changes

See: https://linear.app/expo/issue/ENG-9957/fix-internal-distribution-pages-for-simulator-builds

* update CHANGELOG.md

* [eas-cli] Update schema

Updated graphql schema after recent changes

See: https://linear.app/expo/issue/ENG-9957/fix-internal-distribution-pages-for-simulator-builds
2024-01-31 17:21:05 +01:00
Szymon Dziedzic ceb561a4af add sjchmiela as codeowner (#2205) 2024-01-31 15:23:00 +01:00
Expo CI 63743cae65 update CHANGELOG.md 2024-01-30 10:26:13 +00:00
Szymon Dziedzic e8e5eb622c v7.1.2 2024-01-30 11:19:50 +01:00
Szymon DziedzicandStanisław Chmiela fe8f1b32b3 Revert "Revert "[eas-json] validate EAS Submit inputs better"" (#2202)
* Revert "Revert "[eas-json] validate EAS Submit inputs better""

* make validation constraints more loose where necessary

* update CHANGELOG.md

* fix message

* Apply suggestions from code review

Co-authored-by: Stanisław Chmiela <[email protected]>

* apply suggested changes

---------

Co-authored-by: Stanisław Chmiela <[email protected]>
2024-01-30 11:13:41 +01:00
Expo CI 3a1e5298a4 update CHANGELOG.md 2024-01-26 20:19:03 +00:00
Szymon Dziedzic 92c1256e8b v7.1.1 2024-01-26 21:11:12 +01:00
Szymon Dziedzic 61543c7983 Revert "[eas-json] validate EAS Submit inputs better" (#2200)
* Revert "[eas-json] validate EAS Submit inputs better"

* revert changelog revert

* update CHANGELOG.md
2024-01-26 21:03:43 +01:00
Expo CI 62d149ae60 update CHANGELOG.md 2024-01-26 09:58:59 +00:00
Szymon Dziedzic bbf14e2ee8 v7.1.0 2024-01-26 10:53:35 +01:00
Szymon DziedzicandStanisław Chmiela 126c5627eb [eas-json] validate EAS Submit inputs better (#2198)
* [eas-json] sanitize EAS Submit inputs better

* add link to docs

* update CHANGELOG.md

* validate app specific password

* use Joi schema for validation

* fix typo

* minor improvements

* Update packages/eas-cli/src/submit/ios/__tests__/IosSubmitCommand-test.ts

Co-authored-by: Stanisław Chmiela <[email protected]>

* make uuid validation less strict

* apply suggested changes

* fix tests

---------

Co-authored-by: Stanisław Chmiela <[email protected]>
2024-01-26 10:48:01 +01:00
Will Schurman b5f2f5286a [eas-cli] Support requireCommit for EAS Update (#2196) 2024-01-22 10:38:13 -08:00
Will Schurman 8ea05793dd [eas-cli] Remove support for classic updates release channel in 50+ (#2189) 2024-01-19 10:53:52 -08:00
Expo CI 02c8dcaa5b update CHANGELOG.md 2024-01-19 14:57:46 +00:00
Szymon Dziedzic fe1a1f14d1 v7.0.0 2024-01-19 15:51:27 +01:00
Szymon Dziedzic df7b18ca03 upgrade eas-cli-local-build-plugin to 1.0.60 2024-01-19 15:46:42 +01:00
Quinlan Jung 41142a9486 [eas-cli] Revert "[1/1][eas-cli] generate eas-update-metadata.json on publish … (#2187)
* Revert "[1/1][eas-cli] generate eas-update-metadata.json  on publish (#2158)"

This reverts commit 183fe8712b.

* lint

* update CHANGELOG.md
2024-01-18 13:59:19 -08:00
Quinlan Jung 72c28d4259 [eas-cli] use branch mapping utility fn (#2186)
* [eas-cli] use branch mapping utility fn

* update CHANGELOG.md
2024-01-18 13:58:43 -08:00
Expo CI da42962151 update CHANGELOG.md 2024-01-18 21:28:12 +00:00
Brent Vatne bbebe90876 v6.1.0 2024-01-18 13:21:18 -08:00
Will Schurman ea57d6383a [eas-cli] Upgrade packages from the expo/expo repo (#2145) 2024-01-18 11:01:00 -08:00
Szymon Dziedzic f5a99cea6b [ENG-11092][eas-json] update eas.schema.json to add support for Xcode 15.2 image (#2184)
* [eas-json] update `eas.schema.json` to add support for Xcode 15.2 image

* update CHANGELOG.md
2024-01-18 17:57:31 +01:00
197 changed files with 10697 additions and 2829 deletions

No files matched your search

+36 -2
View File
@@ -69,16 +69,22 @@ jobs:
- uses: actions/setup-node@v2 - uses: actions/setup-node@v2
with: with:
node-version: 20 node-version: 20
- run: brew install python-setuptools
env:
HOMEBREW_NO_AUTO_UPDATE: 1
- run: yarn install --frozen-lockfile --check-files - run: yarn install --frozen-lockfile --check-files
- run: yarn build - run: yarn build
- name: Build tarballs - name: Build tarballs
working-directory: ${{ github.workspace }}/packages/eas-cli working-directory: ${{ github.workspace }}/packages/eas-cli
run: | run: |
yarn pretarball-ci yarn pretarball-ci
yarn oclif pack:tarballs --no-xz --targets darwin-x64 yarn oclif pack:tarballs --no-xz --targets darwin-x64,darwin-arm64
- id: x64 - id: x64
run: echo "filename=$(ls eas-*-x64.tar.gz)" >> $GITHUB_OUTPUT run: echo "filename=$(ls eas-*-x64.tar.gz)" >> $GITHUB_OUTPUT
working-directory: ${{ github.workspace }}/packages/eas-cli/dist working-directory: ${{ github.workspace }}/packages/eas-cli/dist
- id: arm64
run: echo "filename=$(ls eas-*-arm64.tar.gz)" >> $GITHUB_OUTPUT
working-directory: ${{ github.workspace }}/packages/eas-cli/dist
- name: Upload darwin-x64 tarball - name: Upload darwin-x64 tarball
uses: actions/upload-release-asset@v1 uses: actions/upload-release-asset@v1
env: env:
@@ -88,6 +94,15 @@ jobs:
asset_path: packages/eas-cli/dist/${{ steps.x64.outputs.filename }} asset_path: packages/eas-cli/dist/${{ steps.x64.outputs.filename }}
asset_name: ${{ steps.x64.outputs.filename }} asset_name: ${{ steps.x64.outputs.filename }}
asset_content_type: application/gzip asset_content_type: application/gzip
- name: Upload darwin-arm64 tarball
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.release.outputs.upload_url }}
asset_path: packages/eas-cli/dist/${{ steps.arm64.outputs.filename }}
asset_name: ${{ steps.arm64.outputs.filename }}
asset_content_type: application/gzip
build-windows: build-windows:
name: Build for Windows name: Build for Windows
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -152,7 +167,13 @@ jobs:
VERSION=$(cat lerna.json | jq -r .version) VERSION=$(cat lerna.json | jq -r .version)
echo //registry.npmjs.org/:_authToken=$NODE_AUTH_TOKEN > ~/.npmrc echo //registry.npmjs.org/:_authToken=$NODE_AUTH_TOKEN > ~/.npmrc
npm dist-tag add eas-cli@$VERSION latest-eas-build-staging npm dist-tag add eas-cli@$VERSION latest-eas-build-staging
echo "Run \"npm dist-tag add eas-cli@$VERSION latest-eas-build\" to promote it to production." env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }}
- name: Add latest-eas-build tag
run: |
VERSION=$(cat lerna.json | jq -r .version)
echo //registry.npmjs.org/:_authToken=$NODE_AUTH_TOKEN > ~/.npmrc
npm dist-tag add eas-cli@$VERSION latest-eas-build
env: env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }}
release-changelog: release-changelog:
@@ -205,3 +226,16 @@ jobs:
SLACK_USERNAME: 'EAS CLI CI' SLACK_USERNAME: 'EAS CLI CI'
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_FOOTER: '' SLACK_FOOTER: ''
open-pr-in-universe:
name: Open a PR with `@expo/eas-json` bump in universe
needs: publish-to-npm
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Open a PR with `@expo/eas-json` version bump in universe
uses: benc-uk/workflow-dispatch@v1
with:
repo: expo/universe
ref: main
workflow: update-eas-json.yml
token: ${{ secrets.EXPO_BOT_PAT }}
+1 -1
View File
@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
node: ['16', '18', '20'] node: ['18', '20', '22']
include: include:
- node: '20' - node: '20'
coverage: true coverage: true
@@ -0,0 +1,81 @@
name: Open a PR bumping eas-build modules
on: workflow_dispatch
jobs:
open-pr:
name: Open a PR bumping eas-build modules
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: main
token: ${{ secrets.EXPO_BOT_PAT }}
- name: Setup node
uses: actions/setup-node@v2
with:
node-version: 20
- run: yarn install --frozen-lockfile
- name: Configure git
run: |
git config --global user.email "[email protected]"
git config --global user.name "Expo Bot"
- name: Upgrade eas-build modules
run: |
for DIR in packages/eas-cli packages/eas-json; do
pushd $DIR >/dev/null 2>&1
# packages are ordered according to output of `lerna list --toposort`
# https://github.com/expo/turtle-v2/pull/568
for PACKAGE in "@expo/downloader" "@expo/eas-build-job" "@expo/logger" "@expo/template-file" "@expo/steps" "@expo/turtle-spawn" "@expo/build-tools"; do
if grep -q $PACKAGE package.json; then
echo "[$DIR] yarn --exact add $PACKAGE"
yarn add --exact $PACKAGE
fi
done
popd >/dev/null 2>&1
done
- name: Set a branch name
id: bump-branch-name
run: |
HASH="$(echo $RANDOM | md5sum | head -c 10)"
BRANCH_NAME="@expo-bot/eas-build-bump-$HASH"
echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_OUTPUT
- name: Create a branch, commit, and push
run: |
BRANCH_NAME="${{ steps.bump-branch-name.outputs.BRANCH_NAME }}"
git checkout -b $BRANCH_NAME
git add .
git commit -m "Upgrade eas-build dependencies"
git push origin $BRANCH_NAME
- name: Open a PR to main
uses: repo-sync/pull-request@v2
id: open-pr
with:
source_branch: '${{ steps.bump-branch-name.outputs.BRANCH_NAME }}'
destination_branch: 'main'
pr_title: 'Upgrade eas-build dependencies'
pr_body: ':arrow_up: Upgrades [`eas-build`](https://github.com/expo/eas-build) dependencies.'
pr_reviewer: 'szdziedzic,radoslawkrzemien,sjchmiela,khamilowicz'
github_token: ${{ secrets.EXPO_BOT_PAT }}
- uses: actions/github-script@v3
with:
github-token: ${{ secrets.EXPO_BOT_PAT }}
script: |
github.issues.createComment({
issue_number: ${{ steps.open-pr.outputs.pr_number }},
owner: context.repo.owner,
repo: context.repo.repo,
body: "/changelog-entry chore Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies."
})
+10
View File
@@ -0,0 +1,10 @@
{
"eslint.enable": true,
"search.exclude": {
"**/node_modules": true,
"**/bower_components": true,
"**/*.code-search": true,
"**/src/**/build/**": false,
"**/src/build/**": false,
}
}
+342 -2
View File
@@ -8,16 +8,356 @@ This is the log of notable changes to EAS CLI and related packages.
### 🎉 New features ### 🎉 New features
- Add `build:delete` command. ([#2178](https://github.com/expo/eas-cli/pull/2178) by [@radoslawkrzemien](https://github.com/radoslawkrzemien)) ### 🐛 Bug fixes
- Add filter flags for `platform` and `profile` to `build:cancel` and `build:delete` commands. ([#2178](https://github.com/expo/eas-cli/pull/2178) by [@radoslawkrzemien](https://github.com/radoslawkrzemien))
### 🧹 Chores
- Remove any mentions of deleted Xcode < 15 images. ([#2438](https://github.com/expo/eas-cli/pull/2438) by [@szdziedzic](https://github.com/szdziedzic))
## [10.0.2](https://github.com/expo/eas-cli/releases/tag/v10.0.2) - 2024-06-17
### 🐛 Bug fixes ### 🐛 Bug fixes
- Fix parsing of `build.gradle` file by `gradle-to-js` parser by filtering out empty single line comments. ([#2435](https://github.com/expo/eas-cli/pull/2435) by [@szdziedzic](https://github.com/szdziedzic))
## [10.0.1](https://github.com/expo/eas-cli/releases/tag/v10.0.1) - 2024-06-17
### 🧹 Chores
- Add clarification to private-key flag in command line help. ([#2432](https://github.com/expo/eas-cli/pull/2432) by [@quinlanj](https://github.com/quinlanj))
## [10.0.0](https://github.com/expo/eas-cli/releases/tag/v10.0.0) - 2024-06-13
### 🛠 Breaking changes
- Drop support for Node 16. ([#2413](https://github.com/expo/eas-cli/pull/2413) by [@byCedric](https://github.com/byCedric))
- Update [`eas-build`](https://github.com/expo/eas-build) dependencies to the version requiring Node 18 as minimal Node version. ([#2416](https://github.com/expo/eas-cli/pull/2416) by [@expo-bot](https://github.com/expo-bot))
### 🐛 Bug fixes
- Resolve correct submit profile configuration for `eas build` command with `--auto-submit-with-profile` flag. ([#2425](https://github.com/expo/eas-cli/pull/2425) by [@szdziedzic](https://github.com/szdziedzic))
- Correctly parse the EXPO_APPLE_PROVIER_ID environment variable. ([#2349](https://github.com/expo/eas-cli/pull/2349) by [@louix](https://github.com/louix))
### 🧹 Chores
- Update lockfile to only include `@types/[email protected]`. ([#2412](https://github.com/expo/eas-cli/pull/2412) by [@byCedric](https://github.com/byCedric))
- Update test workflow Node versions to 18, 20, and 22. ([#2413](https://github.com/expo/eas-cli/pull/2413) by [@byCedric](https://github.com/byCedric))
## [9.2.0](https://github.com/expo/eas-cli/releases/tag/v9.2.0) - 2024-06-06
### 🎉 New features
- Add `target-profile` and `source-profile` flags to the `eas build:resign` command. ([#2410](https://github.com/expo/eas-cli/pull/2410) by [@szdziedzic](https://github.com/szdziedzic))
- Display build profile in the output of `eas build:list`. ([#2408](https://github.com/expo/eas-cli/pull/2408) by [@szdziedzic](https://github.com/szdziedzic))
### 🐛 Bug fixes
- Use the correct app config for no GitHub flow in `init:onboarding`. ([#2397](https://github.com/expo/eas-cli/pull/2397) by [@szdziedzic](https://github.com/szdziedzic))
- Disallow picking expired builds as submit archive source. ([#2406](https://github.com/expo/eas-cli/pull/2406) by [@sjchmiela](https://github.com/sjchmiela))
### 🧹 Chores
- Print network error message if present. ([#2407](https://github.com/expo/eas-cli/pull/2407) by [@szdziedzic](https://github.com/szdziedzic))
- Make flags for `eas build:list` command more aligned with flags for rest of the commands. ([#2409](https://github.com/expo/eas-cli/pull/2409) by [@szdziedzic](https://github.com/szdziedzic))
## [9.1.0](https://github.com/expo/eas-cli/releases/tag/v9.1.0) - 2024-05-23
### 🎉 New features
- Make `eas init:onboarding` command public. ([#2399](https://github.com/expo/eas-cli/pull/2399) by [@szdziedzic](https://github.com/szdziedzic))
## [9.0.10](https://github.com/expo/eas-cli/releases/tag/v9.0.10) - 2024-05-22
## [9.0.9](https://github.com/expo/eas-cli/releases/tag/v9.0.9) - 2024-05-22
## [9.0.8](https://github.com/expo/eas-cli/releases/tag/v9.0.8) - 2024-05-21
### 🧹 Chores
- Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies. ([#2387](https://github.com/expo/eas-cli/pull/2387) by [@expo-bot](https://github.com/expo-bot))
- Improve displaying of device registration QR code. ([#2391](https://github.com/expo/eas-cli/pull/2391) by [@szdziedzic](https://github.com/szdziedzic))
## [9.0.7](https://github.com/expo/eas-cli/releases/tag/v9.0.7) - 2024-05-17
## [9.0.6](https://github.com/expo/eas-cli/releases/tag/v9.0.6) - 2024-05-15
## [9.0.5](https://github.com/expo/eas-cli/releases/tag/v9.0.5) - 2024-05-13
## [9.0.4](https://github.com/expo/eas-cli/releases/tag/v9.0.4) - 2024-05-13
### 🧹 Chores
- Add loader and progress information to the `diagnostics` command. ([#2378](https://github.com/expo/eas-cli/pull/2378) by [@simek](https://github.com/simek))
## [9.0.3](https://github.com/expo/eas-cli/releases/tag/v9.0.3) - 2024-05-10
### 🧹 Chores
- Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies. ([#2372](https://github.com/expo/eas-cli/pull/2372) by [@expo-bot](https://github.com/expo-bot))
## [9.0.2](https://github.com/expo/eas-cli/releases/tag/v9.0.2) - 2024-05-09
## [9.0.1](https://github.com/expo/eas-cli/releases/tag/v9.0.1) - 2024-05-09
### 🧹 Chores
- Update image tags in `eas.schema.json`. ([#2363](https://github.com/expo/eas-cli/pull/2363) by [@szdziedzic](https://github.com/szdziedzic))
## [9.0.0](https://github.com/expo/eas-cli/releases/tag/v9.0.0) - 2024-05-08
### 🛠 Breaking changes
- Allow modification of provisioning profile in CI, add --freeze-credentials flag. ([#2347](https://github.com/expo/eas-cli/pull/2347) by [@quinlanj](https://github.com/quinlanj))
### 🐛 Bug fixes
- Pass env from process.env and build profile to expo-updates CLI calls where applicable. ([#2359](https://github.com/expo/eas-cli/pull/2359) by [@wschurman](https://github.com/wschurman))
### 🧹 Chores
- Remove more classic updates code. ([#2357](https://github.com/expo/eas-cli/pull/2357) by [@wschurman](https://github.com/wschurman))
- Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies. ([#2360](https://github.com/expo/eas-cli/pull/2360) by [@expo-bot](https://github.com/expo-bot))
- Don't pass custom global `"expoCli"` version set in `eas.json` to EAS Build process and warn users when setting it. ([#2361](https://github.com/expo/eas-cli/pull/2361) by [@szdziedzic](https://github.com/szdziedzic))
## [8.0.0](https://github.com/expo/eas-cli/releases/tag/v8.0.0) - 2024-05-01
### 🛠 Breaking changes
- Stop creating a channel on `eas update` and `eas update:roll-back-to-embedded` unless the `--channel` flag is specified. ([#2346](https://github.com/expo/eas-cli/pull/2346) by [@quinlanj](https://github.com/quinlanj))
### 🐛 Bug fixes
- Improve login info message for other login options. ([#2352](https://github.com/expo/eas-cli/pull/2352) by [@wschurman](https://github.com/wschurman))
- Show the -s, --sso option in the login command help. ([#2353](https://github.com/expo/eas-cli/pull/2353) by [@lzkb](https://github.com/lzkb))
### 🧹 Chores
- Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies. ([#2351](https://github.com/expo/eas-cli/pull/2351) by [@expo-bot](https://github.com/expo-bot))
- Don't prompt users to set push notifications by default if they don't have the `expo-notifications` installed. ([#2343](https://github.com/expo/eas-cli/pull/2343) by [@szdziedzic](https://github.com/szdziedzic))
## [7.8.5](https://github.com/expo/eas-cli/releases/tag/v7.8.5) - 2024-04-26
### 🐛 Bug fixes
- Add explicit workflow arg to expo-update CLI calls. ([#2340](https://github.com/expo/eas-cli/pull/2340) by [@wschurman](https://github.com/wschurman))
### 🧹 Chores
- Improve error message if the server returns `UNAUTHORIZED_ERROR`. ([#2345](https://github.com/expo/eas-cli/pull/2345) by [@szdziedzic](https://github.com/szdziedzic))
- Fill in min expo-updates version for expo-updates CLI. ([#2344](https://github.com/expo/eas-cli/pull/2344) by [@wschurman](https://github.com/wschurman))
## [7.8.4](https://github.com/expo/eas-cli/releases/tag/v7.8.4) - 2024-04-24
### 🧹 Chores
- Update the list of available Android images. ([#2337](https://github.com/expo/eas-cli/pull/2337) by [@radoslawkrzemien](https://github.com/radoslawkrzemien))
- Make multi-select for revoking distribution certificates more readable. ([#2342](https://github.com/expo/eas-cli/pull/2342) by [@szdziedzic](https://github.com/szdziedzic))
- Improve error message displayed when EAS CLI version doesn't satisfy minimal version required specified in eas.json. ([#2341](https://github.com/expo/eas-cli/pull/2341) by [@szdziedzic](https://github.com/szdziedzic))
## [7.8.3](https://github.com/expo/eas-cli/releases/tag/v7.8.3) - 2024-04-23
### 🐛 Bug fixes
- Don't prompt to set `android.package` and `ios.bundleIdentifier` values when running in non-interactive mode. ([#2336](https://github.com/expo/eas-cli/pull/2336) by [@szdziedzic](https://github.com/szdziedzic))
### 🧹 Chores
- Amend credential removal wording. ([#2334](https://github.com/expo/eas-cli/pull/2334) by [@quinlanj](https://github.com/quinlanj))
## [7.8.2](https://github.com/expo/eas-cli/releases/tag/v7.8.2) - 2024-04-15
### 🐛 Bug fixes
- Fix display of errors when expo-updates CLI command fails. ([#2324](https://github.com/expo/eas-cli/pull/2324) by [@wschurman](https://github.com/wschurman))
- Move credentials endpoints to paginated counterparts. ([#2327](https://github.com/expo/eas-cli/pull/2327) by [@quinlanj](https://github.com/quinlanj))
### 🧹 Chores
- Add progress bar for fetching paginated datasets. ([#2326](https://github.com/expo/eas-cli/pull/2326) by [@quinlanj](https://github.com/quinlanj))
## [7.8.1](https://github.com/expo/eas-cli/releases/tag/v7.8.1) - 2024-04-11
### 🐛 Bug fixes
- Fix command source files URLs in autogenerated `README`. ([#2318](https://github.com/expo/eas-cli/pull/2318) by [@szdziedzic](https://github.com/szdziedzic))
### 🧹 Chores
- Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies. ([#2316](https://github.com/expo/eas-cli/pull/2316) by [@expo-bot](https://github.com/expo-bot))
- Stop querying `Build.resourceClass` field. ([#2320](https://github.com/expo/eas-cli/pull/2320) by [@szdziedzic](https://github.com/szdziedzic))
## [7.8.0](https://github.com/expo/eas-cli/releases/tag/v7.8.0) - 2024-04-08
### 🎉 New features
- Add `auto`, `sdk-50` and `sdk-49` image tags. ([#2298](https://github.com/expo/eas-cli/pull/2298) by [@szdziedzic](https://github.com/szdziedzic))
- Add `--build-logger-level` flag to `eas build` command. ([#2313](https://github.com/expo/eas-cli/pull/2313) by [@szdziedzic](https://github.com/szdziedzic))
### 🧹 Chores
- Deprecate the `default` image tag. ([#2298](https://github.com/expo/eas-cli/pull/2298) by [@szdziedzic](https://github.com/szdziedzic))
- Deprecate iOS images with Xcode version lower then 15. ([#2298](https://github.com/expo/eas-cli/pull/2298) by [@szdziedzic](https://github.com/szdziedzic))
## [7.7.0](https://github.com/expo/eas-cli/releases/tag/v7.7.0) - 2024-04-05
### 🎉 New features
- Generate metadata file for project archive ([#2149](https://github.com/expo/eas-cli/pull/2149) by [@khamilowicz](https://github.com/khamilowicz))
- Add --verbose-fastlane flag to eas submit command for more robust fastlane pilot logs. ([#2276](https://github.com/expo/eas-cli/pull/2276) by [@khamilowicz](https://github.com/khamilowicz))
- Add `eas credentials:configure-build` subcommand. ([#2282](https://github.com/expo/eas-cli/pull/2282) by [@fiberjw](https://github.com/fiberjw))
### 🧹 Chores
- Add info about the Xcode 15.3 image to `eas.schema.json`. ([#2312](https://github.com/expo/eas-cli/pull/2312) by [@szdziedzic](https://github.com/szdziedzic))
## [7.6.2](https://github.com/expo/eas-cli/releases/tag/v7.6.2) - 2024-03-27
### 🧹 Chores
- Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies. ([#2301](https://github.com/expo/eas-cli/pull/2301) by [@expo-bot](https://github.com/expo-bot))
- Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies. ([#2304](https://github.com/expo/eas-cli/pull/2304) by [@expo-bot](https://github.com/expo-bot))
## [7.6.1](https://github.com/expo/eas-cli/releases/tag/v7.6.1) - 2024-03-25
### 🧹 Chores
- Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies. ([#2291](https://github.com/expo/eas-cli/pull/2291) by [@expo-bot](https://github.com/expo-bot))
- Fix asset limit punctuation. ([#2296](https://github.com/expo/eas-cli/pull/2296) by [@quinlanj](https://github.com/quinlanj))
- Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies. ([#2293](https://github.com/expo/eas-cli/pull/2293) by [@expo-bot](https://github.com/expo-bot))
## [7.6.0](https://github.com/expo/eas-cli/releases/tag/v7.6.0) - 2024-03-18
### 🎉 New features
- Print uncommitted files in non-interactive mode if they fail the execution. ([#2288](https://github.com/expo/eas-cli/pull/2288) by [@sjchmiela](https://github.com/sjchmiela))
### 🐛 Bug fixes
- Use a custom build config path with POSIX separator when sending data to the EAS Build server. ([#2285](https://github.com/expo/eas-cli/pull/2285) by [@szdziedzic](https://github.com/szdziedzic))
- Improve resolving vcsClient as a part of the project context. ([#2295](https://github.com/expo/eas-cli/pull/2295) by [@szdziedzic](https://github.com/szdziedzic))
### 🧹 Chores
- Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies. ([#2277](https://github.com/expo/eas-cli/pull/2277) by [@expo-bot](https://github.com/expo-bot))
- Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies. ([#2283](https://github.com/expo/eas-cli/pull/2283) by [@expo-bot](https://github.com/expo-bot))
- Bump the `@expo/apple-utils` version to switch between the `developer.apple.com` and `developer-mdn.apple.com` domains when one of them doesn't work. ([#2290](https://github.com/expo/eas-cli/pull/2290) by [@szdziedzic](https://github.com/szdziedzic))
## [7.5.0](https://github.com/expo/eas-cli/releases/tag/v7.5.0) - 2024-03-11
### 🎉 New features
- Add `--auto-submit` option to `eas build:internal` command. ([#2271](https://github.com/expo/eas-cli/pull/2271) by [@szdziedzic](https://github.com/szdziedzic))
### 🧹 Chores
- Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies. ([#2274](https://github.com/expo/eas-cli/pull/2274) by [@expo-bot](https://github.com/expo-bot))
## [7.4.0](https://github.com/expo/eas-cli/releases/tag/v7.4.0) - 2024-03-10
### 🎉 New features
- Use new expo-updates configuration:syncnative for versioned native sync. ([#2269](https://github.com/expo/eas-cli/pull/2269) by [@wschurman](https://github.com/wschurman))
### 🐛 Bug fixes
- Fix expo-updates package version detection for canaries. ([#2243](https://github.com/expo/eas-cli/pull/2243) by [@wschurman](https://github.com/wschurman))
- Add missing `config` property to `eas.json` schema. ([#2248](https://github.com/expo/eas-cli/pull/2248) by [@sjchmiela](https://github.com/sjchmiela))
- Use expo-updates runtime version CLI to generate runtime versions. ([#2251](https://github.com/expo/eas-cli/pull/2251) by [@wschurman](https://github.com/wschurman))
- Update @expo/apple-utils to handle changes in API. ([73ba19de6662763cc6bff9fac6b7700ffbd0e88a](https://github.com/expo/eas-cli/commit/73ba19de6662763cc6bff9fac6b7700ffbd0e88a) by [@brentvatne](https://github.com/brentvatne))
### 🧹 Chores
- Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies. ([#2237](https://github.com/expo/eas-cli/pull/2237) by [@expo-bot](https://github.com/expo-bot))
- Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies. ([#2240](https://github.com/expo/eas-cli/pull/2240) by [@expo-bot](https://github.com/expo-bot))
- Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies. ([#2253](https://github.com/expo/eas-cli/pull/2253) by [@expo-bot](https://github.com/expo-bot))
- Include src/\*\*/build directories in vscode search and replace. ([#2250](https://github.com/expo/eas-cli/pull/2250) by [@wschurman](https://github.com/wschurman))
- Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies. ([#2259](https://github.com/expo/eas-cli/pull/2259) by [@expo-bot](https://github.com/expo-bot))
## [7.3.0](https://github.com/expo/eas-cli/releases/tag/v7.3.0) - 2024-02-19
### 🎉 New features
- Fix expo-updates fingerprinting during update. ([#2231](https://github.com/expo/eas-cli/pull/2231) by [@wschurman](https://github.com/wschurman))
### 🐛 Bug fixes
- Don't require expo on fresh react-native project. ([#2235](https://github.com/expo/eas-cli/pull/2235) by [@radoslawkrzemien](https://github.com/radoslawkrzemien))
### 🧹 Chores
- Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies. ([#2229](https://github.com/expo/eas-cli/pull/2229) by [@expo-bot](https://github.com/expo-bot))
- Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies. ([#2230](https://github.com/expo/eas-cli/pull/2230) by [@expo-bot](https://github.com/expo-bot))
- Reword update configuration warning. ([#2234](https://github.com/expo/eas-cli/pull/2234) by [@quinlanj](https://github.com/quinlanj))
## [7.2.0](https://github.com/expo/eas-cli/releases/tag/v7.2.0) - 2024-02-11
### 🎉 New features
- Support configuring a Google Service Account Key via eas credentials, for sending Android Notifications via FCM V1. ([#2197](https://github.com/expo/eas-cli/pull/2197) by [@christopherwalter](https://github.com/christopherwalter))
### 🐛 Bug fixes
- Revert expose expo export dev flag as an option in eas update. ([#2214](https://github.com/expo/eas-cli/pull/2214) by [@wschurman](https://github.com/wschurman))
### 🧹 Chores
- Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies. ([#2223](https://github.com/expo/eas-cli/pull/2223) by [@expo-bot](https://github.com/expo-bot))
## [7.1.3](https://github.com/expo/eas-cli/releases/tag/v7.1.3) - 2024-02-07
### 🧹 Chores
- Remove duplicated log message when creating ASC API key. ([#2208](https://github.com/expo/eas-cli/pull/2208) by [@radoslawkrzemien](https://github.com/radoslawkrzemien))
- Add simulator flag to metadata. ([#2073](https://github.com/expo/eas-cli/pull/2073) by [@radoslawkrzemien](https://github.com/radoslawkrzemien))
- Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies. ([#2220](https://github.com/expo/eas-cli/pull/2220) by [@expo-bot](https://github.com/expo-bot))
## [7.1.2](https://github.com/expo/eas-cli/releases/tag/v7.1.2) - 2024-01-30
### 🧹 Chores
- Add better validation for EAS Submit inputs. ([#2202](https://github.com/expo/eas-cli/pull/2202) by [@szdziedzic](https://github.com/szdziedzic))
## [7.1.1](https://github.com/expo/eas-cli/releases/tag/v7.1.1) - 2024-01-26
### 🐛 Bug fixes
- Revert incorrect EAS Submit input validation changes. ([#2200](https://github.com/expo/eas-cli/pull/2200) by [@szdziedzic](https://github.com/szdziedzic))
## [7.1.0](https://github.com/expo/eas-cli/releases/tag/v7.1.0) - 2024-01-26
### 🎉 New features
- Support requireCommit for EAS Update. ([#2196](https://github.com/expo/eas-cli/pull/2196) by [@wschurman](https://github.com/wschurman))
### 🧹 Chores
- Remove support for classic updates release channel in 50+. ([#2189](https://github.com/expo/eas-cli/pull/2189) by [@wschurman](https://github.com/wschurman))
- Validate EAS Submit inputs better. ([#2198](https://github.com/expo/eas-cli/pull/2198) by [@szdziedzic](https://github.com/szdziedzic))
## [7.0.0](https://github.com/expo/eas-cli/releases/tag/v7.0.0) - 2024-01-19
### 🛠 Breaking changes
- Stop generating eas-update-metadata.json on publish. ([#2187](https://github.com/expo/eas-cli/pull/2187) by [@quinlanj](https://github.com/quinlanj))
### 🧹 Chores
- Use branch mapping utility fn. ([#2186](https://github.com/expo/eas-cli/pull/2186) by [@quinlanj](https://github.com/quinlanj))
## [6.1.0](https://github.com/expo/eas-cli/releases/tag/v6.1.0) - 2024-01-18
### 🎉 New features
- Add `build:delete` command. ([#2178](https://github.com/expo/eas-cli/pull/2178) by [@radoslawkrzemien](https://github.com/radoslawkrzemien))
- Add filter flags for `platform` and `profile` to `build:cancel` and `build:delete` commands. ([#2178](https://github.com/expo/eas-cli/pull/2178) by [@radoslawkrzemien](https://github.com/radoslawkrzemien))
### 🧹 Chores ### 🧹 Chores
- Remove "bare"-specific **eas.json** template. ([#2179](https://github.com/expo/eas-cli/pull/2179) by [@sjchmiela](https://github.com/sjchmiela)) - Remove "bare"-specific **eas.json** template. ([#2179](https://github.com/expo/eas-cli/pull/2179) by [@sjchmiela](https://github.com/sjchmiela))
- Prompt users if they want to continue if EAS CLI fails to provision the devices. ([#2181](https://github.com/expo/eas-cli/pull/2181) by [@szdziedzic](https://github.com/szdziedzic)) - Prompt users if they want to continue if EAS CLI fails to provision the devices. ([#2181](https://github.com/expo/eas-cli/pull/2181) by [@szdziedzic](https://github.com/szdziedzic))
- Update `eas-cli` and `@expo/eas-json` dependencies. ([#2176](https://github.com/expo/eas-cli/pull/2176) by [@szdziedzic](https://github.com/szdziedzic)) - Update `eas-cli` and `@expo/eas-json` dependencies. ([#2176](https://github.com/expo/eas-cli/pull/2176) by [@szdziedzic](https://github.com/szdziedzic))
- Update `eas.schema.json` to after adding Xcode 15.2 image. ([#2184](https://github.com/expo/eas-cli/pull/2184) by [@szdziedzic](https://github.com/szdziedzic))
- Upgrade packages from the expo/expo repo. ([#2145](https://github.com/expo/eas-cli/pull/2145) by [@wschurman](https://github.com/wschurman))
## [6.0.0](https://github.com/expo/eas-cli/releases/tag/v6.0.0) - 2024-01-12 ## [6.0.0](https://github.com/expo/eas-cli/releases/tag/v6.0.0) - 2024-01-12
+6 -6
View File
@@ -1,10 +1,10 @@
* @szdziedzic @khamilowicz * @szdziedzic @khamilowicz @sjchmiela
packages/eas-cli/src/build @szdziedzic @khamilowicz packages/eas-cli/src/build @szdziedzic @khamilowicz @sjchmiela
packages/eas-cli/src/commands/build @szdziedzic @khamilowicz packages/eas-cli/src/commands/build @szdziedzic @khamilowicz @sjchmiela
packages/eas-cli/src/submit @szdziedzic @khamilowicz packages/eas-cli/src/submit @szdziedzic @khamilowicz @sjchmiela
packages/eas-cli/src/commands/submit.ts @szdziedzic @khamilowicz packages/eas-cli/src/commands/submit.ts @szdziedzic @khamilowicz @sjchmiela
packages/eas-cli/src/update @EvanBacon @byCedric @wschurman packages/eas-cli/src/update @EvanBacon @byCedric @wschurman
packages/eas-cli/src/commands/update @EvanBacon @byCedric @wschurman packages/eas-cli/src/commands/update @EvanBacon @byCedric @wschurman
@@ -13,4 +13,4 @@ packages/eas-cli/schema @bycedric
packages/eas-cli/src/metadata @bycedric packages/eas-cli/src/metadata @bycedric
packages/eas-cli/src/commands/metadata @bycedric packages/eas-cli/src/commands/metadata @bycedric
packages/eas-json @szdziedzic @khamilowicz packages/eas-json @szdziedzic @khamilowicz @sjchmiela
-4
View File
@@ -12,7 +12,3 @@ The algorithm works as follows:
- If there are any entries in the "🛠 Breaking changes" section, bump the MAJOR version. - If there are any entries in the "🛠 Breaking changes" section, bump the MAJOR version.
- Otherwise, if there are any entries in the "🎉 New features", bump the MINOR version. - Otherwise, if there are any entries in the "🎉 New features", bump the MINOR version.
- Otherwise, bump the PATCH version. - Otherwise, bump the PATCH version.
## Updating EAS CLI version on EAS Build
The release process promotes the new version to staging. After verifying it works there, you can promote it to production with `npm dist-tag add eas-cli@{version} latest-eas-build`.
+1 -1
View File
@@ -1,5 +1,5 @@
{ {
"npmClient": "yarn", "npmClient": "yarn",
"version": "6.0.0", "version": "10.0.2",
"$schema": "node_modules/lerna/schemas/lerna-schema.json" "$schema": "node_modules/lerna/schemas/lerna-schema.json"
} }
+225 -97
View File
@@ -68,6 +68,7 @@ eas --help COMMAND
* [`eas build`](#eas-build) * [`eas build`](#eas-build)
* [`eas build:cancel [BUILD_ID]`](#eas-buildcancel-build_id) * [`eas build:cancel [BUILD_ID]`](#eas-buildcancel-build_id)
* [`eas build:configure`](#eas-buildconfigure) * [`eas build:configure`](#eas-buildconfigure)
* [`eas build:delete [BUILD_ID]`](#eas-builddelete-build_id)
* [`eas build:inspect`](#eas-buildinspect) * [`eas build:inspect`](#eas-buildinspect)
* [`eas build:list`](#eas-buildlist) * [`eas build:list`](#eas-buildlist)
* [`eas build:resign`](#eas-buildresign) * [`eas build:resign`](#eas-buildresign)
@@ -84,6 +85,7 @@ eas --help COMMAND
* [`eas channel:view [NAME]`](#eas-channelview-name) * [`eas channel:view [NAME]`](#eas-channelview-name)
* [`eas config`](#eas-config) * [`eas config`](#eas-config)
* [`eas credentials`](#eas-credentials) * [`eas credentials`](#eas-credentials)
* [`eas credentials:configure-build`](#eas-credentialsconfigure-build)
* [`eas device:create`](#eas-devicecreate) * [`eas device:create`](#eas-devicecreate)
* [`eas device:delete`](#eas-devicedelete) * [`eas device:delete`](#eas-devicedelete)
* [`eas device:list`](#eas-devicelist) * [`eas device:list`](#eas-devicelist)
@@ -92,14 +94,17 @@ eas --help COMMAND
* [`eas diagnostics`](#eas-diagnostics) * [`eas diagnostics`](#eas-diagnostics)
* [`eas help [COMMAND]`](#eas-help-command) * [`eas help [COMMAND]`](#eas-help-command)
* [`eas init`](#eas-init) * [`eas init`](#eas-init)
* [`eas init:onboarding [TARGET_PROJECT_DIRECTORY]`](#eas-initonboarding-target_project_directory)
* [`eas login`](#eas-login) * [`eas login`](#eas-login)
* [`eas logout`](#eas-logout) * [`eas logout`](#eas-logout)
* [`eas metadata:lint`](#eas-metadatalint) * [`eas metadata:lint`](#eas-metadatalint)
* [`eas metadata:pull`](#eas-metadatapull) * [`eas metadata:pull`](#eas-metadatapull)
* [`eas metadata:push`](#eas-metadatapush) * [`eas metadata:push`](#eas-metadatapush)
* [`eas onboarding [TARGET_PROJECT_DIRECTORY]`](#eas-onboarding-target_project_directory)
* [`eas open`](#eas-open) * [`eas open`](#eas-open)
* [`eas project:info`](#eas-projectinfo) * [`eas project:info`](#eas-projectinfo)
* [`eas project:init`](#eas-projectinit) * [`eas project:init`](#eas-projectinit)
* [`eas project:onboarding [TARGET_PROJECT_DIRECTORY]`](#eas-projectonboarding-target_project_directory)
* [`eas secret:create`](#eas-secretcreate) * [`eas secret:create`](#eas-secretcreate)
* [`eas secret:delete`](#eas-secretdelete) * [`eas secret:delete`](#eas-secretdelete)
* [`eas secret:list`](#eas-secretlist) * [`eas secret:list`](#eas-secretlist)
@@ -126,7 +131,10 @@ log in with your Expo account
``` ```
USAGE USAGE
$ eas account:login $ eas account:login [-s]
FLAGS
-s, --sso Login with SSO
DESCRIPTION DESCRIPTION
log in with your Expo account log in with your Expo account
@@ -135,7 +143,7 @@ ALIASES
$ eas login $ eas login
``` ```
_See code: [src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/account/login.ts)_ _See code: [packages/eas-cli/src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/account/login.ts)_
## `eas account:logout` ## `eas account:logout`
@@ -152,7 +160,7 @@ ALIASES
$ eas logout $ eas logout
``` ```
_See code: [src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/account/logout.ts)_ _See code: [packages/eas-cli/src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/account/logout.ts)_
## `eas account:view` ## `eas account:view`
@@ -169,7 +177,7 @@ ALIASES
$ eas whoami $ eas whoami
``` ```
_See code: [src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/account/view.ts)_ _See code: [packages/eas-cli/src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/account/view.ts)_
## `eas analytics [STATUS]` ## `eas analytics [STATUS]`
@@ -183,7 +191,7 @@ DESCRIPTION
display or change analytics settings display or change analytics settings
``` ```
_See code: [src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/analytics.ts)_ _See code: [packages/eas-cli/src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/analytics.ts)_
## `eas autocomplete [SHELL]` ## `eas autocomplete [SHELL]`
@@ -214,7 +222,7 @@ EXAMPLES
$ eas autocomplete --refresh-cache $ eas autocomplete --refresh-cache
``` ```
_See code: [@oclif/plugin-autocomplete](https://github.com/oclif/plugin-autocomplete/blob/v2.3.10/src/commands/autocomplete/index.ts)_ _See code: [@oclif/plugin-autocomplete](https://github.com/oclif/plugin-autocomplete/blob/v2.3.10/packages/eas-cli/src/commands/autocomplete/index.ts)_
## `eas branch:create [NAME]` ## `eas branch:create [NAME]`
@@ -235,7 +243,7 @@ DESCRIPTION
create a branch create a branch
``` ```
_See code: [src/commands/branch/create.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/branch/create.ts)_ _See code: [packages/eas-cli/src/commands/branch/create.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/branch/create.ts)_
## `eas branch:delete [NAME]` ## `eas branch:delete [NAME]`
@@ -256,7 +264,7 @@ DESCRIPTION
delete a branch delete a branch
``` ```
_See code: [src/commands/branch/delete.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/branch/delete.ts)_ _See code: [packages/eas-cli/src/commands/branch/delete.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/branch/delete.ts)_
## `eas branch:list` ## `eas branch:list`
@@ -276,7 +284,7 @@ DESCRIPTION
list all branches list all branches
``` ```
_See code: [src/commands/branch/list.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/branch/list.ts)_ _See code: [packages/eas-cli/src/commands/branch/list.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/branch/list.ts)_
## `eas branch:rename` ## `eas branch:rename`
@@ -296,7 +304,7 @@ DESCRIPTION
rename a branch rename a branch
``` ```
_See code: [src/commands/branch/rename.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/branch/rename.ts)_ _See code: [packages/eas-cli/src/commands/branch/rename.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/branch/rename.ts)_
## `eas branch:view [NAME]` ## `eas branch:view [NAME]`
@@ -319,7 +327,7 @@ DESCRIPTION
view a branch view a branch
``` ```
_See code: [src/commands/branch/view.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/branch/view.ts)_ _See code: [packages/eas-cli/src/commands/branch/view.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/branch/view.ts)_
## `eas build` ## `eas build`
@@ -328,18 +336,25 @@ start a build
``` ```
USAGE USAGE
$ eas build [-p android|ios|all] [-e <value>] [--local] [--output <value>] [--wait] [--clear-cache] $ eas build [-p android|ios|all] [-e <value>] [--local] [--output <value>] [--wait] [--clear-cache]
[--auto-submit | --auto-submit-with-profile <value>] [-m <value>] [--json --non-interactive] [--auto-submit | --auto-submit-with-profile <value>] [-m <value>] [--build-logger-level
trace|debug|info|warn|error|fatal] [--freeze-credentials] [--json --non-interactive]
FLAGS FLAGS
-e, --profile=PROFILE_NAME Name of the build profile from eas.json. Defaults to "production" if defined -e, --profile=PROFILE_NAME Name of the build profile from eas.json. Defaults to
in eas.json. "production" if defined in eas.json.
-m, --message=<value> A short message describing the build -m, --message=<value> A short message describing the build
-p, --platform=(android|ios|all) -p, --platform=(android|ios|all)
--auto-submit Submit on build complete using the submit profile with the same name as the --auto-submit Submit on build complete using the submit profile with the
build profile same name as the build profile
--auto-submit-with-profile=PROFILE_NAME Submit on build complete using the submit profile with provided name --auto-submit-with-profile=PROFILE_NAME Submit on build complete using the submit profile with
provided name
--build-logger-level=(trace|debug|info|warn|error|fatal) The level of logs to output during the build process.
Defaults to "info".
--clear-cache Clear cache before the build --clear-cache Clear cache before the build
--json Enable JSON output, non-JSON messages will be printed to stderr. --freeze-credentials Prevent the build from updating credentials in
non-interactive mode
--json Enable JSON output, non-JSON messages will be printed to
stderr.
--local Run build locally [experimental] --local Run build locally [experimental]
--non-interactive Run the command in non-interactive mode. --non-interactive Run the command in non-interactive mode.
--output=<value> Output path for local build --output=<value> Output path for local build
@@ -349,7 +364,7 @@ DESCRIPTION
start a build start a build
``` ```
_See code: [src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/build/index.ts)_ _See code: [packages/eas-cli/src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/build/index.ts)_
## `eas build:cancel [BUILD_ID]` ## `eas build:cancel [BUILD_ID]`
@@ -357,16 +372,18 @@ cancel a build
``` ```
USAGE USAGE
$ eas build:cancel [BUILD_ID] [--non-interactive] $ eas build:cancel [BUILD_ID] [--non-interactive] [-p android|ios|all] [-e <value>]
FLAGS FLAGS
-e, --profile=PROFILE_NAME Filter builds by build profile if build ID is not provided
-p, --platform=(android|ios|all) Filter builds by the platform if build ID is not provided
--non-interactive Run the command in non-interactive mode. --non-interactive Run the command in non-interactive mode.
DESCRIPTION DESCRIPTION
cancel a build cancel a build
``` ```
_See code: [src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/build/cancel.ts)_ _See code: [packages/eas-cli/src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/build/cancel.ts)_
## `eas build:configure` ## `eas build:configure`
@@ -383,7 +400,26 @@ DESCRIPTION
configure the project to support EAS Build configure the project to support EAS Build
``` ```
_See code: [src/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/build/configure.ts)_ _See code: [packages/eas-cli/src/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/build/configure.ts)_
## `eas build:delete [BUILD_ID]`
delete a build
```
USAGE
$ eas build:delete [BUILD_ID] [--non-interactive] [-p android|ios|all] [-e <value>]
FLAGS
-e, --profile=PROFILE_NAME Filter builds by build profile if build ID is not provided
-p, --platform=(android|ios|all) Filter builds by the platform if build ID is not provided
--non-interactive Run the command in non-interactive mode.
DESCRIPTION
delete a build
```
_See code: [packages/eas-cli/src/commands/build/delete.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/build/delete.ts)_
## `eas build:inspect` ## `eas build:inspect`
@@ -418,7 +454,7 @@ DESCRIPTION
inspect the state of the project at specific build stages, useful for troubleshooting inspect the state of the project at specific build stages, useful for troubleshooting
``` ```
_See code: [src/commands/build/inspect.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/build/inspect.ts)_ _See code: [packages/eas-cli/src/commands/build/inspect.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/build/inspect.ts)_
## `eas build:list` ## `eas build:list`
@@ -426,20 +462,27 @@ list all builds for your project
``` ```
USAGE USAGE
$ eas build:list [--platform all|android|ios] [--status $ eas build:list [-p android|ios|all] [--status
new|in-queue|in-progress|pending-cancel|errored|finished|canceled] [--distribution store|internal|simulator] new|in-queue|in-progress|pending-cancel|errored|finished|canceled] [--distribution store|internal|simulator]
[--channel <value>] [--appVersion <value>] [--appBuildVersion <value>] [--sdkVersion <value>] [--runtimeVersion [--channel <value>] [--app-version <value>] [--app-build-version <value>] [--sdk-version <value>] [--runtime-version
<value>] [--appIdentifier <value>] [--buildProfile <value>] [--gitCommitHash <value>] [--offset <value>] [--limit <value>] [--app-identifier <value>] [-e <value>] [--git-commit-hash <value>] [--offset <value>] [--limit <value>]
<value>] [--json --non-interactive] [--json --non-interactive] [--simulator]
FLAGS FLAGS
--appBuildVersion=<value> -e, --build-profile=<value> Filter only builds created with the
--appIdentifier=<value> specified build profile
--appVersion=<value> -p, --platform=(android|ios|all)
--buildProfile=<value> --app-build-version=<value> Filter only builds created with the
specified app build version
--app-identifier=<value> Filter only builds created with the
specified app identifier
--app-version=<value> Filter only builds created with the
specified main app version
--channel=<value> --channel=<value>
--distribution=(store|internal|simulator) --distribution=(store|internal|simulator) Filter only builds with the specified
--gitCommitHash=<value> distribution type
--git-commit-hash=<value> Filter only builds created with the
specified git commit hash
--json Enable JSON output, non-JSON messages --json Enable JSON output, non-JSON messages
will be printed to stderr. will be printed to stderr.
--limit=<value> The number of items to fetch each query. --limit=<value> The number of items to fetch each query.
@@ -447,16 +490,21 @@ FLAGS
--non-interactive Run the command in non-interactive mode. --non-interactive Run the command in non-interactive mode.
--offset=<value> Start queries from specified index. Use --offset=<value> Start queries from specified index. Use
for paginating results. Defaults to 0. for paginating results. Defaults to 0.
--platform=(all|android|ios) --runtime-version=<value> Filter only builds created with the
--runtimeVersion=<value> specified runtime version
--sdkVersion=<value> --sdk-version=<value> Filter only builds created with the
--status=(new|in-queue|in-progress|pending-cancel|errored|finished|canceled) specified Expo SDK version
--simulator Filter only iOS simulator builds. Can
only be used with --platform flag set to
"ios"
--status=(new|in-queue|in-progress|pending-cancel|errored|finished|canceled) Filter only builds with the specified
status
DESCRIPTION DESCRIPTION
list all builds for your project list all builds for your project
``` ```
_See code: [src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/build/list.ts)_ _See code: [packages/eas-cli/src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/build/list.ts)_
## `eas build:resign` ## `eas build:resign`
@@ -464,25 +512,28 @@ re-sign a build archive
``` ```
USAGE USAGE
$ eas build:resign [-p android|ios] [-e <value>] [--wait] [--id <value>] [--offset <value>] [--limit <value>] $ eas build:resign [-p android|ios] [-e <value>] [--source-profile <value>] [--wait] [--id <value>] [--offset
[--json --non-interactive] <value>] [--limit <value>] [--json --non-interactive]
FLAGS FLAGS
-e, --profile=PROFILE_NAME Name of the build profile from eas.json. Defaults to "production" if defined in -e, --target-profile=PROFILE_NAME Name of the target build profile from eas.json. Credentials and environment
eas.json. variables from this profile will be used when re-signing. Defaults to "production"
if defined in eas.json.
-p, --platform=(android|ios) -p, --platform=(android|ios)
--id=<value> ID of the build to re-sign. --id=<value> ID of the build to re-sign.
--json Enable JSON output, non-JSON messages will be printed to stderr. --json Enable JSON output, non-JSON messages will be printed to stderr.
--limit=<value> The number of items to fetch each query. Defaults to 50 and is capped at 100. --limit=<value> The number of items to fetch each query. Defaults to 50 and is capped at 100.
--non-interactive Run the command in non-interactive mode. --non-interactive Run the command in non-interactive mode.
--offset=<value> Start queries from specified index. Use for paginating results. Defaults to 0. --offset=<value> Start queries from specified index. Use for paginating results. Defaults to 0.
--source-profile=PROFILE_NAME Name of the source build profile from eas.json. Used to filter builds eligible for
re-signing.
--[no-]wait Wait for build(s) to complete. --[no-]wait Wait for build(s) to complete.
DESCRIPTION DESCRIPTION
re-sign a build archive re-sign a build archive
``` ```
_See code: [src/commands/build/resign.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/build/resign.ts)_ _See code: [packages/eas-cli/src/commands/build/resign.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/build/resign.ts)_
## `eas build:run` ## `eas build:run`
@@ -508,7 +559,7 @@ DESCRIPTION
run simulator/emulator builds from eas-cli run simulator/emulator builds from eas-cli
``` ```
_See code: [src/commands/build/run.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/build/run.ts)_ _See code: [packages/eas-cli/src/commands/build/run.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/build/run.ts)_
## `eas build:submit` ## `eas build:submit`
@@ -517,7 +568,7 @@ submit app binary to App Store and/or Play Store
``` ```
USAGE USAGE
$ eas build:submit [-p android|ios|all] [-e <value>] [--latest | --id <value> | --path <value> | --url <value>] $ eas build:submit [-p android|ios|all] [-e <value>] [--latest | --id <value> | --path <value> | --url <value>]
[--verbose] [--wait] [--non-interactive] [--verbose] [--wait] [--verbose-fastlane] [--non-interactive]
FLAGS FLAGS
-e, --profile=<value> Name of the submit profile from eas.json. Defaults to "production" if defined in -e, --profile=<value> Name of the submit profile from eas.json. Defaults to "production" if defined in
@@ -529,6 +580,7 @@ FLAGS
--path=<value> Path to the .apk/.aab/.ipa file --path=<value> Path to the .apk/.aab/.ipa file
--url=<value> App archive url --url=<value> App archive url
--verbose Always print logs from EAS Submit --verbose Always print logs from EAS Submit
--verbose-fastlane Enable verbose logging for the submission process
--[no-]wait Wait for submission to complete --[no-]wait Wait for submission to complete
DESCRIPTION DESCRIPTION
@@ -557,7 +609,7 @@ DESCRIPTION
get the latest version from EAS servers get the latest version from EAS servers
``` ```
_See code: [src/commands/build/version/get.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/build/version/get.ts)_ _See code: [packages/eas-cli/src/commands/build/version/get.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/build/version/get.ts)_
## `eas build:version:set` ## `eas build:version:set`
@@ -576,7 +628,7 @@ DESCRIPTION
update version of an app update version of an app
``` ```
_See code: [src/commands/build/version/set.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/build/version/set.ts)_ _See code: [packages/eas-cli/src/commands/build/version/set.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/build/version/set.ts)_
## `eas build:version:sync` ## `eas build:version:sync`
@@ -595,7 +647,7 @@ DESCRIPTION
update a version in native code with a value stored on EAS servers update a version in native code with a value stored on EAS servers
``` ```
_See code: [src/commands/build/version/sync.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/build/version/sync.ts)_ _See code: [packages/eas-cli/src/commands/build/version/sync.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/build/version/sync.ts)_
## `eas build:view [BUILD_ID]` ## `eas build:view [BUILD_ID]`
@@ -612,7 +664,7 @@ DESCRIPTION
view a build for your project view a build for your project
``` ```
_See code: [src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/build/view.ts)_ _See code: [packages/eas-cli/src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/build/view.ts)_
## `eas channel:create [NAME]` ## `eas channel:create [NAME]`
@@ -633,7 +685,7 @@ DESCRIPTION
create a channel create a channel
``` ```
_See code: [src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/channel/create.ts)_ _See code: [packages/eas-cli/src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/channel/create.ts)_
## `eas channel:edit [NAME]` ## `eas channel:edit [NAME]`
@@ -655,7 +707,7 @@ DESCRIPTION
point a channel at a new branch point a channel at a new branch
``` ```
_See code: [src/commands/channel/edit.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/channel/edit.ts)_ _See code: [packages/eas-cli/src/commands/channel/edit.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/channel/edit.ts)_
## `eas channel:list` ## `eas channel:list`
@@ -675,7 +727,7 @@ DESCRIPTION
list all channels list all channels
``` ```
_See code: [src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/channel/list.ts)_ _See code: [packages/eas-cli/src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/channel/list.ts)_
## `eas channel:rollout [CHANNEL]` ## `eas channel:rollout [CHANNEL]`
@@ -700,14 +752,15 @@ FLAGS
--action=create --action=create
--private-key-path=<value> File containing the PEM-encoded private key corresponding to the certificate --private-key-path=<value> File containing the PEM-encoded private key corresponding to the certificate
in expo-updates' configuration. Defaults to a file named "private-key.pem" in in expo-updates' configuration. Defaults to a file named "private-key.pem" in
the certificate's directory. the certificate's directory. Only relevant if you are using code signing:
https://docs.expo.dev/eas-update/code-signing/
--runtime-version=<value> Runtime version to target. Use with --action=create --runtime-version=<value> Runtime version to target. Use with --action=create
DESCRIPTION DESCRIPTION
Roll a new branch out on a channel incrementally. Roll a new branch out on a channel incrementally.
``` ```
_See code: [src/commands/channel/rollout.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/channel/rollout.ts)_ _See code: [packages/eas-cli/src/commands/channel/rollout.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/channel/rollout.ts)_
## `eas channel:view [NAME]` ## `eas channel:view [NAME]`
@@ -730,7 +783,7 @@ DESCRIPTION
view a channel view a channel
``` ```
_See code: [src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/channel/view.ts)_ _See code: [packages/eas-cli/src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/channel/view.ts)_
## `eas config` ## `eas config`
@@ -751,7 +804,7 @@ DESCRIPTION
display project configuration (app.json + eas.json) display project configuration (app.json + eas.json)
``` ```
_See code: [src/commands/config.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/config.ts)_ _See code: [packages/eas-cli/src/commands/config.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/config.ts)_
## `eas credentials` ## `eas credentials`
@@ -768,7 +821,25 @@ DESCRIPTION
manage credentials manage credentials
``` ```
_See code: [src/commands/credentials.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/credentials.ts)_ _See code: [packages/eas-cli/src/commands/credentials/index.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/credentials/index.ts)_
## `eas credentials:configure-build`
Set up credentials for building your project.
```
USAGE
$ eas credentials:configure-build [-p android|ios] [-e <value>]
FLAGS
-e, --profile=PROFILE_NAME The name of the build profile in eas.json.
-p, --platform=(android|ios)
DESCRIPTION
Set up credentials for building your project.
```
_See code: [packages/eas-cli/src/commands/credentials/configure-build.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/credentials/configure-build.ts)_
## `eas device:create` ## `eas device:create`
@@ -782,7 +853,7 @@ DESCRIPTION
register new Apple Devices to use for internal distribution register new Apple Devices to use for internal distribution
``` ```
_See code: [src/commands/device/create.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/device/create.ts)_ _See code: [packages/eas-cli/src/commands/device/create.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/device/create.ts)_
## `eas device:delete` ## `eas device:delete`
@@ -802,7 +873,7 @@ DESCRIPTION
remove a registered device from your account remove a registered device from your account
``` ```
_See code: [src/commands/device/delete.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/device/delete.ts)_ _See code: [packages/eas-cli/src/commands/device/delete.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/device/delete.ts)_
## `eas device:list` ## `eas device:list`
@@ -823,7 +894,7 @@ DESCRIPTION
list all registered devices for your account list all registered devices for your account
``` ```
_See code: [src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/device/list.ts)_ _See code: [packages/eas-cli/src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/device/list.ts)_
## `eas device:rename` ## `eas device:rename`
@@ -844,7 +915,7 @@ DESCRIPTION
rename a registered device rename a registered device
``` ```
_See code: [src/commands/device/rename.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/device/rename.ts)_ _See code: [packages/eas-cli/src/commands/device/rename.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/device/rename.ts)_
## `eas device:view [UDID]` ## `eas device:view [UDID]`
@@ -858,7 +929,7 @@ DESCRIPTION
view a device for your project view a device for your project
``` ```
_See code: [src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/device/view.ts)_ _See code: [packages/eas-cli/src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/device/view.ts)_
## `eas diagnostics` ## `eas diagnostics`
@@ -872,7 +943,7 @@ DESCRIPTION
display environment info display environment info
``` ```
_See code: [src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/diagnostics.ts)_ _See code: [packages/eas-cli/src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/diagnostics.ts)_
## `eas help [COMMAND]` ## `eas help [COMMAND]`
@@ -892,7 +963,7 @@ DESCRIPTION
Display help for eas. Display help for eas.
``` ```
_See code: [@expo/plugin-help](https://github.com/expo/oclif-plugin-help/blob/v5.1.23/src/commands/help.ts)_ _See code: [@expo/plugin-help](https://github.com/expo/oclif-plugin-help/blob/v5.1.23/packages/eas-cli/src/commands/help.ts)_
## `eas init` ## `eas init`
@@ -914,13 +985,32 @@ ALIASES
$ eas init $ eas init
``` ```
## `eas init:onboarding [TARGET_PROJECT_DIRECTORY]`
continue onboarding process started on the https://expo.new website.
```
USAGE
$ eas init:onboarding [TARGET_PROJECT_DIRECTORY]
DESCRIPTION
continue onboarding process started on the https://expo.new website.
ALIASES
$ eas init:onboarding
$ eas onboarding
```
## `eas login` ## `eas login`
log in with your Expo account log in with your Expo account
``` ```
USAGE USAGE
$ eas login $ eas login [-s]
FLAGS
-s, --sso Login with SSO
DESCRIPTION DESCRIPTION
log in with your Expo account log in with your Expo account
@@ -960,7 +1050,7 @@ DESCRIPTION
validate the local store configuration validate the local store configuration
``` ```
_See code: [src/commands/metadata/lint.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/metadata/lint.ts)_ _See code: [packages/eas-cli/src/commands/metadata/lint.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/metadata/lint.ts)_
## `eas metadata:pull` ## `eas metadata:pull`
@@ -977,7 +1067,7 @@ DESCRIPTION
generate the local store configuration from the app stores generate the local store configuration from the app stores
``` ```
_See code: [src/commands/metadata/pull.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/metadata/pull.ts)_ _See code: [packages/eas-cli/src/commands/metadata/pull.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/metadata/pull.ts)_
## `eas metadata:push` ## `eas metadata:push`
@@ -994,7 +1084,23 @@ DESCRIPTION
sync the local store configuration to the app stores sync the local store configuration to the app stores
``` ```
_See code: [src/commands/metadata/push.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/metadata/push.ts)_ _See code: [packages/eas-cli/src/commands/metadata/push.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/metadata/push.ts)_
## `eas onboarding [TARGET_PROJECT_DIRECTORY]`
continue onboarding process started on the https://expo.new website.
```
USAGE
$ eas onboarding [TARGET_PROJECT_DIRECTORY]
DESCRIPTION
continue onboarding process started on the https://expo.new website.
ALIASES
$ eas init:onboarding
$ eas onboarding
```
## `eas open` ## `eas open`
@@ -1008,7 +1114,7 @@ DESCRIPTION
open the project page in a web browser open the project page in a web browser
``` ```
_See code: [src/commands/open.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/open.ts)_ _See code: [packages/eas-cli/src/commands/open.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/open.ts)_
## `eas project:info` ## `eas project:info`
@@ -1022,7 +1128,7 @@ DESCRIPTION
information about the current project information about the current project
``` ```
_See code: [src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/project/info.ts)_ _See code: [packages/eas-cli/src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/project/info.ts)_
## `eas project:init` ## `eas project:init`
@@ -1044,7 +1150,25 @@ ALIASES
$ eas init $ eas init
``` ```
_See code: [src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/project/init.ts)_ _See code: [packages/eas-cli/src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/project/init.ts)_
## `eas project:onboarding [TARGET_PROJECT_DIRECTORY]`
continue onboarding process started on the https://expo.new website.
```
USAGE
$ eas project:onboarding [TARGET_PROJECT_DIRECTORY]
DESCRIPTION
continue onboarding process started on the https://expo.new website.
ALIASES
$ eas init:onboarding
$ eas onboarding
```
_See code: [packages/eas-cli/src/commands/project/onboarding.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/project/onboarding.ts)_
## `eas secret:create` ## `eas secret:create`
@@ -1067,7 +1191,7 @@ DESCRIPTION
create an environment secret on the current project or owner account create an environment secret on the current project or owner account
``` ```
_See code: [src/commands/secret/create.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/secret/create.ts)_ _See code: [packages/eas-cli/src/commands/secret/create.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/secret/create.ts)_
## `eas secret:delete` ## `eas secret:delete`
@@ -1085,7 +1209,7 @@ DESCRIPTION
delete an environment secret by ID delete an environment secret by ID
``` ```
_See code: [src/commands/secret/delete.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/secret/delete.ts)_ _See code: [packages/eas-cli/src/commands/secret/delete.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/secret/delete.ts)_
## `eas secret:list` ## `eas secret:list`
@@ -1099,7 +1223,7 @@ DESCRIPTION
list environment secrets available for your current app list environment secrets available for your current app
``` ```
_See code: [src/commands/secret/list.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/secret/list.ts)_ _See code: [packages/eas-cli/src/commands/secret/list.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/secret/list.ts)_
## `eas secret:push` ## `eas secret:push`
@@ -1119,7 +1243,7 @@ DESCRIPTION
read environment secrets from env file and store on the server read environment secrets from env file and store on the server
``` ```
_See code: [src/commands/secret/push.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/secret/push.ts)_ _See code: [packages/eas-cli/src/commands/secret/push.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/secret/push.ts)_
## `eas submit` ## `eas submit`
@@ -1128,7 +1252,7 @@ submit app binary to App Store and/or Play Store
``` ```
USAGE USAGE
$ eas submit [-p android|ios|all] [-e <value>] [--latest | --id <value> | --path <value> | --url <value>] $ eas submit [-p android|ios|all] [-e <value>] [--latest | --id <value> | --path <value> | --url <value>]
[--verbose] [--wait] [--non-interactive] [--verbose] [--wait] [--verbose-fastlane] [--non-interactive]
FLAGS FLAGS
-e, --profile=<value> Name of the submit profile from eas.json. Defaults to "production" if defined in -e, --profile=<value> Name of the submit profile from eas.json. Defaults to "production" if defined in
@@ -1140,6 +1264,7 @@ FLAGS
--path=<value> Path to the .apk/.aab/.ipa file --path=<value> Path to the .apk/.aab/.ipa file
--url=<value> App archive url --url=<value> App archive url
--verbose Always print logs from EAS Submit --verbose Always print logs from EAS Submit
--verbose-fastlane Enable verbose logging for the submission process
--[no-]wait Wait for submission to complete --[no-]wait Wait for submission to complete
DESCRIPTION DESCRIPTION
@@ -1149,7 +1274,7 @@ ALIASES
$ eas build:submit $ eas build:submit
``` ```
_See code: [src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/submit.ts)_ _See code: [packages/eas-cli/src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/submit.ts)_
## `eas update` ## `eas update`
@@ -1158,8 +1283,8 @@ publish an update group
``` ```
USAGE USAGE
$ eas update [--branch <value>] [--channel <value>] [-m <value>] [--republish | --input-dir <value> | $ eas update [--branch <value>] [--channel <value>] [-m <value>] [--republish | --input-dir <value> |
--skip-bundler] [--group <value> | | ] [--clear-cache] [-p android|ios|all] [--dev] [--auto] [--private-key-path --skip-bundler] [--group <value> | | ] [--clear-cache] [-p android|ios|all] [--auto] [--private-key-path <value>]
<value>] [--json --non-interactive] [--json --non-interactive]
FLAGS FLAGS
-m, --message=<value> A short message describing the update -m, --message=<value> A short message describing the update
@@ -1168,14 +1293,14 @@ FLAGS
--branch=<value> Branch to publish the update group on --branch=<value> Branch to publish the update group on
--channel=<value> Channel that the published update should affect --channel=<value> Channel that the published update should affect
--clear-cache Clear the bundler cache before publishing --clear-cache Clear the bundler cache before publishing
--dev Publish a development bundle
--group=<value> Update group to republish (deprecated, see republish command) --group=<value> Update group to republish (deprecated, see republish command)
--input-dir=<value> [default: dist] Location of the bundle --input-dir=<value> [default: dist] Location of the bundle
--json Enable JSON output, non-JSON messages will be printed to stderr. --json Enable JSON output, non-JSON messages will be printed to stderr.
--non-interactive Run the command in non-interactive mode. --non-interactive Run the command in non-interactive mode.
--private-key-path=<value> File containing the PEM-encoded private key corresponding to the certificate in --private-key-path=<value> File containing the PEM-encoded private key corresponding to the certificate in
expo-updates' configuration. Defaults to a file named "private-key.pem" in the expo-updates' configuration. Defaults to a file named "private-key.pem" in the
certificate's directory. certificate's directory. Only relevant if you are using code signing:
https://docs.expo.dev/eas-update/code-signing/
--republish Republish an update group (deprecated, see republish command) --republish Republish an update group (deprecated, see republish command)
--skip-bundler Skip running Expo CLI to bundle the app before publishing --skip-bundler Skip running Expo CLI to bundle the app before publishing
@@ -1183,7 +1308,7 @@ DESCRIPTION
publish an update group publish an update group
``` ```
_See code: [src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/update/index.ts)_ _See code: [packages/eas-cli/src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/update/index.ts)_
## `eas update:configure` ## `eas update:configure`
@@ -1201,7 +1326,7 @@ DESCRIPTION
configure the project to support EAS Update configure the project to support EAS Update
``` ```
_See code: [src/commands/update/configure.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/update/configure.ts)_ _See code: [packages/eas-cli/src/commands/update/configure.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/update/configure.ts)_
## `eas update:delete GROUPID` ## `eas update:delete GROUPID`
@@ -1222,7 +1347,7 @@ DESCRIPTION
delete all the updates in an update group delete all the updates in an update group
``` ```
_See code: [src/commands/update/delete.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/update/delete.ts)_ _See code: [packages/eas-cli/src/commands/update/delete.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/update/delete.ts)_
## `eas update:list` ## `eas update:list`
@@ -1244,7 +1369,7 @@ DESCRIPTION
view the recent updates view the recent updates
``` ```
_See code: [src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/update/list.ts)_ _See code: [packages/eas-cli/src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/update/list.ts)_
## `eas update:republish` ## `eas update:republish`
@@ -1265,13 +1390,14 @@ FLAGS
--non-interactive Run the command in non-interactive mode. --non-interactive Run the command in non-interactive mode.
--private-key-path=<value> File containing the PEM-encoded private key corresponding to the certificate in --private-key-path=<value> File containing the PEM-encoded private key corresponding to the certificate in
expo-updates' configuration. Defaults to a file named "private-key.pem" in the expo-updates' configuration. Defaults to a file named "private-key.pem" in the
certificate's directory. certificate's directory. Only relevant if you are using code signing:
https://docs.expo.dev/eas-update/code-signing/
DESCRIPTION DESCRIPTION
roll back to an existing update roll back to an existing update
``` ```
_See code: [src/commands/update/republish.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/update/republish.ts)_ _See code: [packages/eas-cli/src/commands/update/republish.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/update/republish.ts)_
## `eas update:roll-back-to-embedded` ## `eas update:roll-back-to-embedded`
@@ -1292,13 +1418,14 @@ FLAGS
--non-interactive Run the command in non-interactive mode. --non-interactive Run the command in non-interactive mode.
--private-key-path=<value> File containing the PEM-encoded private key corresponding to the certificate in --private-key-path=<value> File containing the PEM-encoded private key corresponding to the certificate in
expo-updates' configuration. Defaults to a file named "private-key.pem" in the expo-updates' configuration. Defaults to a file named "private-key.pem" in the
certificate's directory. certificate's directory. Only relevant if you are using code signing:
https://docs.expo.dev/eas-update/code-signing/
DESCRIPTION DESCRIPTION
roll back to the embedded update roll back to the embedded update
``` ```
_See code: [src/commands/update/roll-back-to-embedded.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/update/roll-back-to-embedded.ts)_ _See code: [packages/eas-cli/src/commands/update/roll-back-to-embedded.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/update/roll-back-to-embedded.ts)_
## `eas update:rollback` ## `eas update:rollback`
@@ -1311,13 +1438,14 @@ USAGE
FLAGS FLAGS
--private-key-path=<value> File containing the PEM-encoded private key corresponding to the certificate in --private-key-path=<value> File containing the PEM-encoded private key corresponding to the certificate in
expo-updates' configuration. Defaults to a file named "private-key.pem" in the expo-updates' configuration. Defaults to a file named "private-key.pem" in the
certificate's directory. certificate's directory. Only relevant if you are using code signing:
https://docs.expo.dev/eas-update/code-signing/
DESCRIPTION DESCRIPTION
roll back to an embedded update or an existing update roll back to an embedded update or an existing update
``` ```
_See code: [src/commands/update/rollback.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/update/rollback.ts)_ _See code: [packages/eas-cli/src/commands/update/rollback.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/update/rollback.ts)_
## `eas update:view GROUPID` ## `eas update:view GROUPID`
@@ -1337,7 +1465,7 @@ DESCRIPTION
update group details update group details
``` ```
_See code: [src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/update/view.ts)_ _See code: [packages/eas-cli/src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/update/view.ts)_
## `eas webhook:create` ## `eas webhook:create`
@@ -1358,7 +1486,7 @@ DESCRIPTION
create a webhook create a webhook
``` ```
_See code: [src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/webhook/create.ts)_ _See code: [packages/eas-cli/src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/webhook/create.ts)_
## `eas webhook:delete [ID]` ## `eas webhook:delete [ID]`
@@ -1378,7 +1506,7 @@ DESCRIPTION
delete a webhook delete a webhook
``` ```
_See code: [src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/webhook/delete.ts)_ _See code: [packages/eas-cli/src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/webhook/delete.ts)_
## `eas webhook:list` ## `eas webhook:list`
@@ -1396,7 +1524,7 @@ DESCRIPTION
list webhooks list webhooks
``` ```
_See code: [src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/webhook/list.ts)_ _See code: [packages/eas-cli/src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/webhook/list.ts)_
## `eas webhook:update` ## `eas webhook:update`
@@ -1418,7 +1546,7 @@ DESCRIPTION
update a webhook update a webhook
``` ```
_See code: [src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/webhook/update.ts)_ _See code: [packages/eas-cli/src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/webhook/update.ts)_
## `eas webhook:view ID` ## `eas webhook:view ID`
@@ -1435,7 +1563,7 @@ DESCRIPTION
view a webhook view a webhook
``` ```
_See code: [src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/webhook/view.ts)_ _See code: [packages/eas-cli/src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/webhook/view.ts)_
## `eas whoami` ## `eas whoami`
+4697 -1238
View File
File diff suppressed because it is too large. Load diff
+13 -12
View File
@@ -1,21 +1,22 @@
{ {
"name": "eas-cli", "name": "eas-cli",
"description": "EAS command line tool", "description": "EAS command line tool",
"version": "6.0.0", "version": "10.0.2",
"author": "Expo <[email protected]>", "author": "Expo <[email protected]>",
"bin": { "bin": {
"eas": "./bin/run" "eas": "./bin/run"
}, },
"bugs": "https://github.com/expo/eas-cli/issues", "bugs": "https://github.com/expo/eas-cli/issues",
"dependencies": { "dependencies": {
"@expo/apple-utils": "1.3.2", "@expo/apple-utils": "1.7.0",
"@expo/code-signing-certificates": "0.0.5", "@expo/code-signing-certificates": "0.0.5",
"@expo/config": "8.1.2", "@expo/config": "8.5.4",
"@expo/config-plugins": "7.2.4", "@expo/config-plugins": "7.8.4",
"@expo/config-types": "49.0.0", "@expo/config-types": "50.0.0",
"@expo/eas-build-job": "1.0.56", "@expo/eas-build-job": "1.0.117",
"@expo/eas-json": "6.0.0", "@expo/eas-json": "10.0.0",
"@expo/json-file": "8.2.37", "@expo/json-file": "8.2.37",
"@expo/logger": "1.0.117",
"@expo/multipart-body-parser": "1.1.0", "@expo/multipart-body-parser": "1.1.0",
"@expo/osascript": "2.0.33", "@expo/osascript": "2.0.33",
"@expo/package-manager": "1.1.2", "@expo/package-manager": "1.1.2",
@@ -23,11 +24,11 @@
"@expo/plist": "0.0.20", "@expo/plist": "0.0.20",
"@expo/plugin-help": "5.1.23", "@expo/plugin-help": "5.1.23",
"@expo/plugin-warn-if-update-available": "2.5.1", "@expo/plugin-warn-if-update-available": "2.5.1",
"@expo/prebuild-config": "6.2.5", "@expo/prebuild-config": "6.7.3",
"@expo/results": "1.0.0", "@expo/results": "1.0.0",
"@expo/rudder-sdk-node": "1.1.1", "@expo/rudder-sdk-node": "1.1.1",
"@expo/spawn-async": "1.7.0", "@expo/spawn-async": "1.7.0",
"@expo/steps": "1.0.51", "@expo/steps": "1.0.118",
"@expo/timeago.js": "1.0.0", "@expo/timeago.js": "1.0.0",
"@oclif/core": "^1.26.2", "@oclif/core": "^1.26.2",
"@oclif/plugin-autocomplete": "^2.3.10", "@oclif/plugin-autocomplete": "^2.3.10",
@@ -76,7 +77,7 @@
"resolve-from": "5.0.0", "resolve-from": "5.0.0",
"semver": "7.5.4", "semver": "7.5.4",
"slash": "3.0.0", "slash": "3.0.0",
"tar": "6.2.0", "tar": "6.2.1",
"terminal-link": "2.1.1", "terminal-link": "2.1.1",
"tslib": "2.6.2", "tslib": "2.6.2",
"turndown": "7.1.2", "turndown": "7.1.2",
@@ -109,7 +110,7 @@
"@types/wrap-ansi": "3.0.0", "@types/wrap-ansi": "3.0.0",
"axios": "0.27.2", "axios": "0.27.2",
"eslint-plugin-graphql": "4.0.0", "eslint-plugin-graphql": "4.0.0",
"express": "4.18.2", "express": "4.19.2",
"memfs": "3.4.13", "memfs": "3.4.13",
"mockdate": "3.0.5", "mockdate": "3.0.5",
"nock": "13.4.0", "nock": "13.4.0",
@@ -120,7 +121,7 @@
"typescript": "5.3.3" "typescript": "5.3.3"
}, },
"engines": { "engines": {
"node": ">=16.0.0" "node": ">=18.0.0"
}, },
"files": [ "files": [
"/bin", "/bin",
+1 -2
View File
@@ -3,8 +3,7 @@ const fs = require('fs/promises');
(async () => { (async () => {
// Patch `oclif readme` path and link generation // Patch `oclif readme` path and link generation
let readmeContent = await fs.readFile('README.md', 'utf8'); let readmeContent = await fs.readFile('README.md', 'utf8');
readmeContent = readmeContent.replace(/\[build\//g, '[src/'); readmeContent = readmeContent.replace(/src\/commands/g, 'packages/eas-cli/src/commands');
readmeContent = readmeContent.replace(/build\/commands/g, 'packages/eas-cli/src/commands');
await fs.writeFile('README.md', readmeContent); await fs.writeFile('README.md', readmeContent);
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
@@ -24,6 +24,7 @@ export function getMockAppFragment(): AppFragment {
return { return {
id: mockProjectId, id: mockProjectId,
slug: 'testapp', slug: 'testapp',
name: 'testapp',
fullName: '@testuser/testpp', fullName: '@testuser/testpp',
ownerAccount: { ownerAccount: {
id: 'test-account-id', id: 'test-account-id',
@@ -3,13 +3,7 @@ import { v4 as uuid } from 'uuid';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient'; import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
import { selectBuildToCancelAsync } from '../../commands/build/cancel'; import { selectBuildToCancelAsync } from '../../commands/build/cancel';
import { import { AppPlatform, BuildFragment, BuildPriority, BuildStatus } from '../../graphql/generated';
AppPlatform,
BuildFragment,
BuildPriority,
BuildResourceClass,
BuildStatus,
} from '../../graphql/generated';
import { BuildQuery } from '../../graphql/queries/BuildQuery'; import { BuildQuery } from '../../graphql/queries/BuildQuery';
import { confirmAsync, selectAsync } from '../../prompts'; import { confirmAsync, selectAsync } from '../../prompts';
@@ -91,6 +85,6 @@ function createMockBuildFragment({
}, },
}, },
status: BuildStatus.InQueue, status: BuildStatus.InQueue,
resourceClass: BuildResourceClass.AndroidMedium, isForIosSimulator: false,
}; };
} }
@@ -3,13 +3,7 @@ import { v4 as uuid } from 'uuid';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient'; import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
import { selectBuildToDeleteAsync } from '../../commands/build/delete'; import { selectBuildToDeleteAsync } from '../../commands/build/delete';
import { import { AppPlatform, BuildFragment, BuildPriority, BuildStatus } from '../../graphql/generated';
AppPlatform,
BuildFragment,
BuildPriority,
BuildResourceClass,
BuildStatus,
} from '../../graphql/generated';
import { BuildQuery } from '../../graphql/queries/BuildQuery'; import { BuildQuery } from '../../graphql/queries/BuildQuery';
import { confirmAsync, selectAsync } from '../../prompts'; import { confirmAsync, selectAsync } from '../../prompts';
@@ -91,6 +85,6 @@ function createMockBuildFragment({
}, },
}, },
status: BuildStatus.InQueue, status: BuildStatus.InQueue,
resourceClass: BuildResourceClass.AndroidMedium, isForIosSimulator: false,
}; };
} }
@@ -8,7 +8,7 @@ import os from 'os';
import path from 'path'; import path from 'path';
import { getAppBuildGradleAsync, resolveConfigValue } from '../../../project/android/gradleUtils'; import { getAppBuildGradleAsync, resolveConfigValue } from '../../../project/android/gradleUtils';
import { getVcsClient } from '../../../vcs'; import { resolveVcsClient } from '../../../vcs';
import { import {
BumpStrategy, BumpStrategy,
bumpVersionAsync, bumpVersionAsync,
@@ -19,7 +19,7 @@ import {
const fsReal = jest.requireActual('fs').promises as typeof fs; const fsReal = jest.requireActual('fs').promises as typeof fs;
jest.mock('fs'); jest.mock('fs');
const vcsClient = getVcsClient(); const vcsClient = resolveVcsClient();
afterAll(async () => { afterAll(async () => {
// do not remove the following line // do not remove the following line
+4 -4
View File
@@ -1,4 +1,4 @@
import { Android, Job, Metadata, Platform, Workflow } from '@expo/eas-build-job'; import { Android, Metadata, Platform, Workflow } from '@expo/eas-build-job';
import { AppVersionSource } from '@expo/eas-json'; import { AppVersionSource } from '@expo/eas-json';
import chalk from 'chalk'; import chalk from 'chalk';
import nullthrows from 'nullthrows'; import nullthrows from 'nullthrows';
@@ -99,21 +99,21 @@ export async function prepareAndroidBuildAsync(
return await ensureAndroidCredentialsAsync(ctx); return await ensureAndroidCredentialsAsync(ctx);
}, },
syncProjectConfigurationAsync: async () => { syncProjectConfigurationAsync: async () => {
await syncProjectConfigurationAsync(ctx.graphqlClient, { await syncProjectConfigurationAsync({
projectDir: ctx.projectDir, projectDir: ctx.projectDir,
exp: ctx.exp, exp: ctx.exp,
localAutoIncrement: localAutoIncrement:
ctx.easJsonCliConfig?.appVersionSource === AppVersionSource.REMOTE ctx.easJsonCliConfig?.appVersionSource === AppVersionSource.REMOTE
? false ? false
: ctx.buildProfile.autoIncrement, : ctx.buildProfile.autoIncrement,
projectId: ctx.projectId,
vcsClient: ctx.vcsClient, vcsClient: ctx.vcsClient,
env: ctx.buildProfile.env,
}); });
}, },
prepareJobAsync: async ( prepareJobAsync: async (
ctx: BuildContext<Platform.ANDROID>, ctx: BuildContext<Platform.ANDROID>,
jobData: JobData<AndroidCredentials> jobData: JobData<AndroidCredentials>
): Promise<Job> => { ): Promise<Android.Job> => {
return await prepareJobAsync(ctx, jobData); return await prepareJobAsync(ctx, jobData);
}, },
sendBuildRequestAsync: async ( sendBuildRequestAsync: async (
@@ -2,6 +2,7 @@ import { Android } from '@expo/eas-build-job';
import { AndroidBuildType, AndroidJobInput } from '../../graphql/generated'; import { AndroidBuildType, AndroidJobInput } from '../../graphql/generated';
import { import {
loggerLevelToGraphQLWorkerLoggerLevel,
transformBuildMode, transformBuildMode,
transformBuildTrigger, transformBuildTrigger,
transformProjectArchive, transformProjectArchive,
@@ -14,7 +15,6 @@ export function transformJob(job: Android.Job): AndroidJobInput {
triggeredBy: transformBuildTrigger(job.triggeredBy), triggeredBy: transformBuildTrigger(job.triggeredBy),
projectArchive: transformProjectArchive(job.projectArchive), projectArchive: transformProjectArchive(job.projectArchive),
projectRootDirectory: job.projectRootDirectory, projectRootDirectory: job.projectRootDirectory,
releaseChannel: job.releaseChannel,
updates: job.updates, updates: job.updates,
secrets: job.secrets, secrets: job.secrets,
builderEnvironment: job.builderEnvironment, builderEnvironment: job.builderEnvironment,
@@ -29,6 +29,9 @@ export function transformJob(job: Android.Job): AndroidJobInput {
experimental: job.experimental, experimental: job.experimental,
mode: transformBuildMode(job.mode), mode: transformBuildMode(job.mode),
customBuildConfig: job.customBuildConfig, customBuildConfig: job.customBuildConfig,
loggerLevel: job.loggerLevel
? loggerLevelToGraphQLWorkerLoggerLevel[job.loggerLevel]
: undefined,
}; };
} }
@@ -3,16 +3,15 @@ import {
ArchiveSource, ArchiveSource,
BuildMode, BuildMode,
BuildTrigger, BuildTrigger,
Job,
Platform, Platform,
sanitizeJob, sanitizeBuildJob,
} from '@expo/eas-build-job'; } from '@expo/eas-build-job';
import { BuildProfile } from '@expo/eas-json'; import { BuildProfile } from '@expo/eas-json';
import path from 'path'; import path from 'path';
import slash from 'slash'; import slash from 'slash';
import { AndroidCredentials } from '../../credentials/android/AndroidCredentialsProvider'; import { AndroidCredentials } from '../../credentials/android/AndroidCredentialsProvider';
import { getCustomBuildConfigPath } from '../../project/customBuildConfig'; import { getCustomBuildConfigPathForJob } from '../../project/customBuildConfig';
import { getUsername } from '../../project/projectUtils'; import { getUsername } from '../../project/projectUtils';
import { BuildContext } from '../context'; import { BuildContext } from '../context';
@@ -29,7 +28,7 @@ const cacheDefaults = {
export async function prepareJobAsync( export async function prepareJobAsync(
ctx: BuildContext<Platform.ANDROID>, ctx: BuildContext<Platform.ANDROID>,
jobData: JobData jobData: JobData
): Promise<Job> { ): Promise<Android.Job> {
const username = getUsername(ctx.exp, ctx.user); const username = getUsername(ctx.exp, ctx.user);
const buildProfile: BuildProfile<Platform.ANDROID> = ctx.buildProfile; const buildProfile: BuildProfile<Platform.ANDROID> = ctx.buildProfile;
const projectRootDirectory = const projectRootDirectory =
@@ -54,9 +53,18 @@ export async function prepareJobAsync(
} }
const maybeCustomBuildConfigPath = buildProfile.config const maybeCustomBuildConfigPath = buildProfile.config
? getCustomBuildConfigPath(buildProfile.config) ? getCustomBuildConfigPathForJob(buildProfile.config)
: undefined; : undefined;
let buildMode;
if (ctx.repack) {
buildMode = BuildMode.REPACK;
} else if (buildProfile.config) {
buildMode = BuildMode.CUSTOM;
} else {
buildMode = BuildMode.BUILD;
}
const job: Android.Job = { const job: Android.Job = {
type: ctx.workflow, type: ctx.workflow,
platform: Platform.ANDROID, platform: Platform.ANDROID,
@@ -69,7 +77,6 @@ export async function prepareJobAsync(
bun: buildProfile.bun, bun: buildProfile.bun,
yarn: buildProfile.yarn, yarn: buildProfile.yarn,
ndk: buildProfile.ndk, ndk: buildProfile.ndk,
expoCli: buildProfile.expoCli,
env: buildProfile.env, env: buildProfile.env,
}, },
cache: { cache: {
@@ -80,7 +87,6 @@ export async function prepareJobAsync(
secrets: { secrets: {
...buildCredentials, ...buildCredentials,
}, },
releaseChannel: buildProfile.releaseChannel,
updates: { channel: buildProfile.channel }, updates: { channel: buildProfile.channel },
developmentClient: buildProfile.developmentClient, developmentClient: buildProfile.developmentClient,
gradleCommand: buildProfile.gradleCommand, gradleCommand: buildProfile.gradleCommand,
@@ -96,14 +102,20 @@ export async function prepareJobAsync(
experimental: { experimental: {
prebuildCommand: buildProfile.prebuildCommand, prebuildCommand: buildProfile.prebuildCommand,
}, },
mode: buildProfile.config ? BuildMode.CUSTOM : BuildMode.BUILD, mode: buildMode,
triggeredBy: BuildTrigger.EAS_CLI, triggeredBy: BuildTrigger.EAS_CLI,
...(maybeCustomBuildConfigPath && { ...(maybeCustomBuildConfigPath && {
customBuildConfig: { customBuildConfig: {
path: maybeCustomBuildConfigPath, path: maybeCustomBuildConfigPath,
}, },
}), }),
...(ctx.repack && {
customBuildConfig: {
path: '__eas/repack.yml',
},
}),
loggerLevel: ctx.loggerLevel,
}; };
return sanitizeJob(job); return sanitizeBuildJob(job) as Android.Job;
} }
@@ -1,42 +1,38 @@
import { ExpoConfig } from '@expo/config'; import { ExpoConfig } from '@expo/config';
import { AndroidConfig } from '@expo/config-plugins'; import { AndroidConfig } from '@expo/config-plugins';
import { Platform, Workflow } from '@expo/eas-build-job'; import { Env, Platform, Workflow } from '@expo/eas-build-job';
import { AndroidVersionAutoIncrement } from '@expo/eas-json'; import { AndroidVersionAutoIncrement } from '@expo/eas-json';
import chalk from 'chalk'; import chalk from 'chalk';
import fs from 'fs-extra'; import fs from 'fs-extra';
import path from 'path'; import path from 'path';
import { BumpStrategy, bumpVersionAsync, bumpVersionInAppJsonAsync } from './version'; import { BumpStrategy, bumpVersionAsync, bumpVersionInAppJsonAsync } from './version';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
import Log from '../../log'; import Log from '../../log';
import { isExpoUpdatesInstalled } from '../../project/projectUtils'; import { isExpoUpdatesInstalled } from '../../project/projectUtils';
import { resolveWorkflowAsync } from '../../project/workflow'; import { resolveWorkflowAsync } from '../../project/workflow';
import { syncUpdatesConfigurationAsync } from '../../update/android/UpdatesModule'; import { syncUpdatesConfigurationAsync } from '../../update/android/UpdatesModule';
import { Client } from '../../vcs/vcs'; import { Client } from '../../vcs/vcs';
export async function syncProjectConfigurationAsync( export async function syncProjectConfigurationAsync({
graphqlClient: ExpoGraphqlClient,
{
projectDir, projectDir,
exp, exp,
localAutoIncrement, localAutoIncrement,
projectId,
vcsClient, vcsClient,
env,
}: { }: {
projectDir: string; projectDir: string;
exp: ExpoConfig; exp: ExpoConfig;
localAutoIncrement?: AndroidVersionAutoIncrement; localAutoIncrement?: AndroidVersionAutoIncrement;
projectId: string;
vcsClient: Client; vcsClient: Client;
} env: Env | undefined;
): Promise<void> { }): Promise<void> {
const workflow = await resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient); const workflow = await resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient);
const versionBumpStrategy = resolveVersionBumpStrategy(localAutoIncrement ?? false); const versionBumpStrategy = resolveVersionBumpStrategy(localAutoIncrement ?? false);
if (workflow === Workflow.GENERIC) { if (workflow === Workflow.GENERIC) {
await cleanUpOldEasBuildGradleScriptAsync(projectDir); await cleanUpOldEasBuildGradleScriptAsync(projectDir);
if (isExpoUpdatesInstalled(projectDir)) { if (isExpoUpdatesInstalled(projectDir)) {
await syncUpdatesConfigurationAsync(graphqlClient, projectDir, exp, projectId); await syncUpdatesConfigurationAsync({ projectDir, exp, workflow, env });
} }
await bumpVersionAsync({ projectDir, exp, bumpStrategy: versionBumpStrategy }); await bumpVersionAsync({ projectDir, exp, bumpStrategy: versionBumpStrategy });
} else { } else {
@@ -232,7 +232,9 @@ export async function resolveRemoteVersionCodeAsync(
applicationIdentifier: applicationId, applicationIdentifier: applicationId,
storeVersion: localVersions.appVersion ?? exp.version ?? '1.0.0', storeVersion: localVersions.appVersion ?? exp.version ?? '1.0.0',
buildVersion: currentBuildVersion, buildVersion: currentBuildVersion,
runtimeVersion: Updates.getRuntimeVersionNullable(exp, Platform.ANDROID) ?? undefined, runtimeVersion:
(await Updates.getRuntimeVersionNullableAsync(projectDir, exp, Platform.ANDROID)) ??
undefined,
}); });
spinner.succeed(`Initialized versionCode with ${chalk.bold(currentBuildVersion)}.`); spinner.succeed(`Initialized versionCode with ${chalk.bold(currentBuildVersion)}.`);
} catch (err) { } catch (err) {
@@ -254,7 +256,9 @@ export async function resolveRemoteVersionCodeAsync(
applicationIdentifier: applicationId, applicationIdentifier: applicationId,
storeVersion: localVersions.appVersion ?? exp.version ?? '1.0.0', storeVersion: localVersions.appVersion ?? exp.version ?? '1.0.0',
buildVersion: String(nextBuildVersion), buildVersion: String(nextBuildVersion),
runtimeVersion: Updates.getRuntimeVersionNullable(exp, Platform.ANDROID) ?? undefined, runtimeVersion:
(await Updates.getRuntimeVersionNullableAsync(projectDir, exp, Platform.ANDROID)) ??
undefined,
}); });
spinner.succeed( spinner.succeed(
`Incremented versionCode from ${chalk.bold(currentBuildVersion)} to ${chalk.bold( `Incremented versionCode from ${chalk.bold(currentBuildVersion)} to ${chalk.bold(
+73 -16
View File
@@ -1,4 +1,10 @@
import { ArchiveSource, ArchiveSourceType, Job, Metadata, Platform } from '@expo/eas-build-job'; import {
ArchiveSource,
ArchiveSourceType,
BuildJob,
Metadata,
Platform,
} from '@expo/eas-build-job';
import { CredentialsSource } from '@expo/eas-json'; import { CredentialsSource } from '@expo/eas-json';
import assert from 'assert'; import assert from 'assert';
import chalk from 'chalk'; import chalk from 'chalk';
@@ -26,7 +32,12 @@ import { transformMetadata } from './graphql';
import { LocalBuildMode, runLocalBuildAsync } from './local'; import { LocalBuildMode, runLocalBuildAsync } from './local';
import { collectMetadataAsync } from './metadata'; import { collectMetadataAsync } from './metadata';
import { printDeprecationWarnings } from './utils/printBuildInfo'; import { printDeprecationWarnings } from './utils/printBuildInfo';
import { makeProjectTarballAsync, reviewAndCommitChangesAsync } from './utils/repository'; import {
LocalFile,
makeProjectMetadataFileAsync,
makeProjectTarballAsync,
reviewAndCommitChangesAsync,
} from './utils/repository';
import { BuildEvent } from '../analytics/AnalyticsManager'; import { BuildEvent } from '../analytics/AnalyticsManager';
import { withAnalyticsAsync } from '../analytics/common'; import { withAnalyticsAsync } from '../analytics/common';
import { getExpoWebsiteBaseUrl } from '../api'; import { getExpoWebsiteBaseUrl } from '../api';
@@ -65,14 +76,14 @@ export interface JobData<Credentials> {
projectArchive: ArchiveSource; projectArchive: ArchiveSource;
} }
interface Builder<TPlatform extends Platform, Credentials, TJob extends Job> { interface Builder<TPlatform extends Platform, Credentials, TJob extends BuildJob> {
ctx: BuildContext<TPlatform>; ctx: BuildContext<TPlatform>;
ensureCredentialsAsync( ensureCredentialsAsync(
ctx: BuildContext<TPlatform> ctx: BuildContext<TPlatform>
): Promise<CredentialsResult<Credentials> | undefined>; ): Promise<CredentialsResult<Credentials> | undefined>;
syncProjectConfigurationAsync(ctx: BuildContext<TPlatform>): Promise<void>; syncProjectConfigurationAsync(ctx: BuildContext<TPlatform>): Promise<void>;
prepareJobAsync(ctx: BuildContext<TPlatform>, jobData: JobData<Credentials>): Promise<Job>; prepareJobAsync(ctx: BuildContext<TPlatform>, jobData: JobData<Credentials>): Promise<BuildJob>;
sendBuildRequestAsync( sendBuildRequestAsync(
appId: string, appId: string,
job: TJob, job: TJob,
@@ -97,7 +108,7 @@ function resolveBuildParamsInput<T extends Platform>(
export async function prepareBuildRequestForPlatformAsync< export async function prepareBuildRequestForPlatformAsync<
TPlatform extends Platform, TPlatform extends Platform,
Credentials, Credentials,
TJob extends Job, TJob extends BuildJob,
>(builder: Builder<TPlatform, Credentials, TJob>): Promise<BuildRequestSender> { >(builder: Builder<TPlatform, Credentials, TJob>): Promise<BuildRequestSender> {
const { ctx } = builder; const { ctx } = builder;
const credentialsResult = await withAnalyticsAsync( const credentialsResult = await withAnalyticsAsync(
@@ -133,9 +144,10 @@ export async function prepareBuildRequestForPlatformAsync<
let projectArchive: ArchiveSource | undefined; let projectArchive: ArchiveSource | undefined;
if (ctx.localBuildOptions.localBuildMode === LocalBuildMode.LOCAL_BUILD_PLUGIN) { if (ctx.localBuildOptions.localBuildMode === LocalBuildMode.LOCAL_BUILD_PLUGIN) {
const projectPath = (await makeProjectTarballAsync(ctx.vcsClient)).path;
projectArchive = { projectArchive = {
type: ArchiveSourceType.PATH, type: ArchiveSourceType.PATH,
path: (await makeProjectTarballAsync(ctx.vcsClient)).path, path: projectPath,
}; };
} else if (ctx.localBuildOptions.localBuildMode === LocalBuildMode.INTERNAL) { } else if (ctx.localBuildOptions.localBuildMode === LocalBuildMode.INTERNAL) {
projectArchive = { projectArchive = {
@@ -145,7 +157,7 @@ export async function prepareBuildRequestForPlatformAsync<
} else if (!ctx.localBuildOptions.localBuildMode) { } else if (!ctx.localBuildOptions.localBuildMode) {
projectArchive = { projectArchive = {
type: ArchiveSourceType.GCS, type: ArchiveSourceType.GCS,
bucketKey: await uploadProjectAsync(ctx), ...(await uploadProjectAsync(ctx)),
}; };
} }
assert(projectArchive); assert(projectArchive);
@@ -231,7 +243,10 @@ export function handleBuildRequestError(error: any, platform: Platform): never {
async function uploadProjectAsync<TPlatform extends Platform>( async function uploadProjectAsync<TPlatform extends Platform>(
ctx: BuildContext<TPlatform> ctx: BuildContext<TPlatform>
): Promise<string> { ): Promise<{
bucketKey: string;
metadataLocation?: string;
}> {
let projectTarballPath; let projectTarballPath;
try { try {
return await withAnalyticsAsync( return await withAnalyticsAsync(
@@ -260,21 +275,27 @@ async function uploadProjectAsync<TPlatform extends Platform>(
} }
projectTarballPath = projectTarball.path; projectTarballPath = projectTarball.path;
const [bucketKey, { metadataLocation }] = await Promise.all([
const bucketKey = await uploadFileAtPathToGCSAsync( uploadFileAtPathToGCSAsync(
ctx.graphqlClient, ctx.graphqlClient,
UploadSessionType.EasBuildGcsProjectSources, UploadSessionType.EasBuildGcsProjectSources,
projectTarball.path, projectTarball.path,
createProgressTracker({ createProgressTracker({
total: projectTarball.size, total: projectTarball.size,
message: ratio => message: ratio =>
`Uploading to EAS Build (${formatBytes(projectTarball.size * ratio)} / ${formatBytes( `Uploading to EAS Build (${formatBytes(
projectTarball.size projectTarball.size * ratio
)})`, )} / ${formatBytes(projectTarball.size)})`,
completedMessage: (duration: string) => `Uploaded to EAS ${chalk.dim(duration)}`, completedMessage: (duration: string) => `Uploaded to EAS ${chalk.dim(duration)}`,
}) })
); ),
return bucketKey; uploadMetadataFileAsync<TPlatform>(projectTarball, ctx),
]);
if (metadataLocation) {
return { bucketKey, metadataLocation };
}
return { bucketKey };
}, },
{ {
attemptEvent: BuildEvent.PROJECT_UPLOAD_ATTEMPT, attemptEvent: BuildEvent.PROJECT_UPLOAD_ATTEMPT,
@@ -285,9 +306,11 @@ async function uploadProjectAsync<TPlatform extends Platform>(
); );
} catch (err: any) { } catch (err: any) {
let errMessage = 'Failed to upload the project tarball to EAS Build'; let errMessage = 'Failed to upload the project tarball to EAS Build';
if (err.message) { if (err.message) {
errMessage += `\n\nReason: ${err.message}`; errMessage += `\n\nReason: ${err.message}`;
} }
throw new EasBuildProjectArchiveUploadError(errMessage); throw new EasBuildProjectArchiveUploadError(errMessage);
} finally { } finally {
if (projectTarballPath) { if (projectTarballPath) {
@@ -296,7 +319,41 @@ async function uploadProjectAsync<TPlatform extends Platform>(
} }
} }
async function sendBuildRequestAsync<TPlatform extends Platform, Credentials, TJob extends Job>( async function uploadMetadataFileAsync<TPlatform extends Platform>(
projectTarball: LocalFile,
ctx: BuildContext<TPlatform>
): Promise<{ metadataLocation: string | null }> {
let projectMetadataFile: LocalFile | null = null;
try {
projectMetadataFile = await makeProjectMetadataFileAsync(projectTarball.path);
const metadataLocation = await uploadFileAtPathToGCSAsync(
ctx.graphqlClient,
UploadSessionType.EasBuildGcsProjectMetadata,
projectMetadataFile.path
);
return { metadataLocation };
} catch (err: any) {
let errMessage = 'Failed to upload metadata to EAS Build';
if (err.message) {
errMessage += `\n\nReason: ${err.message}`;
}
Log.warn(errMessage);
return { metadataLocation: null };
} finally {
if (projectMetadataFile) {
await fs.remove(projectMetadataFile.path);
}
}
}
async function sendBuildRequestAsync<
TPlatform extends Platform,
Credentials,
TJob extends BuildJob,
>(
builder: Builder<TPlatform, Credentials, TJob>, builder: Builder<TPlatform, Credentials, TJob>,
job: TJob, job: TJob,
metadata: Metadata, metadata: Metadata,
+1 -1
View File
@@ -40,7 +40,7 @@ async function configureAsync({
nonInteractive, nonInteractive,
vcsClient, vcsClient,
}: ConfigureParams): Promise<void> { }: ConfigureParams): Promise<void> {
await maybeBailOnRepoStatusAsync(vcsClient); await maybeBailOnRepoStatusAsync(vcsClient, nonInteractive);
await createEasJsonAsync(projectDir, vcsClient); await createEasJsonAsync(projectDir, vcsClient);
+3
View File
@@ -1,6 +1,7 @@
import { ExpoConfig } from '@expo/config'; import { ExpoConfig } from '@expo/config';
import { Platform, Workflow } from '@expo/eas-build-job'; import { Platform, Workflow } from '@expo/eas-build-job';
import { BuildProfile, EasJson } from '@expo/eas-json'; import { BuildProfile, EasJson } from '@expo/eas-json';
import { LoggerLevel } from '@expo/logger';
import { NodePackageManager } from '@expo/package-manager'; import { NodePackageManager } from '@expo/package-manager';
import { LocalBuildOptions } from './local'; import { LocalBuildOptions } from './local';
@@ -60,4 +61,6 @@ export interface BuildContext<T extends Platform> {
developmentClient: boolean; developmentClient: boolean;
requiredPackageManager: NodePackageManager['name'] | null; requiredPackageManager: NodePackageManager['name'] | null;
vcsClient: Client; vcsClient: Client;
loggerLevel?: LoggerLevel;
repack: boolean;
} }
@@ -1,6 +1,7 @@
import { Platform } from '@expo/eas-build-job'; import { Platform } from '@expo/eas-build-job';
import { BuildProfile, EasJson, ResourceClass } from '@expo/eas-json'; import { BuildProfile, EasJson, ResourceClass } from '@expo/eas-json';
import JsonFile from '@expo/json-file'; import JsonFile from '@expo/json-file';
import { LoggerLevel } from '@expo/logger';
import { resolvePackageManager } from '@expo/package-manager'; import { resolvePackageManager } from '@expo/package-manager';
import getenv from 'getenv'; import getenv from 'getenv';
import resolveFrom from 'resolve-from'; import resolveFrom from 'resolve-from';
@@ -39,6 +40,9 @@ export async function createBuildContextAsync<T extends Platform>({
vcsClient, vcsClient,
getDynamicPrivateProjectConfigAsync, getDynamicPrivateProjectConfigAsync,
customBuildConfigMetadata, customBuildConfigMetadata,
buildLoggerLevel,
freezeCredentials,
repack,
}: { }: {
buildProfileName: string; buildProfileName: string;
buildProfile: BuildProfile<T>; buildProfile: BuildProfile<T>;
@@ -57,6 +61,9 @@ export async function createBuildContextAsync<T extends Platform>({
vcsClient: Client; vcsClient: Client;
getDynamicPrivateProjectConfigAsync: DynamicConfigContextFn; getDynamicPrivateProjectConfigAsync: DynamicConfigContextFn;
customBuildConfigMetadata?: CustomBuildConfigMetadata; customBuildConfigMetadata?: CustomBuildConfigMetadata;
buildLoggerLevel?: LoggerLevel;
freezeCredentials: boolean;
repack: boolean;
}): Promise<BuildContext<T>> { }): Promise<BuildContext<T>> {
const { exp, projectId } = await getDynamicPrivateProjectConfigAsync({ env: buildProfile.env }); const { exp, projectId } = await getDynamicPrivateProjectConfigAsync({ env: buildProfile.env });
const projectName = exp.slug; const projectName = exp.slug;
@@ -83,6 +90,7 @@ export async function createBuildContextAsync<T extends Platform>({
env: buildProfile.env, env: buildProfile.env,
easJsonCliConfig, easJsonCliConfig,
vcsClient, vcsClient,
freezeCredentials,
}); });
const devClientProperties = getDevClientEventProperties({ const devClientProperties = getDevClientEventProperties({
@@ -136,6 +144,8 @@ export async function createBuildContextAsync<T extends Platform>({
customBuildConfigMetadata, customBuildConfigMetadata,
developmentClient, developmentClient,
requiredPackageManager, requiredPackageManager,
loggerLevel: buildLoggerLevel,
repack,
}; };
if (platform === Platform.ANDROID) { if (platform === Platform.ANDROID) {
const common = commonContext as CommonContext<Platform.ANDROID>; const common = commonContext as CommonContext<Platform.ANDROID>;
+13
View File
@@ -6,6 +6,7 @@ import {
Metadata, Metadata,
Workflow, Workflow,
} from '@expo/eas-build-job'; } from '@expo/eas-build-job';
import { LoggerLevel } from '@expo/logger';
import assert from 'assert'; import assert from 'assert';
import { import {
@@ -18,6 +19,7 @@ import {
BuildTrigger as GraphQLBuildTrigger, BuildTrigger as GraphQLBuildTrigger,
ProjectArchiveSourceInput, ProjectArchiveSourceInput,
ProjectArchiveSourceType, ProjectArchiveSourceType,
WorkerLoggerLevel,
} from '../graphql/generated'; } from '../graphql/generated';
export function transformProjectArchive(archiveSource: ArchiveSource): ProjectArchiveSourceInput { export function transformProjectArchive(archiveSource: ArchiveSource): ProjectArchiveSourceInput {
@@ -25,6 +27,7 @@ export function transformProjectArchive(archiveSource: ArchiveSource): ProjectAr
return { return {
type: ProjectArchiveSourceType.Gcs, type: ProjectArchiveSourceType.Gcs,
bucketKey: archiveSource.bucketKey, bucketKey: archiveSource.bucketKey,
metadataLocation: archiveSource.metadataLocation,
}; };
} else if (archiveSource.type === ArchiveSourceType.URL) { } else if (archiveSource.type === ArchiveSourceType.URL) {
return { return {
@@ -91,6 +94,7 @@ const buildModeToGraphQLBuildMode: Record<BuildMode, GraphQLBuildMode> = {
[BuildMode.BUILD]: GraphQLBuildMode.Build, [BuildMode.BUILD]: GraphQLBuildMode.Build,
[BuildMode.CUSTOM]: GraphQLBuildMode.Custom, [BuildMode.CUSTOM]: GraphQLBuildMode.Custom,
[BuildMode.RESIGN]: GraphQLBuildMode.Resign, [BuildMode.RESIGN]: GraphQLBuildMode.Resign,
[BuildMode.REPACK]: GraphQLBuildMode.Repack,
}; };
export function transformBuildMode(buildMode: BuildMode): GraphQLBuildMode { export function transformBuildMode(buildMode: BuildMode): GraphQLBuildMode {
@@ -107,3 +111,12 @@ export function transformBuildTrigger(buildTrigger: BuildTrigger): GraphQLBuildT
} }
throw new Error('Unknown build trigger'); throw new Error('Unknown build trigger');
} }
export const loggerLevelToGraphQLWorkerLoggerLevel: Record<LoggerLevel, WorkerLoggerLevel> = {
[LoggerLevel.TRACE]: WorkerLoggerLevel.Trace,
[LoggerLevel.DEBUG]: WorkerLoggerLevel.Debug,
[LoggerLevel.INFO]: WorkerLoggerLevel.Info,
[LoggerLevel.WARN]: WorkerLoggerLevel.Warn,
[LoggerLevel.ERROR]: WorkerLoggerLevel.Error,
[LoggerLevel.FATAL]: WorkerLoggerLevel.Fatal,
};
@@ -6,7 +6,7 @@ import os from 'os';
import type { XCBuildConfiguration } from 'xcode'; import type { XCBuildConfiguration } from 'xcode';
import { readPlistAsync } from '../../../utils/plist'; import { readPlistAsync } from '../../../utils/plist';
import { getVcsClient } from '../../../vcs'; import { resolveVcsClient } from '../../../vcs';
import { import {
BumpStrategy, BumpStrategy,
bumpVersionAsync, bumpVersionAsync,
@@ -19,7 +19,7 @@ import {
jest.mock('fs'); jest.mock('fs');
const vcsClient = getVcsClient(); const vcsClient = resolveVcsClient();
const getXCBuildConfigurationFromPbxproj = jest.spyOn( const getXCBuildConfigurationFromPbxproj = jest.spyOn(
IOSConfig.Target, IOSConfig.Target,
+4 -4
View File
@@ -1,4 +1,4 @@
import { Ios, Job, Metadata, Platform, Workflow } from '@expo/eas-build-job'; import { Ios, Metadata, Platform, Workflow } from '@expo/eas-build-job';
import { AppVersionSource } from '@expo/eas-json'; import { AppVersionSource } from '@expo/eas-json';
import { ensureIosCredentialsAsync } from './credentials'; import { ensureIosCredentialsAsync } from './credentials';
@@ -80,7 +80,7 @@ export async function prepareIosBuildAsync(
return ensureIosCredentialsAsync(ctx, ctx.ios.targets); return ensureIosCredentialsAsync(ctx, ctx.ios.targets);
}, },
syncProjectConfigurationAsync: async () => { syncProjectConfigurationAsync: async () => {
await syncProjectConfigurationAsync(ctx.graphqlClient, { await syncProjectConfigurationAsync({
projectDir: ctx.projectDir, projectDir: ctx.projectDir,
exp: ctx.exp, exp: ctx.exp,
targets: ctx.ios.targets, targets: ctx.ios.targets,
@@ -88,14 +88,14 @@ export async function prepareIosBuildAsync(
ctx.easJsonCliConfig?.appVersionSource === AppVersionSource.REMOTE ctx.easJsonCliConfig?.appVersionSource === AppVersionSource.REMOTE
? false ? false
: ctx.buildProfile.autoIncrement, : ctx.buildProfile.autoIncrement,
projectId: ctx.projectId,
vcsClient: ctx.vcsClient, vcsClient: ctx.vcsClient,
env: ctx.buildProfile.env,
}); });
}, },
prepareJobAsync: async ( prepareJobAsync: async (
ctx: BuildContext<Platform.IOS>, ctx: BuildContext<Platform.IOS>,
jobData: JobData<IosCredentials> jobData: JobData<IosCredentials>
): Promise<Job> => { ): Promise<Ios.Job> => {
return await prepareJobAsync(ctx, { return await prepareJobAsync(ctx, {
...jobData, ...jobData,
buildScheme: ctx.ios.xcodeBuildContext.buildScheme, buildScheme: ctx.ios.xcodeBuildContext.buildScheme,
+4 -1
View File
@@ -3,6 +3,7 @@ import nullthrows from 'nullthrows';
import { IosJobInput, IosJobSecretsInput } from '../../graphql/generated'; import { IosJobInput, IosJobSecretsInput } from '../../graphql/generated';
import { import {
loggerLevelToGraphQLWorkerLoggerLevel,
transformBuildMode, transformBuildMode,
transformBuildTrigger, transformBuildTrigger,
transformProjectArchive, transformProjectArchive,
@@ -15,7 +16,6 @@ export function transformJob(job: Ios.Job): IosJobInput {
triggeredBy: transformBuildTrigger(job.triggeredBy), triggeredBy: transformBuildTrigger(job.triggeredBy),
projectArchive: transformProjectArchive(job.projectArchive), projectArchive: transformProjectArchive(job.projectArchive),
projectRootDirectory: nullthrows(job.projectRootDirectory), projectRootDirectory: nullthrows(job.projectRootDirectory),
releaseChannel: job.releaseChannel,
updates: job.updates, updates: job.updates,
secrets: job.secrets ? transformIosSecrets(job.secrets) : undefined, secrets: job.secrets ? transformIosSecrets(job.secrets) : undefined,
builderEnvironment: job.builderEnvironment, builderEnvironment: job.builderEnvironment,
@@ -31,6 +31,9 @@ export function transformJob(job: Ios.Job): IosJobInput {
experimental: job.experimental, experimental: job.experimental,
mode: transformBuildMode(job.mode), mode: transformBuildMode(job.mode),
customBuildConfig: job.customBuildConfig, customBuildConfig: job.customBuildConfig,
loggerLevel: job.loggerLevel
? loggerLevelToGraphQLWorkerLoggerLevel[job.loggerLevel]
: undefined,
}; };
} }
+21 -9
View File
@@ -3,9 +3,8 @@ import {
BuildMode, BuildMode,
BuildTrigger, BuildTrigger,
Ios, Ios,
Job,
Platform, Platform,
sanitizeJob, sanitizeBuildJob,
} from '@expo/eas-build-job'; } from '@expo/eas-build-job';
import { BuildProfile } from '@expo/eas-json'; import { BuildProfile } from '@expo/eas-json';
import nullthrows from 'nullthrows'; import nullthrows from 'nullthrows';
@@ -14,7 +13,7 @@ import slash from 'slash';
import { IosCredentials, TargetCredentials } from '../../credentials/ios/types'; import { IosCredentials, TargetCredentials } from '../../credentials/ios/types';
import { IosJobSecretsInput } from '../../graphql/generated'; import { IosJobSecretsInput } from '../../graphql/generated';
import { getCustomBuildConfigPath } from '../../project/customBuildConfig'; import { getCustomBuildConfigPathForJob } from '../../project/customBuildConfig';
import { getUsername } from '../../project/projectUtils'; import { getUsername } from '../../project/projectUtils';
import { BuildContext } from '../context'; import { BuildContext } from '../context';
@@ -32,7 +31,7 @@ const cacheDefaults = {
export async function prepareJobAsync( export async function prepareJobAsync(
ctx: BuildContext<Platform.IOS>, ctx: BuildContext<Platform.IOS>,
jobData: JobData jobData: JobData
): Promise<Job> { ): Promise<Ios.Job> {
const username = getUsername(ctx.exp, ctx.user); const username = getUsername(ctx.exp, ctx.user);
const buildProfile: BuildProfile<Platform.IOS> = ctx.buildProfile; const buildProfile: BuildProfile<Platform.IOS> = ctx.buildProfile;
const projectRootDirectory = const projectRootDirectory =
@@ -46,9 +45,18 @@ export async function prepareJobAsync(
} }
const maybeCustomBuildConfigPath = buildProfile.config const maybeCustomBuildConfigPath = buildProfile.config
? getCustomBuildConfigPath(buildProfile.config) ? getCustomBuildConfigPathForJob(buildProfile.config)
: undefined; : undefined;
let buildMode;
if (ctx.repack) {
buildMode = BuildMode.REPACK;
} else if (buildProfile.config) {
buildMode = BuildMode.CUSTOM;
} else {
buildMode = BuildMode.BUILD;
}
const job: Ios.Job = { const job: Ios.Job = {
type: ctx.workflow, type: ctx.workflow,
platform: Platform.IOS, platform: Platform.IOS,
@@ -63,7 +71,6 @@ export async function prepareJobAsync(
bundler: buildProfile.bundler, bundler: buildProfile.bundler,
cocoapods: buildProfile.cocoapods, cocoapods: buildProfile.cocoapods,
fastlane: buildProfile.fastlane, fastlane: buildProfile.fastlane,
expoCli: buildProfile.expoCli,
env: buildProfile.env, env: buildProfile.env,
}, },
cache: { cache: {
@@ -74,7 +81,6 @@ export async function prepareJobAsync(
secrets: { secrets: {
buildCredentials, buildCredentials,
}, },
releaseChannel: buildProfile.releaseChannel,
updates: { channel: buildProfile.channel }, updates: { channel: buildProfile.channel },
developmentClient: buildProfile.developmentClient, developmentClient: buildProfile.developmentClient,
simulator: buildProfile.simulator, simulator: buildProfile.simulator,
@@ -91,15 +97,21 @@ export async function prepareJobAsync(
experimental: { experimental: {
prebuildCommand: buildProfile.prebuildCommand, prebuildCommand: buildProfile.prebuildCommand,
}, },
mode: buildProfile.config ? BuildMode.CUSTOM : BuildMode.BUILD, mode: buildMode,
triggeredBy: BuildTrigger.EAS_CLI, triggeredBy: BuildTrigger.EAS_CLI,
...(maybeCustomBuildConfigPath && { ...(maybeCustomBuildConfigPath && {
customBuildConfig: { customBuildConfig: {
path: maybeCustomBuildConfigPath, path: maybeCustomBuildConfigPath,
}, },
}), }),
...(ctx.repack && {
customBuildConfig: {
path: '__eas/repack.yml',
},
}),
loggerLevel: ctx.loggerLevel,
}; };
return sanitizeJob(job); return sanitizeBuildJob(job) as Ios.Job;
} }
export function prepareCredentialsToResign(credentials: IosCredentials): IosJobSecretsInput { export function prepareCredentialsToResign(credentials: IosCredentials): IosJobSecretsInput {
@@ -1,39 +1,35 @@
import { ExpoConfig } from '@expo/config'; import { ExpoConfig } from '@expo/config';
import { Platform, Workflow } from '@expo/eas-build-job'; import { Env, Platform, Workflow } from '@expo/eas-build-job';
import { IosVersionAutoIncrement } from '@expo/eas-json'; import { IosVersionAutoIncrement } from '@expo/eas-json';
import { BumpStrategy, bumpVersionAsync, bumpVersionInAppJsonAsync } from './version'; import { BumpStrategy, bumpVersionAsync, bumpVersionInAppJsonAsync } from './version';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
import { Target } from '../../credentials/ios/types'; import { Target } from '../../credentials/ios/types';
import { isExpoUpdatesInstalled } from '../../project/projectUtils'; import { isExpoUpdatesInstalled } from '../../project/projectUtils';
import { resolveWorkflowAsync } from '../../project/workflow'; import { resolveWorkflowAsync } from '../../project/workflow';
import { syncUpdatesConfigurationAsync } from '../../update/ios/UpdatesModule'; import { syncUpdatesConfigurationAsync } from '../../update/ios/UpdatesModule';
import { Client } from '../../vcs/vcs'; import { Client } from '../../vcs/vcs';
export async function syncProjectConfigurationAsync( export async function syncProjectConfigurationAsync({
graphqlClient: ExpoGraphqlClient,
{
projectDir, projectDir,
exp, exp,
targets, targets,
localAutoIncrement, localAutoIncrement,
projectId,
vcsClient, vcsClient,
env,
}: { }: {
projectDir: string; projectDir: string;
exp: ExpoConfig; exp: ExpoConfig;
targets: Target[]; targets: Target[];
localAutoIncrement?: IosVersionAutoIncrement; localAutoIncrement?: IosVersionAutoIncrement;
projectId: string;
vcsClient: Client; vcsClient: Client;
} env: Env | undefined;
): Promise<void> { }): Promise<void> {
const workflow = await resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient); const workflow = await resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient);
const versionBumpStrategy = resolveVersionBumpStrategy(localAutoIncrement ?? false); const versionBumpStrategy = resolveVersionBumpStrategy(localAutoIncrement ?? false);
if (workflow === Workflow.GENERIC) { if (workflow === Workflow.GENERIC) {
if (isExpoUpdatesInstalled(projectDir)) { if (isExpoUpdatesInstalled(projectDir)) {
await syncUpdatesConfigurationAsync(graphqlClient, vcsClient, projectDir, exp, projectId); await syncUpdatesConfigurationAsync({ vcsClient, projectDir, exp, workflow, env });
} }
await bumpVersionAsync({ projectDir, exp, bumpStrategy: versionBumpStrategy, targets }); await bumpVersionAsync({ projectDir, exp, bumpStrategy: versionBumpStrategy, targets });
} else { } else {
+6 -2
View File
@@ -342,7 +342,9 @@ export async function resolveRemoteBuildNumberAsync(
applicationIdentifier: applicationTarget.bundleIdentifier, applicationIdentifier: applicationTarget.bundleIdentifier,
storeVersion: localShortVersion ?? '1.0.0', storeVersion: localShortVersion ?? '1.0.0',
buildVersion: currentBuildVersion, buildVersion: currentBuildVersion,
runtimeVersion: Updates.getRuntimeVersionNullable(exp, Platform.IOS) ?? undefined, runtimeVersion:
(await Updates.getRuntimeVersionNullableAsync(projectDir, exp, Platform.IOS)) ??
undefined,
}); });
spinner.succeed(`Initialized buildNumber with ${chalk.bold(currentBuildVersion)}.`); spinner.succeed(`Initialized buildNumber with ${chalk.bold(currentBuildVersion)}.`);
} catch (err) { } catch (err) {
@@ -364,7 +366,9 @@ export async function resolveRemoteBuildNumberAsync(
applicationIdentifier: applicationTarget.bundleIdentifier, applicationIdentifier: applicationTarget.bundleIdentifier,
storeVersion: localShortVersion ?? '1.0.0', storeVersion: localShortVersion ?? '1.0.0',
buildVersion: nextBuildVersion, buildVersion: nextBuildVersion,
runtimeVersion: Updates.getRuntimeVersionNullable(exp, Platform.IOS) ?? undefined, runtimeVersion:
(await Updates.getRuntimeVersionNullableAsync(projectDir, exp, Platform.IOS)) ??
undefined,
}); });
spinner.succeed( spinner.succeed(
`Incremented buildNumber from ${chalk.bold(currentBuildVersion)} to ${chalk.bold( `Incremented buildNumber from ${chalk.bold(currentBuildVersion)} to ${chalk.bold(
+1 -1
View File
@@ -6,7 +6,7 @@ import semver from 'semver';
import { ora } from '../ora'; import { ora } from '../ora';
const PLUGIN_PACKAGE_NAME = 'eas-cli-local-build-plugin'; const PLUGIN_PACKAGE_NAME = 'eas-cli-local-build-plugin';
const PLUGIN_PACKAGE_VERSION = '1.0.56'; const PLUGIN_PACKAGE_VERSION = '1.0.118';
export enum LocalBuildMode { export enum LocalBuildMode {
/** /**
+20 -37
View File
@@ -1,4 +1,3 @@
import { Updates } from '@expo/config-plugins';
import { Metadata, Platform, sanitizeMetadata } from '@expo/eas-build-job'; import { Metadata, Platform, sanitizeMetadata } from '@expo/eas-build-job';
import { IosEnterpriseProvisioning } from '@expo/eas-json'; import { IosEnterpriseProvisioning } from '@expo/eas-json';
import fs from 'fs-extra'; import fs from 'fs-extra';
@@ -8,26 +7,19 @@ import { maybeResolveVersionsAsync as maybeResolveAndroidVersionsAsync } from '.
import { BuildContext } from './context'; import { BuildContext } from './context';
import { maybeResolveVersionsAsync as maybeResolveIosVersionsAsync } from './ios/version'; import { maybeResolveVersionsAsync as maybeResolveIosVersionsAsync } from './ios/version';
import { LocalBuildMode } from './local'; import { LocalBuildMode } from './local';
import { BuildDistributionType } from './types';
import Log from '../log'; import Log from '../log';
import { getUsername, isExpoUpdatesInstalled } from '../project/projectUtils'; import { getUsername, isExpoUpdatesInstalled } from '../project/projectUtils';
import { import { resolveRuntimeVersionAsync } from '../project/resolveRuntimeVersionAsync';
readChannelSafelyAsync as readAndroidChannelSafelyAsync, import { readChannelSafelyAsync as readAndroidChannelSafelyAsync } from '../update/android/UpdatesModule';
readReleaseChannelSafelyAsync as readAndroidReleaseChannelSafelyAsync, import { readChannelSafelyAsync as readIosChannelSafelyAsync } from '../update/ios/UpdatesModule';
} from '../update/android/UpdatesModule';
import {
readChannelSafelyAsync as readIosChannelSafelyAsync,
readReleaseChannelSafelyAsync as readIosReleaseChannelSafelyAsync,
} from '../update/ios/UpdatesModule';
import { easCliVersion } from '../utils/easCli'; import { easCliVersion } from '../utils/easCli';
export async function collectMetadataAsync<T extends Platform>( export async function collectMetadataAsync<T extends Platform>(
ctx: BuildContext<T> ctx: BuildContext<T>
): Promise<Metadata> { ): Promise<Metadata> {
const channelOrReleaseChannel = await resolveChannelOrReleaseChannelAsync(ctx); const channelObject = await resolveChannelAsync(ctx);
const distribution = const distribution = ctx.buildProfile.distribution ?? BuildDistributionType.STORE;
('simulator' in ctx.buildProfile && ctx.buildProfile.simulator
? 'simulator'
: ctx.buildProfile.distribution) ?? 'store';
const metadata: Metadata = { const metadata: Metadata = {
trackingContext: ctx.analyticsEventProperties, trackingContext: ctx.analyticsEventProperties,
...(await maybeResolveVersionsAsync(ctx)), ...(await maybeResolveVersionsAsync(ctx)),
@@ -35,9 +27,17 @@ export async function collectMetadataAsync<T extends Platform>(
workflow: ctx.workflow, workflow: ctx.workflow,
credentialsSource: ctx.buildProfile.credentialsSource, credentialsSource: ctx.buildProfile.credentialsSource,
sdkVersion: ctx.exp.sdkVersion, sdkVersion: ctx.exp.sdkVersion,
runtimeVersion: Updates.getRuntimeVersionNullable(ctx.exp, ctx.platform) ?? undefined, runtimeVersion:
(await resolveRuntimeVersionAsync({
exp: ctx.exp,
platform: ctx.platform,
workflow: ctx.workflow,
projectDir: ctx.projectDir,
env: ctx.buildProfile.env,
cwd: ctx.projectDir,
})) ?? undefined,
reactNativeVersion: await getReactNativeVersionAsync(ctx.projectDir), reactNativeVersion: await getReactNativeVersionAsync(ctx.projectDir),
...channelOrReleaseChannel, ...channelObject,
distribution, distribution,
appName: ctx.exp.name, appName: ctx.exp.name,
appIdentifier: resolveAppIdentifier(ctx), appIdentifier: resolveAppIdentifier(ctx),
@@ -64,6 +64,7 @@ export async function collectMetadataAsync<T extends Platform>(
requiredPackageManager: ctx.requiredPackageManager ?? undefined, requiredPackageManager: ctx.requiredPackageManager ?? undefined,
selectedImage: ctx.buildProfile.image, selectedImage: ctx.buildProfile.image,
customNodeVersion: ctx.buildProfile.node, customNodeVersion: ctx.buildProfile.node,
simulator: 'simulator' in ctx.buildProfile && ctx.buildProfile.simulator,
}; };
return sanitizeMetadata(metadata); return sanitizeMetadata(metadata);
} }
@@ -114,39 +115,21 @@ function resolveAppIdentifier<T extends Platform>(ctx: BuildContext<T>): string
} }
} }
async function resolveChannelOrReleaseChannelAsync<T extends Platform>( async function resolveChannelAsync<T extends Platform>(
ctx: BuildContext<T> ctx: BuildContext<T>
): Promise<{ channel: string } | { releaseChannel: string } | null> { ): Promise<{ channel: string } | null> {
if (!isExpoUpdatesInstalled(ctx.projectDir)) { if (!isExpoUpdatesInstalled(ctx.projectDir)) {
return null; return null;
} }
if (ctx.buildProfile.channel) { if (ctx.buildProfile.channel) {
return { channel: ctx.buildProfile.channel }; return { channel: ctx.buildProfile.channel };
} }
if (ctx.buildProfile.releaseChannel) {
return { releaseChannel: ctx.buildProfile.releaseChannel };
}
const channel = await getNativeChannelAsync(ctx); const channel = await getNativeChannelAsync(ctx);
if (channel) { if (channel) {
return { channel }; return { channel };
} }
const releaseChannel = await getNativeReleaseChannelAsync(ctx);
return { releaseChannel };
}
async function getNativeReleaseChannelAsync<T extends Platform>( return null;
ctx: BuildContext<T>
): Promise<string> {
switch (ctx.platform) {
case Platform.ANDROID: {
return (await readAndroidReleaseChannelSafelyAsync(ctx.projectDir)) ?? 'default';
}
case Platform.IOS: {
return (await readIosReleaseChannelSafelyAsync(ctx.projectDir)) ?? 'default';
}
default:
return 'default';
}
} }
async function getNativeChannelAsync<T extends Platform>( async function getNativeChannelAsync<T extends Platform>(
+58 -17
View File
@@ -1,5 +1,5 @@
import { ExpoConfig } from '@expo/config-types'; import { ExpoConfig } from '@expo/config-types';
import { Platform, Workflow } from '@expo/eas-build-job'; import { Env, Platform, Workflow } from '@expo/eas-build-job';
import { import {
AppVersionSource, AppVersionSource,
BuildProfile, BuildProfile,
@@ -9,6 +9,7 @@ import {
ResourceClass, ResourceClass,
SubmitProfile, SubmitProfile,
} from '@expo/eas-json'; } from '@expo/eas-json';
import { LoggerLevel } from '@expo/logger';
import assert from 'assert'; import assert from 'assert';
import chalk from 'chalk'; import chalk from 'chalk';
import nullthrows from 'nullthrows'; import nullthrows from 'nullthrows';
@@ -19,7 +20,7 @@ import { ensureProjectConfiguredAsync } from './configure';
import { BuildContext } from './context'; import { BuildContext } from './context';
import { createBuildContextAsync } from './createContext'; import { createBuildContextAsync } from './createContext';
import { prepareIosBuildAsync } from './ios/build'; import { prepareIosBuildAsync } from './ios/build';
import { LocalBuildOptions } from './local'; import { LocalBuildMode, LocalBuildOptions } from './local';
import { ensureExpoDevClientInstalledForDevClientBuildsAsync } from './utils/devClient'; import { ensureExpoDevClientInstalledForDevClientBuildsAsync } from './utils/devClient';
import { printBuildResults, printLogsUrls } from './utils/printBuildInfo'; import { printBuildResults, printLogsUrls } from './utils/printBuildInfo';
import { ensureRepoIsCleanAsync } from './utils/repository'; import { ensureRepoIsCleanAsync } from './utils/repository';
@@ -70,7 +71,6 @@ import {
} from '../submit/submit'; } from '../submit/submit';
import { printSubmissionDetailsUrls } from '../submit/utils/urls'; import { printSubmissionDetailsUrls } from '../submit/utils/urls';
import { ensureEASUpdateIsConfiguredAsync } from '../update/configure'; import { ensureEASUpdateIsConfiguredAsync } from '../update/configure';
import { validateBuildProfileConfigMatchesProjectConfigAsync } from '../update/utils';
import { Actor } from '../user/User'; import { Actor } from '../user/User';
import { downloadAndMaybeExtractAppAsync } from '../utils/download'; import { downloadAndMaybeExtractAppAsync } from '../utils/download';
import { truthy } from '../utils/expodash/filter'; import { truthy } from '../utils/expodash/filter';
@@ -93,6 +93,9 @@ export interface BuildFlags {
localBuildOptions: LocalBuildOptions; localBuildOptions: LocalBuildOptions;
resourceClass?: ResourceClass; resourceClass?: ResourceClass;
message?: string; message?: string;
buildLoggerLevel?: LoggerLevel;
freezeCredentials: boolean;
repack: boolean;
} }
export async function runBuildAndSubmitAsync( export async function runBuildAndSubmitAsync(
@@ -103,7 +106,9 @@ export async function runBuildAndSubmitAsync(
flags: BuildFlags, flags: BuildFlags,
actor: Actor, actor: Actor,
getDynamicPrivateProjectConfigAsync: DynamicConfigContextFn getDynamicPrivateProjectConfigAsync: DynamicConfigContextFn
): Promise<void> { ): Promise<{
buildIds: string[];
}> {
await vcsClient.ensureRepoExistsAsync(); await vcsClient.ensureRepoExistsAsync();
await ensureRepoIsCleanAsync(vcsClient, flags.nonInteractive); await ensureRepoIsCleanAsync(vcsClient, flags.nonInteractive);
@@ -132,6 +137,14 @@ export async function runBuildAndSubmitAsync(
}. ${learnMore('https://docs.expo.dev/build-reference/variables/')}` }. ${learnMore('https://docs.expo.dev/build-reference/variables/')}`
); );
for (const buildProfile of buildProfiles) {
if (buildProfile.profile.image && ['default', 'stable'].includes(buildProfile.profile.image)) {
Log.warn(
`The "image" field in the build profile "${buildProfile.profileName}" is set to "${buildProfile.profile.image}". This tag is deprecated and will be removed in the future. Use other images or tags listed here: https://docs.expo.dev/build-reference/infrastructure/`
);
}
}
await ensureExpoDevClientInstalledForDevClientBuildsAsync({ await ensureExpoDevClientInstalledForDevClientBuildsAsync({
projectDir, projectDir,
nonInteractive: flags.nonInteractive, nonInteractive: flags.nonInteractive,
@@ -180,13 +193,25 @@ export async function runBuildAndSubmitAsync(
buildCtxByPlatform[platform] = buildCtx; buildCtxByPlatform[platform] = buildCtx;
} }
if (flags.localBuildOptions.localBuildMode) { if (flags.localBuildOptions.localBuildMode === LocalBuildMode.LOCAL_BUILD_PLUGIN) {
return; return {
buildIds: startedBuilds.map(({ build }) => build.id),
};
} }
if (flags.localBuildOptions.localBuildMode === LocalBuildMode.INTERNAL) {
const startedBuild = await BuildQuery.byIdAsync(
graphqlClient,
nullthrows(process.env.EAS_BUILD_ID, 'EAS_BUILD_ID is not defined')
);
startedBuilds.push({ build: startedBuild, buildProfile: buildProfiles[0] });
}
if (!flags.localBuildOptions.localBuildMode) {
Log.newLine(); Log.newLine();
printLogsUrls(startedBuilds.map(startedBuild => startedBuild.build)); printLogsUrls(startedBuilds.map(startedBuild => startedBuild.build));
Log.newLine(); Log.newLine();
}
const submissions: SubmissionFragment[] = []; const submissions: SubmissionFragment[] = [];
if (flags.autoSubmit) { if (flags.autoSubmit) {
@@ -211,6 +236,7 @@ export async function runBuildAndSubmitAsync(
buildProfile: startedBuild.buildProfile.profile, buildProfile: startedBuild.buildProfile.profile,
submitProfile, submitProfile,
nonInteractive: flags.nonInteractive, nonInteractive: flags.nonInteractive,
selectedSubmitProfileName: flags.submitProfile,
}); });
startedBuild.build = await BuildQuery.withSubmissionsByIdAsync( startedBuild.build = await BuildQuery.withSubmissionsByIdAsync(
graphqlClient, graphqlClient,
@@ -219,16 +245,26 @@ export async function runBuildAndSubmitAsync(
submissions.push(submission); submissions.push(submission);
} }
if (!flags.localBuildOptions.localBuildMode) {
Log.newLine(); Log.newLine();
printSubmissionDetailsUrls(submissions); printSubmissionDetailsUrls(submissions);
Log.newLine(); Log.newLine();
} }
}
if (flags.localBuildOptions.localBuildMode) {
return {
buildIds: startedBuilds.map(({ build }) => build.id),
};
}
if (!flags.wait) { if (!flags.wait) {
if (flags.json) { if (flags.json) {
printJsonOnlyOutput(startedBuilds.map(buildInfo => buildInfo.build)); printJsonOnlyOutput(startedBuilds.map(buildInfo => buildInfo.build));
} }
return; return {
buildIds: startedBuilds.map(({ build }) => build.id),
};
} }
const { accountName } = Object.values(buildCtxByPlatform)[0]; const { accountName } = Object.values(buildCtxByPlatform)[0];
@@ -269,6 +305,9 @@ export async function runBuildAndSubmitAsync(
} }
exitWithNonZeroCodeIfSomeSubmissionsDidntFinish(completedSubmissions); exitWithNonZeroCodeIfSomeSubmissionsDidntFinish(completedSubmissions);
} }
return {
buildIds: startedBuilds.map(({ build }) => build.id),
};
} }
async function prepareAndStartBuildAsync({ async function prepareAndStartBuildAsync({
@@ -314,6 +353,9 @@ async function prepareAndStartBuildAsync({
vcsClient, vcsClient,
getDynamicPrivateProjectConfigAsync, getDynamicPrivateProjectConfigAsync,
customBuildConfigMetadata, customBuildConfigMetadata,
buildLoggerLevel: flags.buildLoggerLevel,
freezeCredentials: flags.freezeCredentials,
repack: flags.repack,
}); });
if (moreBuilds) { if (moreBuilds) {
@@ -326,15 +368,8 @@ async function prepareAndStartBuildAsync({
); );
} }
await validateBuildProfileConfigMatchesProjectConfigAsync(
buildCtx.exp,
buildProfile,
buildCtx.projectId,
flags.nonInteractive
);
if (buildProfile.profile.channel) { if (buildProfile.profile.channel) {
await validateExpoUpdatesInstalledAsProjectDependencyAsync({ await validateExpoUpdatesInstalledAsProjectDependencyAsync({
graphqlClient,
exp: buildCtx.exp, exp: buildCtx.exp,
projectId: buildCtx.projectId, projectId: buildCtx.projectId,
projectDir, projectDir,
@@ -342,6 +377,7 @@ async function prepareAndStartBuildAsync({
sdkVersion: buildCtx.exp.sdkVersion, sdkVersion: buildCtx.exp.sdkVersion,
nonInteractive: flags.nonInteractive, nonInteractive: flags.nonInteractive,
buildProfile, buildProfile,
env: buildProfile.profile.env,
}); });
if (isUsingEASUpdate(buildCtx.exp, buildCtx.projectId)) { if (isUsingEASUpdate(buildCtx.exp, buildCtx.projectId)) {
const doesChannelExist = await doesChannelExistAsync(graphqlClient, { const doesChannelExist = await doesChannelExistAsync(graphqlClient, {
@@ -396,6 +432,7 @@ async function prepareAndStartSubmissionAsync({
projectDir, projectDir,
buildProfile, buildProfile,
submitProfile, submitProfile,
selectedSubmitProfileName,
nonInteractive, nonInteractive,
}: { }: {
build: BuildFragment; build: BuildFragment;
@@ -404,6 +441,7 @@ async function prepareAndStartSubmissionAsync({
projectDir: string; projectDir: string;
buildProfile: BuildProfile; buildProfile: BuildProfile;
submitProfile: SubmitProfile; submitProfile: SubmitProfile;
selectedSubmitProfileName?: string;
nonInteractive: boolean; nonInteractive: boolean;
}): Promise<SubmissionFragment> { }): Promise<SubmissionFragment> {
const platform = toPlatform(build.platform); const platform = toPlatform(build.platform);
@@ -422,6 +460,8 @@ async function prepareAndStartSubmissionAsync({
projectId: buildCtx.projectId, projectId: buildCtx.projectId,
exp: buildCtx.exp, exp: buildCtx.exp,
vcsClient: buildCtx.vcsClient, vcsClient: buildCtx.vcsClient,
isVerboseFastlaneEnabled: false,
specifiedProfile: selectedSubmitProfileName,
}); });
if (moreBuilds) { if (moreBuilds) {
@@ -479,15 +519,14 @@ async function maybeDownloadAndRunSimulatorBuildsAsync(
async function validateExpoUpdatesInstalledAsProjectDependencyAsync({ async function validateExpoUpdatesInstalledAsProjectDependencyAsync({
exp, exp,
graphqlClient,
projectId, projectId,
projectDir, projectDir,
vcsClient, vcsClient,
buildProfile, buildProfile,
nonInteractive, nonInteractive,
sdkVersion, sdkVersion,
env,
}: { }: {
graphqlClient: ExpoGraphqlClient;
exp: ExpoConfig; exp: ExpoConfig;
projectId: string; projectId: string;
projectDir: string; projectDir: string;
@@ -495,6 +534,7 @@ async function validateExpoUpdatesInstalledAsProjectDependencyAsync({
buildProfile: ProfileData<'build'>; buildProfile: ProfileData<'build'>;
nonInteractive: boolean; nonInteractive: boolean;
sdkVersion?: string; sdkVersion?: string;
env: Env | undefined;
}): Promise<void> { }): Promise<void> {
if (isExpoUpdatesInstalledOrAvailable(projectDir, sdkVersion)) { if (isExpoUpdatesInstalledOrAvailable(projectDir, sdkVersion)) {
return; return;
@@ -516,12 +556,13 @@ async function validateExpoUpdatesInstalledAsProjectDependencyAsync({
message: `Would you like to install the "expo-updates" package and configure EAS Update now?`, message: `Would you like to install the "expo-updates" package and configure EAS Update now?`,
}); });
if (installExpoUpdates) { if (installExpoUpdates) {
await ensureEASUpdateIsConfiguredAsync(graphqlClient, { await ensureEASUpdateIsConfiguredAsync({
exp, exp,
projectId, projectId,
projectDir, projectDir,
platform: RequestedPlatform.All, platform: RequestedPlatform.All,
vcsClient, vcsClient,
env,
}); });
Log.withTick('Installed expo-updates and configured EAS Update.'); Log.withTick('Installed expo-updates and configured EAS Update.');
throw new Error('Command must be re-run to pick up new updates configuration.'); throw new Error('Command must be re-run to pick up new updates configuration.');
+1
View File
@@ -11,5 +11,6 @@ export enum BuildStatus {
export enum BuildDistributionType { export enum BuildDistributionType {
STORE = 'store', STORE = 'store',
INTERNAL = 'internal', INTERNAL = 'internal',
/** @deprecated Use simulator flag instead */
SIMULATOR = 'simulator', SIMULATOR = 'simulator',
} }
@@ -39,6 +39,10 @@ export function formatGraphQLBuild(build: BuildFragment): string {
} }
}, },
}, },
{
label: 'Profile',
value: build.buildProfile,
},
{ {
label: 'Message', label: 'Message',
value: build.message, value: build.message,
@@ -51,10 +55,6 @@ export function formatGraphQLBuild(build: BuildFragment): string {
label: 'Enterprise Provisioning', label: 'Enterprise Provisioning',
value: build.iosEnterpriseProvisioning?.toLowerCase(), value: build.iosEnterpriseProvisioning?.toLowerCase(),
}, },
{
label: 'Release Channel',
value: build.releaseChannel,
},
{ {
label: 'Channel', label: 'Channel',
value: build.channel, value: build.channel,
+38 -4
View File
@@ -12,7 +12,10 @@ import { getTmpDirectory } from '../../utils/paths';
import { endTimer, formatMilliseconds, startTimer } from '../../utils/timer'; import { endTimer, formatMilliseconds, startTimer } from '../../utils/timer';
import { Client } from '../../vcs/vcs'; import { Client } from '../../vcs/vcs';
export async function maybeBailOnRepoStatusAsync(vcsClient: Client): Promise<void> { export async function maybeBailOnRepoStatusAsync(
vcsClient: Client,
nonInteractive: boolean
): Promise<void> {
if (!(await vcsClient.isCommitRequiredAsync())) { if (!(await vcsClient.isCommitRequiredAsync())) {
return; return;
} }
@@ -28,6 +31,11 @@ export async function maybeBailOnRepoStatusAsync(vcsClient: Client): Promise<voi
}); });
if (!answer) { if (!answer) {
if (nonInteractive) {
Log.log('The following files need to be committed:');
await vcsClient.showChangedFilesAsync();
}
throw new Error('Commit all changes. Aborting...'); throw new Error('Commit all changes. Aborting...');
} }
} }
@@ -47,6 +55,9 @@ export async function ensureRepoIsCleanAsync(
)}.` )}.`
); );
if (nonInteractive) { if (nonInteractive) {
Log.log('The following files need to be committed:');
await vcsClient.showChangedFilesAsync();
throw new Error('Commit all changes. Aborting...'); throw new Error('Commit all changes. Aborting...');
} }
const answer = await confirmAsync({ const answer = await confirmAsync({
@@ -83,9 +94,32 @@ export async function commitPromptAsync(
}); });
} }
export async function makeProjectTarballAsync( export type LocalFile = {
vcsClient: Client path: string;
): Promise<{ path: string; size: number }> { size: number;
};
export async function makeProjectMetadataFileAsync(archivePath: string): Promise<LocalFile> {
const metadataLocation = path.join(getTmpDirectory(), `${uuidv4()}-eas-build-metadata.json`);
const archiveContent: string[] = [];
await tar.list({
file: archivePath,
onentry: (entry: tar.ReadEntry) => {
if (entry.type === 'File' && !entry.path.includes('.git/')) {
archiveContent.push(entry.path);
}
},
});
await fs.writeJSON(metadataLocation, {
archiveContent,
});
return { path: metadataLocation, size: await fs.stat(metadataLocation).then(stat => stat.size) };
}
export async function makeProjectTarballAsync(vcsClient: Client): Promise<LocalFile> {
const spinner = ora('Compressing project files'); const spinner = ora('Compressing project files');
await fs.mkdirp(getTmpDirectory()); await fs.mkdirp(getTmpDirectory());
+28
View File
@@ -50,3 +50,31 @@ export function getUpdateGroupUrl(
getExpoWebsiteBaseUrl() getExpoWebsiteBaseUrl()
).toString(); ).toString();
} }
export function getUpdatePreviewUrl({
message,
updateRuntimeVersion,
createdAt,
slug,
projectId,
group,
}: {
message?: string;
updateRuntimeVersion: string;
createdAt: string;
slug: string;
projectId: string;
group: string;
}): string {
const previewUrl = new URL(`/preview/update`, getExpoWebsiteBaseUrl());
if (message) {
//previewUrl.searchParams.append('message', message);
}
previewUrl.searchParams.append('updateRuntimeVersion', updateRuntimeVersion);
//previewUrl.searchParams.append('createdAt', createdAt);
previewUrl.searchParams.append('slug', slug);
previewUrl.searchParams.append('projectId', projectId);
previewUrl.searchParams.append('group', group);
return previewUrl.toString();
}
@@ -1,5 +1,6 @@
import { Command } from '@oclif/core'; import { Command } from '@oclif/core';
import { CombinedError } from '@urql/core'; import { CombinedError } from '@urql/core';
import chalk from 'chalk';
import { GraphQLError } from 'graphql/error'; import { GraphQLError } from 'graphql/error';
import nullthrows from 'nullthrows'; import nullthrows from 'nullthrows';
@@ -24,6 +25,7 @@ import {
} from '../analytics/AnalyticsManager'; } from '../analytics/AnalyticsManager';
import Log from '../log'; import Log from '../log';
import SessionManager from '../user/SessionManager'; import SessionManager from '../user/SessionManager';
import { Client } from '../vcs/vcs';
export type ContextInput< export type ContextInput<
T extends { T extends {
@@ -139,7 +141,7 @@ export default abstract class EasCommand extends Command {
} = object, } = object,
>( >(
commandClass: { contextDefinition: ContextInput<C> }, commandClass: { contextDefinition: ContextInput<C> },
{ nonInteractive }: { nonInteractive: boolean } { nonInteractive, vcsClientOverride }: { nonInteractive: boolean; vcsClientOverride?: Client }
): Promise<ContextOutput<C>> { ): Promise<ContextOutput<C>> {
const contextDefinition = commandClass.contextDefinition; const contextDefinition = commandClass.contextDefinition;
@@ -152,6 +154,7 @@ export default abstract class EasCommand extends Command {
nonInteractive, nonInteractive,
sessionManager: this.sessionManager, sessionManager: this.sessionManager,
analytics: this.analytics, analytics: this.analytics,
vcsClientOverride,
}), }),
]); ]);
} }
@@ -198,7 +201,7 @@ export default abstract class EasCommand extends Command {
if (err instanceof EasCommandError) { if (err instanceof EasCommandError) {
Log.error(err.message); Log.error(err.message);
} else if (err instanceof CombinedError && err?.graphQLErrors) { } else if (err instanceof CombinedError && err?.graphQLErrors) {
const cleanMessage = err?.graphQLErrors const cleanGQLErrorsMessage = err?.graphQLErrors
.map((graphQLError: GraphQLError) => { .map((graphQLError: GraphQLError) => {
const messageLine = graphQLError.message.replace('[GraphQL] ', ''); const messageLine = graphQLError.message.replace('[GraphQL] ', '');
const requestIdLine = graphQLError.extensions?.requestId const requestIdLine = graphQLError.extensions?.requestId
@@ -208,12 +211,21 @@ export default abstract class EasCommand extends Command {
const defaultMsg = `${messageLine}${requestIdLine}`; const defaultMsg = `${messageLine}${requestIdLine}`;
if (graphQLError.extensions?.errorCode === 'UNAUTHORIZED_ERROR') { if (graphQLError.extensions?.errorCode === 'UNAUTHORIZED_ERROR') {
return `You don't have the required permissions to perform this operation.\n\n${defaultMsg}`; return `${chalk.bold(
`You don't have the required permissions to perform this operation.`
)}\n\nThis can sometimes happen if you are logged in as incorrect user.\nRun ${chalk.bold(
'eas whoami'
)} to check the username you are logged in as.\nRun ${chalk.bold(
'eas login'
)} to change the account.\n\nOriginal error message: ${defaultMsg}`;
} }
return defaultMsg; return defaultMsg;
}) })
.join('\n'); .join('\n');
const cleanMessage = err.networkError
? `${cleanGQLErrorsMessage}\n${err.networkError.message}`
: cleanGQLErrorsMessage;
Log.error(cleanMessage); Log.error(cleanMessage);
baseMessage = BASE_GRAPHQL_ERROR_MESSAGE; baseMessage = BASE_GRAPHQL_ERROR_MESSAGE;
} else { } else {
@@ -1,10 +1,12 @@
import { Analytics } from '../../analytics/AnalyticsManager'; import { Analytics } from '../../analytics/AnalyticsManager';
import SessionManager from '../../user/SessionManager'; import SessionManager from '../../user/SessionManager';
import { Client } from '../../vcs/vcs';
export interface ContextOptions { export interface ContextOptions {
sessionManager: SessionManager; sessionManager: SessionManager;
analytics: Analytics; analytics: Analytics;
nonInteractive: boolean; nonInteractive: boolean;
vcsClientOverride?: Client;
} }
export default abstract class ContextField<T> { export default abstract class ContextField<T> {
@@ -1,9 +1,18 @@
import { EasJsonAccessor, EasJsonUtils } from '@expo/eas-json';
import ContextField from './ContextField'; import ContextField from './ContextField';
import { getVcsClient } from '../../vcs'; import { findProjectDirAndVerifyProjectSetupAsync } from './contextUtils/findProjectDirAndVerifyProjectSetupAsync';
import { resolveVcsClient } from '../../vcs';
import { Client } from '../../vcs/vcs'; import { Client } from '../../vcs/vcs';
export default class VcsClientContextField extends ContextField<Client> { export default class VcsClientContextField extends ContextField<Client> {
async getValueAsync(): Promise<Client> { async getValueAsync({ vcsClientOverride }: { vcsClientOverride?: Client }): Promise<Client> {
return getVcsClient(); if (vcsClientOverride) {
return vcsClientOverride;
}
const projectDir = await findProjectDirAndVerifyProjectSetupAsync();
const easJsonAccessor = EasJsonAccessor.fromProjectPath(projectDir);
const config = await EasJsonUtils.getCliConfigAsync(easJsonAccessor);
return resolveVcsClient(config?.requireCommit);
} }
} }
@@ -55,6 +55,7 @@ describe(getProjectIdAsync, () => {
], ],
isExpoAdmin: false, isExpoAdmin: false,
featureGates: {}, featureGates: {},
preferences: {},
}, },
authenticationInfo: { accessToken: 'fake', sessionSecret: null }, authenticationInfo: { accessToken: 'fake', sessionSecret: null },
}); });
@@ -79,6 +80,7 @@ describe(getProjectIdAsync, () => {
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({ jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
id: '1234', id: '1234',
fullName: '@notnotbrent/test', fullName: '@notnotbrent/test',
name: 'test',
slug: 'test', slug: 'test',
ownerAccount: { name: 'notnotbrent' } as any, ownerAccount: { name: 'notnotbrent' } as any,
}); });
@@ -99,6 +101,7 @@ describe(getProjectIdAsync, () => {
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({ jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
id: '1234', id: '1234',
fullName: '@notnotbrent/test', fullName: '@notnotbrent/test',
name: 'test',
slug: 'test', slug: 'test',
ownerAccount: { name: 'notnotbrent' } as any, ownerAccount: { name: 'notnotbrent' } as any,
}); });
@@ -123,6 +126,7 @@ describe(getProjectIdAsync, () => {
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({ jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
id: '1234', id: '1234',
fullName: '@totallybrent/test', fullName: '@totallybrent/test',
name: 'test',
slug: 'test', slug: 'test',
ownerAccount: { name: 'totallybrent' } as any, ownerAccount: { name: 'totallybrent' } as any,
}); });
@@ -171,6 +175,7 @@ describe(getProjectIdAsync, () => {
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({ jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
id: '1234', id: '1234',
fullName: '@totallybrent/test', fullName: '@totallybrent/test',
name: 'test',
slug: 'test', slug: 'test',
ownerAccount: { name: 'totallybrent' } as any, ownerAccount: { name: 'totallybrent' } as any,
}); });
@@ -195,6 +200,7 @@ describe(getProjectIdAsync, () => {
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({ jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
id: '1234', id: '1234',
fullName: '@notnotbrent/test', fullName: '@notnotbrent/test',
name: 'test',
slug: 'test', slug: 'test',
ownerAccount: { name: 'notnotbrent' } as any, ownerAccount: { name: 'notnotbrent' } as any,
}); });
@@ -264,6 +270,7 @@ describe(getProjectIdAsync, () => {
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({ jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
id: '1234', id: '1234',
fullName: '@notnotbrent/test', fullName: '@notnotbrent/test',
name: 'test',
slug: 'test', slug: 'test',
ownerAccount: { name: 'notnotbrent' } as any, ownerAccount: { name: 'notnotbrent' } as any,
}); });
@@ -8,20 +8,20 @@ import semver from 'semver';
import { learnMore } from '../../../log'; import { learnMore } from '../../../log';
import { easCliVersion } from '../../../utils/easCli'; import { easCliVersion } from '../../../utils/easCli';
import { getVcsClient, setVcsClient } from '../../../vcs'; import { resolveVcsClient } from '../../../vcs';
import GitClient from '../../../vcs/clients/git';
async function applyCliConfigAsync(projectDir: string): Promise<void> { async function applyCliConfigAsync(projectDir: string): Promise<void> {
const easJsonAccessor = EasJsonAccessor.fromProjectPath(projectDir); const easJsonAccessor = EasJsonAccessor.fromProjectPath(projectDir);
const config = await EasJsonUtils.getCliConfigAsync(easJsonAccessor); const config = await EasJsonUtils.getCliConfigAsync(easJsonAccessor);
if (config?.version && !semver.satisfies(easCliVersion, config.version)) { if (config?.version && !semver.satisfies(easCliVersion, config.version)) {
throw new Error( throw new Error(
`You are on eas-cli@${easCliVersion} which does not satisfy the CLI version constraint in eas.json (${config.version})` `You are on eas-cli@${easCliVersion} which does not satisfy the CLI version constraint defined in eas.json (${
config.version
}).\n\nThis error probably means that you need update your eas-cli to a newer version.\nRun ${chalk.bold(
'npm install -g eas-cli'
)} to update the eas-cli to the latest version.`
); );
} }
if (config?.requireCommit) {
setVcsClient(new GitClient());
}
} }
async function ensureEasCliIsNotInDependenciesAsync(projectDir: string): Promise<void> { async function ensureEasCliIsNotInDependenciesAsync(projectDir: string): Promise<void> {
@@ -92,7 +92,7 @@ export async function findProjectRootAsync({
} else { } else {
let vcsRoot; let vcsRoot;
try { try {
vcsRoot = path.normalize(await getVcsClient().getRootPathAsync()); vcsRoot = path.normalize(await resolveVcsClient().getRootPathAsync());
} catch {} } catch {}
if (vcsRoot && vcsRoot.startsWith(projectRootDir) && vcsRoot !== projectRootDir) { if (vcsRoot && vcsRoot.startsWith(projectRootDir) && vcsRoot !== projectRootDir) {
throw new Error( throw new Error(
@@ -3,7 +3,7 @@ import { ExpoConfig } from '@expo/config-types';
import { Env } from '@expo/eas-build-job'; import { Env } from '@expo/eas-build-job';
import chalk from 'chalk'; import chalk from 'chalk';
import { createGraphqlClient } from './createGraphqlClient'; import { ExpoGraphqlClient, createGraphqlClient } from './createGraphqlClient';
import { findProjectRootAsync } from './findProjectDirAndVerifyProjectSetupAsync'; import { findProjectRootAsync } from './findProjectDirAndVerifyProjectSetupAsync';
import { AppQuery } from '../../../graphql/queries/AppQuery'; import { AppQuery } from '../../../graphql/queries/AppQuery';
import Log, { learnMore } from '../../../log'; import Log, { learnMore } from '../../../log';
@@ -87,6 +87,23 @@ export async function getProjectIdAsync(
}); });
const graphqlClient = createGraphqlClient(authenticationInfo); const graphqlClient = createGraphqlClient(authenticationInfo);
const projectId = await validateOrSetProjectIdAsync({ exp, graphqlClient, actor, options });
return projectId;
}
export async function validateOrSetProjectIdAsync({
exp,
graphqlClient,
actor,
options,
cwd,
}: {
exp: ExpoConfig;
graphqlClient: ExpoGraphqlClient;
actor: Actor;
options: { env?: Env; nonInteractive: boolean };
cwd?: string;
}): Promise<string> {
const localProjectId = exp.extra?.eas?.projectId; const localProjectId = exp.extra?.eas?.projectId;
if (localProjectId) { if (localProjectId) {
if (typeof localProjectId !== 'string') { if (typeof localProjectId !== 'string') {
@@ -146,7 +163,9 @@ export async function getProjectIdAsync(
return localProjectId; return localProjectId;
} }
const projectDir = await findProjectRootAsync(); const projectDir = await findProjectRootAsync({
cwd,
});
if (!projectDir) { if (!projectDir) {
throw new Error('This command must be run inside a project directory.'); throw new Error('This command must be run inside a project directory.');
} }
@@ -13,7 +13,6 @@ export default class AccountLogin extends EasCommand {
description: 'Login with SSO', description: 'Login with SSO',
char: 's', char: 's',
default: false, default: false,
hidden: true,
}), }),
}; };
@@ -11,10 +11,7 @@ import { isExpoUpdatesInstalled, isUsingEASUpdate } from '../../project/projectU
import { resolveWorkflowAsync } from '../../project/workflow'; import { resolveWorkflowAsync } from '../../project/workflow';
import { promptAsync } from '../../prompts'; import { promptAsync } from '../../prompts';
import { syncUpdatesConfigurationAsync as syncAndroidUpdatesConfigurationAsync } from '../../update/android/UpdatesModule'; import { syncUpdatesConfigurationAsync as syncAndroidUpdatesConfigurationAsync } from '../../update/android/UpdatesModule';
import { import { ensureEASUpdateIsConfiguredInEasJsonAsync } from '../../update/configure';
ensureEASUpdateIsConfiguredInEasJsonAsync,
ensureUseClassicUpdatesIsRemovedAsync,
} from '../../update/configure';
import { syncUpdatesConfigurationAsync as syncIosUpdatesConfigurationAsync } from '../../update/ios/UpdatesModule'; import { syncUpdatesConfigurationAsync as syncIosUpdatesConfigurationAsync } from '../../update/ios/UpdatesModule';
export default class BuildConfigure extends EasCommand { export default class BuildConfigure extends EasCommand {
@@ -38,7 +35,6 @@ export default class BuildConfigure extends EasCommand {
const { flags } = await this.parse(BuildConfigure); const { flags } = await this.parse(BuildConfigure);
const { const {
privateProjectConfig: { exp, projectId, projectDir }, privateProjectConfig: { exp, projectId, projectDir },
loggedIn: { graphqlClient },
vcsClient, vcsClient,
} = await this.getContextAsync(BuildConfigure, { } = await this.getContextAsync(BuildConfigure, {
nonInteractive: false, nonInteractive: false,
@@ -70,12 +66,6 @@ export default class BuildConfigure extends EasCommand {
vcsClient, vcsClient,
}); });
if (didCreateEasJson && isUsingEASUpdate(exp, projectId)) { if (didCreateEasJson && isUsingEASUpdate(exp, projectId)) {
if (exp.updates?.useClassicUpdates) {
// NOTE: this method modifies the Expo config; be sure to use this function's return value
// if the config object is used later in the future
await ensureUseClassicUpdatesIsRemovedAsync({ exp, projectDir });
}
await ensureEASUpdateIsConfiguredInEasJsonAsync(projectDir); await ensureEASUpdateIsConfiguredInEasJsonAsync(projectDir);
} }
@@ -84,20 +74,20 @@ export default class BuildConfigure extends EasCommand {
if ([RequestedPlatform.Android, RequestedPlatform.All].includes(platform)) { if ([RequestedPlatform.Android, RequestedPlatform.All].includes(platform)) {
const workflow = await resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient); const workflow = await resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient);
if (workflow === Workflow.GENERIC) { if (workflow === Workflow.GENERIC) {
await syncAndroidUpdatesConfigurationAsync(graphqlClient, projectDir, exp, projectId); await syncAndroidUpdatesConfigurationAsync({ projectDir, exp, workflow, env: undefined });
} }
} }
if ([RequestedPlatform.Ios, RequestedPlatform.All].includes(platform)) { if ([RequestedPlatform.Ios, RequestedPlatform.All].includes(platform)) {
const workflow = await resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient); const workflow = await resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient);
if (workflow === Workflow.GENERIC) { if (workflow === Workflow.GENERIC) {
await syncIosUpdatesConfigurationAsync( await syncIosUpdatesConfigurationAsync({
graphqlClient,
vcsClient, vcsClient,
projectDir, projectDir,
exp, exp,
projectId workflow,
); env: undefined,
});
} }
} }
} }
@@ -1,5 +1,6 @@
import { Platform } from '@expo/eas-build-job'; import { Platform } from '@expo/eas-build-job';
import { EasJsonAccessor, EasJsonUtils, ResourceClass } from '@expo/eas-json'; import { EasJsonAccessor, EasJsonUtils, ResourceClass } from '@expo/eas-json';
import { LoggerLevel } from '@expo/logger';
import { Errors, Flags } from '@oclif/core'; import { Errors, Flags } from '@oclif/core';
import chalk from 'chalk'; import chalk from 'chalk';
import figures from 'figures'; import figures from 'figures';
@@ -33,6 +34,9 @@ interface RawBuildFlags {
'auto-submit-with-profile'?: string; 'auto-submit-with-profile'?: string;
'resource-class'?: ResourceClass; 'resource-class'?: ResourceClass;
message?: string; message?: string;
'build-logger-level'?: LoggerLevel;
'freeze-credentials': boolean;
repack: boolean;
} }
export default class Build extends EasCommand { export default class Build extends EasCommand {
@@ -98,6 +102,19 @@ export default class Build extends EasCommand {
char: 'm', char: 'm',
description: 'A short message describing the build', description: 'A short message describing the build',
}), }),
'build-logger-level': Flags.enum({
description: 'The level of logs to output during the build process. Defaults to "info".',
options: Object.values(LoggerLevel),
}),
'freeze-credentials': Flags.boolean({
default: false,
description: 'Prevent the build from updating credentials in non-interactive mode',
}),
repack: Flags.boolean({
default: false,
hidden: true,
description: 'Use the golden dev client build repack flow as it works for onboarding',
}),
...EasNonInteractiveAndJsonFlags, ...EasNonInteractiveAndJsonFlags,
}; };
@@ -210,6 +227,9 @@ export default class Build extends EasCommand {
submitProfile: flags['auto-submit-with-profile'] ?? profile, submitProfile: flags['auto-submit-with-profile'] ?? profile,
resourceClass: flags['resource-class'], resourceClass: flags['resource-class'],
message, message,
buildLoggerLevel: flags['build-logger-level'],
freezeCredentials: flags['freeze-credentials'],
repack: flags.repack,
}; };
} }
@@ -105,6 +105,7 @@ export default class BuildInspect extends EasCommand {
projectDir, projectDir,
{ {
nonInteractive: false, nonInteractive: false,
freezeCredentials: false,
wait: true, wait: true,
clearCache: false, clearCache: false,
json: false, json: false,
@@ -119,6 +120,7 @@ export default class BuildInspect extends EasCommand {
workingdir: tmpWorkingdir, workingdir: tmpWorkingdir,
artifactsDir: path.join(tmpWorkingdir, 'artifacts'), artifactsDir: path.join(tmpWorkingdir, 'artifacts'),
}, },
repack: false,
}, },
actor, actor,
getDynamicPrivateProjectConfigAsync getDynamicPrivateProjectConfigAsync
@@ -6,7 +6,6 @@ import { runBuildAndSubmitAsync } from '../../build/runBuildAndSubmit';
import EasCommand from '../../commandUtils/EasCommand'; import EasCommand from '../../commandUtils/EasCommand';
import { RequestedPlatform } from '../../platform'; import { RequestedPlatform } from '../../platform';
import { enableJsonOutput } from '../../utils/json'; import { enableJsonOutput } from '../../utils/json';
import { setVcsClient } from '../../vcs';
import GitNoCommitClient from '../../vcs/clients/gitNoCommit'; import GitNoCommitClient from '../../vcs/clients/gitNoCommit';
/** /**
@@ -30,6 +29,17 @@ export default class BuildInternal extends EasCommand {
'Name of the build profile from eas.json. Defaults to "production" if defined in eas.json.', 'Name of the build profile from eas.json. Defaults to "production" if defined in eas.json.',
helpValue: 'PROFILE_NAME', helpValue: 'PROFILE_NAME',
}), }),
'auto-submit': Flags.boolean({
default: false,
description:
'Submit on build complete using the submit profile with the same name as the build profile',
exclusive: ['auto-submit-with-profile'],
}),
'auto-submit-with-profile': Flags.string({
description: 'Submit on build complete using the submit profile with provided name',
helpValue: 'PROFILE_NAME',
exclusive: ['auto-submit'],
}),
}; };
static override contextDefinition = { static override contextDefinition = {
@@ -53,10 +63,9 @@ export default class BuildInternal extends EasCommand {
vcsClient, vcsClient,
} = await this.getContextAsync(BuildInternal, { } = await this.getContextAsync(BuildInternal, {
nonInteractive: true, nonInteractive: true,
vcsClientOverride: new GitNoCommitClient(),
}); });
setVcsClient(new GitNoCommitClient());
await handleDeprecatedEasJsonAsync(projectDir, flags.nonInteractive); await handleDeprecatedEasJsonAsync(projectDir, flags.nonInteractive);
await runBuildAndSubmitAsync( await runBuildAndSubmitAsync(
@@ -68,13 +77,16 @@ export default class BuildInternal extends EasCommand {
requestedPlatform: flags.platform as RequestedPlatform, requestedPlatform: flags.platform as RequestedPlatform,
profile: flags.profile, profile: flags.profile,
nonInteractive: true, nonInteractive: true,
freezeCredentials: false,
wait: false, wait: false,
clearCache: false, clearCache: false,
json: true, json: true,
autoSubmit: false, autoSubmit: flags['auto-submit'] || flags['auto-submit-with-profile'] !== undefined,
localBuildOptions: { localBuildOptions: {
localBuildMode: LocalBuildMode.INTERNAL, localBuildMode: LocalBuildMode.INTERNAL,
}, },
submitProfile: flags['auto-submit-with-profile'] ?? flags.profile,
repack: false,
}, },
actor, actor,
getDynamicPrivateProjectConfigAsync getDynamicPrivateProjectConfigAsync
+59 -29
View File
@@ -10,6 +10,7 @@ import {
getPaginatedQueryOptions, getPaginatedQueryOptions,
} from '../../commandUtils/pagination'; } from '../../commandUtils/pagination';
import { AppPlatform, BuildStatus as GraphQLBuildStatus } from '../../graphql/generated'; import { AppPlatform, BuildStatus as GraphQLBuildStatus } from '../../graphql/generated';
import Log from '../../log';
import { RequestedPlatform } from '../../platform'; import { RequestedPlatform } from '../../platform';
import { getDisplayNameForProjectIdAsync } from '../../project/projectUtils'; import { getDisplayNameForProjectIdAsync } from '../../project/projectUtils';
import { buildDistributionTypeToGraphQLDistributionType } from '../../utils/buildDistribution'; import { buildDistributionTypeToGraphQLDistributionType } from '../../utils/buildDistribution';
@@ -20,37 +21,54 @@ export default class BuildList extends EasCommand {
static override flags = { static override flags = {
platform: Flags.enum({ platform: Flags.enum({
options: [RequestedPlatform.All, RequestedPlatform.Android, RequestedPlatform.Ios], options: Object.values(RequestedPlatform),
char: 'p',
}), }),
status: Flags.enum({ status: Flags.enum({
options: [ options: Object.values(BuildStatus),
BuildStatus.NEW, description: 'Filter only builds with the specified status',
BuildStatus.IN_QUEUE,
BuildStatus.IN_PROGRESS,
BuildStatus.PENDING_CANCEL,
BuildStatus.ERRORED,
BuildStatus.FINISHED,
BuildStatus.CANCELED,
],
}), }),
distribution: Flags.enum({ distribution: Flags.enum({
options: [ options: Object.values(BuildDistributionType),
BuildDistributionType.STORE, description: 'Filter only builds with the specified distribution type',
BuildDistributionType.INTERNAL,
BuildDistributionType.SIMULATOR,
],
}), }),
channel: Flags.string(), channel: Flags.string(),
appVersion: Flags.string(), 'app-version': Flags.string({
appBuildVersion: Flags.string(), aliases: ['appVersion'],
sdkVersion: Flags.string(), description: 'Filter only builds created with the specified main app version',
runtimeVersion: Flags.string(), }),
appIdentifier: Flags.string(), 'app-build-version': Flags.string({
buildProfile: Flags.string(), aliases: ['appBuildVersion'],
gitCommitHash: Flags.string(), description: 'Filter only builds created with the specified app build version',
}),
'sdk-version': Flags.string({
aliases: ['sdkVersion'],
description: 'Filter only builds created with the specified Expo SDK version',
}),
'runtime-version': Flags.string({
aliases: ['runtimeVersion'],
description: 'Filter only builds created with the specified runtime version',
}),
'app-identifier': Flags.string({
aliases: ['appIdentifier'],
description: 'Filter only builds created with the specified app identifier',
}),
'build-profile': Flags.string({
char: 'e',
aliases: ['profile', 'buildProfile'],
description: 'Filter only builds created with the specified build profile',
}),
'git-commit-hash': Flags.string({
aliases: ['gitCommitHash'],
description: 'Filter only builds created with the specified git commit hash',
}),
...EasPaginatedQueryFlags, ...EasPaginatedQueryFlags,
limit: getLimitFlagWithCustomValues({ defaultTo: 10, limit: BUILDS_LIMIT }), limit: getLimitFlagWithCustomValues({ defaultTo: 10, limit: BUILDS_LIMIT }),
...EasNonInteractiveAndJsonFlags, ...EasNonInteractiveAndJsonFlags,
simulator: Flags.boolean({
description:
'Filter only iOS simulator builds. Can only be used with --platform flag set to "ios"',
}),
}; };
static override contextDefinition = { static override contextDefinition = {
@@ -69,6 +87,17 @@ export default class BuildList extends EasCommand {
distribution: buildDistribution, distribution: buildDistribution,
'non-interactive': nonInteractive, 'non-interactive': nonInteractive,
} = flags; } = flags;
if (buildDistribution === BuildDistributionType.SIMULATOR) {
Log.warn(
`Using --distribution flag with "simulator" value is deprecated - use --simulator flag instead`
);
}
if (flags.simulator && requestedPlatform !== RequestedPlatform.Ios) {
Log.error(
`The --simulator flag is only usable with --platform flag set to "ios", as it is used to filter specifically iOS simulator builds`
);
process.exit(1);
}
const { const {
privateProjectConfig: { projectId }, privateProjectConfig: { projectId },
loggedIn: { graphqlClient }, loggedIn: { graphqlClient },
@@ -93,13 +122,14 @@ export default class BuildList extends EasCommand {
status: graphqlBuildStatus, status: graphqlBuildStatus,
distribution: graphqlBuildDistribution, distribution: graphqlBuildDistribution,
channel: flags.channel, channel: flags.channel,
appVersion: flags.appVersion, appVersion: flags['app-version'],
appBuildVersion: flags.appBuildVersion, appBuildVersion: flags['app-build-version'],
sdkVersion: flags.sdkVersion, sdkVersion: flags['sdk-version'],
runtimeVersion: flags.runtimeVersion, runtimeVersion: flags['runtime-version'],
appIdentifier: flags.appIdentifier, appIdentifier: flags['app-identifier'],
buildProfile: flags.buildProfile, buildProfile: flags['build-profile'],
gitCommitHash: flags.gitCommitHash, gitCommitHash: flags['git-commit-hash'],
simulator: flags.simulator,
}, },
paginatedQueryOptions, paginatedQueryOptions,
}); });
+27 -7
View File
@@ -42,7 +42,8 @@ interface BuildResignFlags {
offset?: number; offset?: number;
limit?: number; limit?: number;
platform?: Platform; platform?: Platform;
profile?: string; targetProfile?: string;
sourceProfile?: string;
maybeBuildId?: string; maybeBuildId?: string;
wait: boolean; wait: boolean;
} }
@@ -52,7 +53,8 @@ interface RawBuildResignFlags {
offset: number | undefined; offset: number | undefined;
limit: number | undefined; limit: number | undefined;
platform: 'android' | 'ios' | undefined; platform: 'android' | 'ios' | undefined;
profile: string | undefined; 'target-profile': string | undefined;
'source-profile': string | undefined;
wait: boolean; wait: boolean;
id: string | undefined; id: string | undefined;
} }
@@ -65,10 +67,16 @@ export default class BuildResign extends EasCommand {
char: 'p', char: 'p',
options: ['android', 'ios'], options: ['android', 'ios'],
}), }),
profile: Flags.string({ 'target-profile': Flags.string({
char: 'e', char: 'e',
description: description:
'Name of the build profile from eas.json. Defaults to "production" if defined in eas.json.', 'Name of the target build profile from eas.json. Credentials and environment variables from this profile will be used when re-signing. Defaults to "production" if defined in eas.json.',
helpValue: 'PROFILE_NAME',
aliases: ['profile'],
}),
'source-profile': Flags.string({
description:
'Name of the source build profile from eas.json. Used to filter builds eligible for re-signing.',
helpValue: 'PROFILE_NAME', helpValue: 'PROFILE_NAME',
}), }),
wait: Flags.boolean({ wait: Flags.boolean({
@@ -130,12 +138,20 @@ export default class BuildResign extends EasCommand {
const buildProfile = await EasJsonUtils.getBuildProfileAsync( const buildProfile = await EasJsonUtils.getBuildProfileAsync(
easJsonAccessor, easJsonAccessor,
platform, platform,
flags.profile ?? 'production' flags.targetProfile ?? 'production'
); );
const { exp, projectId } = await getDynamicPrivateProjectConfigAsync({ env: buildProfile.env }); const { exp, projectId } = await getDynamicPrivateProjectConfigAsync({ env: buildProfile.env });
const account = await getOwnerAccountForProjectIdAsync(graphqlClient, projectId); const account = await getOwnerAccountForProjectIdAsync(graphqlClient, projectId);
const build = await this.ensureBuildSelectedAsync( const build = await this.ensureBuildSelectedAsync(
{ graphqlClient, projectId, platform, nonInteractive, limit, offset }, {
graphqlClient,
projectId,
platform,
nonInteractive,
limit,
offset,
buildProfile: flags.sourceProfile,
},
maybeBuild maybeBuild
); );
const credentialsCtx = new CredentialsContext({ const credentialsCtx = new CredentialsContext({
@@ -228,7 +244,8 @@ export default class BuildResign extends EasCommand {
offset: flags.offset, offset: flags.offset,
limit: flags.limit, limit: flags.limit,
platform: flags.platform as Platform | undefined, platform: flags.platform as Platform | undefined,
profile: flags.profile, sourceProfile: flags['source-profile'],
targetProfile: flags['target-profile'],
maybeBuildId: flags.id, maybeBuildId: flags.id,
wait: flags.wait, wait: flags.wait,
}; };
@@ -242,6 +259,7 @@ export default class BuildResign extends EasCommand {
nonInteractive, nonInteractive,
limit, limit,
offset, offset,
buildProfile,
}: { }: {
graphqlClient: ExpoGraphqlClient; graphqlClient: ExpoGraphqlClient;
projectId: string; projectId: string;
@@ -249,6 +267,7 @@ export default class BuildResign extends EasCommand {
nonInteractive: boolean; nonInteractive: boolean;
limit?: number; limit?: number;
offset?: number; offset?: number;
buildProfile?: string;
}, },
maybeBuild?: BuildFragment maybeBuild?: BuildFragment
): Promise<BuildFragment> { ): Promise<BuildFragment> {
@@ -268,6 +287,7 @@ export default class BuildResign extends EasCommand {
distribution: DistributionType.Internal, distribution: DistributionType.Internal,
platform: toAppPlatform(platform), platform: toAppPlatform(platform),
status: BuildStatus.Finished, status: BuildStatus.Finished,
buildProfile,
}, },
}); });
if (!build) { if (!build) {
+4 -5
View File
@@ -11,7 +11,7 @@ import {
PaginatedQueryOptions, PaginatedQueryOptions,
getPaginatedQueryOptions, getPaginatedQueryOptions,
} from '../../commandUtils/pagination'; } from '../../commandUtils/pagination';
import { AppPlatform, BuildFragment, BuildStatus, DistributionType } from '../../graphql/generated'; import { AppPlatform, BuildFragment, BuildStatus } from '../../graphql/generated';
import { BuildQuery } from '../../graphql/queries/BuildQuery'; import { BuildQuery } from '../../graphql/queries/BuildQuery';
import Log from '../../log'; import Log from '../../log';
import { appPlatformDisplayNames } from '../../platform'; import { appPlatformDisplayNames } from '../../platform';
@@ -200,8 +200,7 @@ async function maybeGetBuildAsync(
projectId: string, projectId: string,
paginatedQueryOptions: PaginatedQueryOptions paginatedQueryOptions: PaginatedQueryOptions
): Promise<BuildFragment | null> { ): Promise<BuildFragment | null> {
const distributionType = const simulator = flags.selectedPlatform === AppPlatform.Ios ? true : undefined;
flags.selectedPlatform === AppPlatform.Ios ? DistributionType.Simulator : undefined;
if (flags.runArchiveFlags.id) { if (flags.runArchiveFlags.id) {
const build = await BuildQuery.byIdAsync(graphqlClient, flags.runArchiveFlags.id); const build = await BuildQuery.byIdAsync(graphqlClient, flags.runArchiveFlags.id);
@@ -219,9 +218,9 @@ async function maybeGetBuildAsync(
} build to run for ${await getDisplayNameForProjectIdAsync(graphqlClient, projectId)} app`, } build to run for ${await getDisplayNameForProjectIdAsync(graphqlClient, projectId)} app`,
filter: { filter: {
platform: flags.selectedPlatform, platform: flags.selectedPlatform,
distribution: distributionType,
status: BuildStatus.Finished, status: BuildStatus.Finished,
buildProfile: flags.profile, buildProfile: flags.profile,
simulator,
}, },
paginatedQueryOptions, paginatedQueryOptions,
selectPromptDisabledFunction: build => !isRunnableOnSimulatorOrEmulator(build), selectPromptDisabledFunction: build => !isRunnableOnSimulatorOrEmulator(build),
@@ -235,9 +234,9 @@ async function maybeGetBuildAsync(
projectId, projectId,
filter: { filter: {
platform: flags.selectedPlatform, platform: flags.selectedPlatform,
distribution: distributionType,
status: BuildStatus.Finished, status: BuildStatus.Finished,
buildProfile: flags.profile, buildProfile: flags.profile,
simulator,
}, },
}); });
@@ -88,6 +88,7 @@ export default class BuildVersionGetView extends EasCommand {
buildProfile: profile, buildProfile: profile,
platform, platform,
vcsClient, vcsClient,
nonInteractive: flags['non-interactive'],
}); });
const remoteVersions = await AppVersionQuery.latestVersionAsync( const remoteVersions = await AppVersionQuery.latestVersionAsync(
graphqlClient, graphqlClient,
@@ -1,4 +1,4 @@
import { getRuntimeVersionNullable } from '@expo/config-plugins/build/utils/Updates'; import { getRuntimeVersionNullableAsync } from '@expo/config-plugins/build/utils/Updates';
import { Platform } from '@expo/eas-build-job'; import { Platform } from '@expo/eas-build-job';
import { EasJsonAccessor, EasJsonUtils } from '@expo/eas-json'; import { EasJsonAccessor, EasJsonUtils } from '@expo/eas-json';
import { Flags } from '@oclif/core'; import { Flags } from '@oclif/core';
@@ -77,6 +77,7 @@ export default class BuildVersionSetView extends EasCommand {
buildProfile: profile, buildProfile: profile,
platform, platform,
vcsClient, vcsClient,
nonInteractive: false,
}); });
const remoteVersions = await AppVersionQuery.latestVersionAsync( const remoteVersions = await AppVersionQuery.latestVersionAsync(
graphqlClient, graphqlClient,
@@ -116,7 +117,8 @@ export default class BuildVersionSetView extends EasCommand {
applicationIdentifier, applicationIdentifier,
storeVersion: exp.version ?? '1.0.0', storeVersion: exp.version ?? '1.0.0',
buildVersion: String(version), buildVersion: String(version),
runtimeVersion: getRuntimeVersionNullable(exp, platform) ?? undefined, runtimeVersion:
(await getRuntimeVersionNullableAsync(projectDir, exp, platform)) ?? undefined,
}); });
} }
} }
@@ -102,6 +102,7 @@ export default class BuildVersionSyncView extends EasCommand {
buildProfile: profileInfo.profile, buildProfile: profileInfo.profile,
platform: profileInfo.platform, platform: profileInfo.platform,
vcsClient, vcsClient,
nonInteractive: false,
}); });
const remoteVersions = await AppVersionQuery.latestVersionAsync( const remoteVersions = await AppVersionQuery.latestVersionAsync(
graphqlClient, graphqlClient,
@@ -4,7 +4,11 @@ import { print } from 'graphql';
import gql from 'graphql-tag'; import gql from 'graphql-tag';
import { selectBranchOnAppAsync } from '../../branch/queries'; import { selectBranchOnAppAsync } from '../../branch/queries';
import { hasEmptyBranchMap, hasStandardBranchMap } from '../../channel/branch-mapping'; import {
getAlwaysTrueBranchMapping,
hasEmptyBranchMap,
hasStandardBranchMap,
} from '../../channel/branch-mapping';
import { selectChannelOnAppAsync } from '../../channel/queries'; import { selectChannelOnAppAsync } from '../../channel/queries';
import EasCommand from '../../commandUtils/EasCommand'; import EasCommand from '../../commandUtils/EasCommand';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient'; import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
@@ -124,11 +128,7 @@ export default class ChannelEdit extends EasCommand {
const channel = await updateChannelBranchMappingAsync(graphqlClient, { const channel = await updateChannelBranchMappingAsync(graphqlClient, {
channelId: existingChannel.id, channelId: existingChannel.id,
// todo: move branch mapping logic to utility branchMapping: JSON.stringify(getAlwaysTrueBranchMapping(branch.id)),
branchMapping: JSON.stringify({
data: [{ branchId: branch.id, branchMappingLogic: 'true' }],
version: 0,
}),
}); });
if (json) { if (json) {
@@ -117,7 +117,7 @@ export default class ChannelRollout extends EasCommand {
required: false, required: false,
}), }),
'private-key-path': Flags.string({ 'private-key-path': Flags.string({
description: `File containing the PEM-encoded private key corresponding to the certificate in expo-updates' configuration. Defaults to a file named "private-key.pem" in the certificate's directory.`, description: `File containing the PEM-encoded private key corresponding to the certificate in expo-updates' configuration. Defaults to a file named "private-key.pem" in the certificate's directory. Only relevant if you are using code signing: https://docs.expo.dev/eas-update/code-signing/`,
required: false, required: false,
}), }),
...EasNonInteractiveAndJsonFlags, ...EasNonInteractiveAndJsonFlags,
@@ -125,6 +125,7 @@ export default class ChannelRollout extends EasCommand {
static override contextDefinition = { static override contextDefinition = {
...this.ContextOptions.ProjectConfig, ...this.ContextOptions.ProjectConfig,
...this.ContextOptions.Vcs,
...this.ContextOptions.LoggedIn, ...this.ContextOptions.LoggedIn,
}; };
@@ -132,7 +133,8 @@ export default class ChannelRollout extends EasCommand {
const { args, flags } = await this.parse(ChannelRollout); const { args, flags } = await this.parse(ChannelRollout);
const argsAndFlags = this.sanitizeArgsAndFlags({ ...flags, ...args }); const argsAndFlags = this.sanitizeArgsAndFlags({ ...flags, ...args });
const { const {
privateProjectConfig: { exp, projectId }, privateProjectConfig: { exp, projectId, projectDir },
vcsClient,
loggedIn: { graphqlClient }, loggedIn: { graphqlClient },
} = await this.getContextAsync(ChannelRollout, { } = await this.getContextAsync(ChannelRollout, {
nonInteractive: argsAndFlags.nonInteractive, nonInteractive: argsAndFlags.nonInteractive,
@@ -141,12 +143,12 @@ export default class ChannelRollout extends EasCommand {
enableJsonOutput(); enableJsonOutput();
} }
const app = { projectId, exp }; const app = { projectId, exp, projectDir };
const ctx = { const ctx = {
projectId,
nonInteractive: argsAndFlags.nonInteractive, nonInteractive: argsAndFlags.nonInteractive,
graphqlClient, graphqlClient,
app, app,
vcsClient,
}; };
if (argsAndFlags.nonInteractive) { if (argsAndFlags.nonInteractive) {
await new NonInteractiveRollout(argsAndFlags).runAsync(ctx); await new NonInteractiveRollout(argsAndFlags).runAsync(ctx);
@@ -0,0 +1,65 @@
import { Platform } from '@expo/eas-build-job';
import { Flags } from '@oclif/core';
import EasCommand from '../../commandUtils/EasCommand';
import { SelectBuildProfileFromEasJson } from '../../credentials/manager/SelectBuildProfileFromEasJson';
import { SetUpBuildCredentialsCommandAction } from '../../credentials/manager/SetUpBuildCredentialsCommandAction';
import { selectPlatformAsync } from '../../platform';
export default class InitializeBuildCredentials extends EasCommand {
static override description = 'Set up credentials for building your project.';
static override flags = {
platform: Flags.enum({
char: 'p',
options: [Platform.ANDROID, Platform.IOS],
}),
profile: Flags.string({
char: 'e',
description: 'The name of the build profile in eas.json.',
helpValue: 'PROFILE_NAME',
}),
};
static override contextDefinition = {
...this.ContextOptions.LoggedIn,
...this.ContextOptions.ProjectConfig,
...this.ContextOptions.DynamicProjectConfig,
...this.ContextOptions.Analytics,
...this.ContextOptions.Vcs,
};
async runAsync(): Promise<void> {
const { flags } = await this.parse(InitializeBuildCredentials);
const {
loggedIn: { actor, graphqlClient },
privateProjectConfig,
getDynamicPrivateProjectConfigAsync,
analytics,
vcsClient,
} = await this.getContextAsync(InitializeBuildCredentials, {
nonInteractive: false,
});
const platform = await selectPlatformAsync(flags.platform);
const buildProfile =
flags.profile ??
(await new SelectBuildProfileFromEasJson(
privateProjectConfig.projectDir,
Platform.IOS
).getProfileNameFromEasConfigAsync());
await new SetUpBuildCredentialsCommandAction(
actor,
graphqlClient,
vcsClient,
analytics,
privateProjectConfig ?? null,
getDynamicPrivateProjectConfigAsync,
platform,
buildProfile,
process.cwd()
).runAsync();
}
}
@@ -1,7 +1,7 @@
import { Flags } from '@oclif/core'; import { Flags } from '@oclif/core';
import EasCommand from '../commandUtils/EasCommand'; import EasCommand from '../../commandUtils/EasCommand';
import { SelectPlatform } from '../credentials/manager/SelectPlatform'; import { SelectPlatform } from '../../credentials/manager/SelectPlatform';
export default class Credentials extends EasCommand { export default class Credentials extends EasCommand {
static override description = 'manage credentials'; static override description = 'manage credentials';
+6 -2
View File
@@ -1,8 +1,10 @@
import { Platform } from '@expo/eas-build-job'; import { Platform } from '@expo/eas-build-job';
import chalk from 'chalk';
import envinfo from 'envinfo'; import envinfo from 'envinfo';
import EasCommand from '../commandUtils/EasCommand'; import EasCommand from '../commandUtils/EasCommand';
import Log from '../log'; import Log from '../log';
import { ora } from '../ora';
import { resolveWorkflowAsync } from '../project/workflow'; import { resolveWorkflowAsync } from '../project/workflow';
import { easCliVersion } from '../utils/easCli'; import { easCliVersion } from '../utils/easCli';
import { Client } from '../vcs/vcs'; import { Client } from '../vcs/vcs';
@@ -20,6 +22,7 @@ export default class Diagnostics extends EasCommand {
nonInteractive: true, nonInteractive: true,
}); });
const spinner = ora().start(`Gathering diagnostic information...`);
const info = await envinfo.run( const info = await envinfo.run(
{ {
System: ['OS', 'Shell'], System: ['OS', 'Shell'],
@@ -40,9 +43,10 @@ export default class Diagnostics extends EasCommand {
npmGlobalPackages: ['eas-cli', 'expo-cli'], npmGlobalPackages: ['eas-cli', 'expo-cli'],
}, },
{ {
title: `EAS CLI ${easCliVersion} environment info`, title: chalk.bold(`EAS CLI ${easCliVersion} environment info`),
} }
); );
spinner.succeed('All needed information gathered!');
Log.log(info.trimEnd()); Log.log(info.trimEnd());
await this.printWorkflowAsync(projectDir, vcsClient); await this.printWorkflowAsync(projectDir, vcsClient);
@@ -56,7 +60,7 @@ export default class Diagnostics extends EasCommand {
if (androidWorkflow === iosWorkflow) { if (androidWorkflow === iosWorkflow) {
Log.log(` Project workflow: ${androidWorkflow}`); Log.log(` Project workflow: ${androidWorkflow}`);
} else { } else {
Log.log(` Project Workflow:`); Log.log(` Project workflow:`);
Log.log(` Android: ${androidWorkflow}`); Log.log(` Android: ${androidWorkflow}`);
Log.log(` iOS: ${iosWorkflow}`); Log.log(` iOS: ${iosWorkflow}`);
} }
@@ -110,6 +110,7 @@ describe(ProjectInit.name, () => {
it('is no-op if already configured for id', async () => { it('is no-op if already configured for id', async () => {
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({ jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
id: '1234', id: '1234',
name: 'testing-123',
slug: 'testing-123', slug: 'testing-123',
fullName: '@jester/testing-123', fullName: '@jester/testing-123',
ownerAccount: jester.accounts[0], ownerAccount: jester.accounts[0],
@@ -121,6 +122,7 @@ describe(ProjectInit.name, () => {
it('prompts to overwrite when different', async () => { it('prompts to overwrite when different', async () => {
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({ jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
id: '1234', id: '1234',
name: 'testing-123',
slug: 'testing-123', slug: 'testing-123',
fullName: '@jester/testing-123', fullName: '@jester/testing-123',
ownerAccount: jester.accounts[0], ownerAccount: jester.accounts[0],
@@ -135,6 +137,7 @@ describe(ProjectInit.name, () => {
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({ jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
id: '1234', id: '1234',
slug: 'testing-123', slug: 'testing-123',
name: 'testing-123',
fullName: '@jester/testing-123', fullName: '@jester/testing-123',
ownerAccount: jester.accounts[0], ownerAccount: jester.accounts[0],
}); });
@@ -152,6 +155,7 @@ describe(ProjectInit.name, () => {
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({ jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
id: '1234', id: '1234',
slug: 'testing-123', slug: 'testing-123',
name: 'testing-123',
fullName: '@jester/testing-123', fullName: '@jester/testing-123',
ownerAccount: jester.accounts[0], ownerAccount: jester.accounts[0],
}); });
@@ -186,6 +190,7 @@ describe(ProjectInit.name, () => {
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({ jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
id: '1234', id: '1234',
slug: 'testing-123', slug: 'testing-123',
name: 'testing-123',
fullName: '@jester/testing-123', fullName: '@jester/testing-123',
ownerAccount: jester.accounts[0], ownerAccount: jester.accounts[0],
}); });
@@ -198,6 +203,7 @@ describe(ProjectInit.name, () => {
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({ jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
id: '1234', id: '1234',
slug: 'testing-124', slug: 'testing-124',
name: 'testing-123',
fullName: '@jester2/testing-124', fullName: '@jester2/testing-124',
ownerAccount: jester2.accounts[0], ownerAccount: jester2.accounts[0],
}); });
@@ -223,6 +229,7 @@ describe(ProjectInit.name, () => {
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({ jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
id: '1234', id: '1234',
slug: 'testing-124', slug: 'testing-124',
name: 'testing-123',
fullName: '@jester2/testing-124', fullName: '@jester2/testing-124',
ownerAccount: jester2.accounts[0], ownerAccount: jester2.accounts[0],
}); });
@@ -247,6 +254,7 @@ describe(ProjectInit.name, () => {
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({ jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
id: '1234', id: '1234',
slug: 'testing-124', slug: 'testing-124',
name: 'testing-123',
fullName: '@jester2/testing-124', fullName: '@jester2/testing-124',
ownerAccount: jester2.accounts[0], ownerAccount: jester2.accounts[0],
}); });
@@ -273,6 +281,7 @@ describe(ProjectInit.name, () => {
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({ jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
id: '1234', id: '1234',
slug: 'testing-123', slug: 'testing-123',
name: 'testing-123',
fullName: '@jester/testing-123', fullName: '@jester/testing-123',
ownerAccount: jester.accounts[0], ownerAccount: jester.accounts[0],
}); });
@@ -288,6 +297,7 @@ describe(ProjectInit.name, () => {
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({ jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
id: '1234', id: '1234',
slug: 'testing-123', slug: 'testing-123',
name: 'testing-123',
fullName: '@jester/testing-123', fullName: '@jester/testing-123',
ownerAccount: jester.accounts[0], ownerAccount: jester.accounts[0],
}); });
@@ -302,6 +312,7 @@ describe(ProjectInit.name, () => {
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({ jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
id: '1234', id: '1234',
slug: 'testing-124', slug: 'testing-124',
name: 'testing-123',
fullName: '@jester2/testing-124', fullName: '@jester2/testing-124',
ownerAccount: jester2.accounts[0], ownerAccount: jester2.accounts[0],
}); });
@@ -329,6 +340,7 @@ describe(ProjectInit.name, () => {
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({ jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
id: '1234', id: '1234',
slug: 'testing-124', slug: 'testing-124',
name: 'testing-123',
fullName: '@jester2/testing-124', fullName: '@jester2/testing-124',
ownerAccount: jester2.accounts[0], ownerAccount: jester2.accounts[0],
}); });
@@ -355,6 +367,7 @@ describe(ProjectInit.name, () => {
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({ jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
id: '1234', id: '1234',
slug: 'testing-124', slug: 'testing-124',
name: 'testing-123',
fullName: '@jester2/testing-124', fullName: '@jester2/testing-124',
ownerAccount: jester2.accounts[0], ownerAccount: jester2.accounts[0],
}); });
@@ -384,6 +397,7 @@ describe(ProjectInit.name, () => {
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({ jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
id: '1234', id: '1234',
slug: 'testing-123', slug: 'testing-123',
name: 'testing-123',
fullName: '@jester/testing-123', fullName: '@jester/testing-123',
ownerAccount: jester.accounts[0], ownerAccount: jester.accounts[0],
}); });
@@ -398,6 +412,7 @@ describe(ProjectInit.name, () => {
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({ jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
id: '1234', id: '1234',
slug: 'testing-124', slug: 'testing-124',
name: 'testing-123',
fullName: '@jester2/testing-124', fullName: '@jester2/testing-124',
ownerAccount: jester2.accounts[0], ownerAccount: jester2.accounts[0],
}); });
@@ -437,6 +452,7 @@ describe(ProjectInit.name, () => {
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({ jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
id: '1234', id: '1234',
slug: 'testing-123', slug: 'testing-123',
name: 'testing-123',
fullName: '@jester/testing-123', fullName: '@jester/testing-123',
ownerAccount: jester.accounts[0], ownerAccount: jester.accounts[0],
}); });
@@ -464,6 +480,7 @@ describe(ProjectInit.name, () => {
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({ jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
id: '0129', id: '0129',
slug: 'testing-123', slug: 'testing-123',
name: 'testing-123',
fullName: '@jester/testing-123', fullName: '@jester/testing-123',
ownerAccount: jester.accounts[0], ownerAccount: jester.accounts[0],
}); });
+14 -2
View File
@@ -1,4 +1,4 @@
import { getProjectConfigDescription } from '@expo/config'; import { ConfigError, getProjectConfigDescription } from '@expo/config';
import { ExpoConfig } from '@expo/config-types'; import { ExpoConfig } from '@expo/config-types';
import { Flags } from '@oclif/core'; import { Flags } from '@oclif/core';
import chalk from 'chalk'; import chalk from 'chalk';
@@ -60,7 +60,19 @@ export default class ProjectInit extends EasCommand {
projectDir: string, projectDir: string,
modifications: Partial<ExpoConfig> modifications: Partial<ExpoConfig>
): Promise<void> { ): Promise<void> {
const result = await createOrModifyExpoConfigAsync(projectDir, modifications); let result;
try {
result = await createOrModifyExpoConfigAsync(projectDir, modifications);
} catch (error) {
if (error instanceof ConfigError && error.code === 'MODULE_NOT_FOUND') {
Log.warn(
'Cannot determine which native SDK version your project uses because the module `expo` is not installed.'
);
return;
} else {
throw error;
}
}
switch (result.type) { switch (result.type) {
case 'success': case 'success':
break; break;
@@ -0,0 +1,494 @@
import { ExpoConfig } from '@expo/config-types';
import { Platform } from '@expo/eas-build-job';
import { EasJson } from '@expo/eas-json';
import chalk from 'chalk';
import fs from 'fs-extra';
import path from 'path';
import { getEASUpdateURL, getExpoWebsiteBaseUrl } from '../../api';
import { runBuildAndSubmitAsync } from '../../build/runBuildAndSubmit';
import { reviewAndCommitChangesAsync } from '../../build/utils/repository';
import EasCommand from '../../commandUtils/EasCommand';
import { DynamicConfigContextFn } from '../../commandUtils/context/DynamicProjectConfigContextField';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
import { validateOrSetProjectIdAsync } from '../../commandUtils/context/contextUtils/getProjectIdAsync';
import { CredentialsContextProjectInfo } from '../../credentials/context';
import { SetUpBuildCredentialsCommandAction } from '../../credentials/manager/SetUpBuildCredentialsCommandAction';
import {
AppFragment,
AppPlatform,
OnboardingDeviceType,
OnboardingEnvironment,
} from '../../graphql/generated';
import { UserPreferencesMutation } from '../../graphql/mutations/UserPreferencesMutation';
import { AppQuery } from '../../graphql/queries/AppQuery';
import Log, { learnMore, link } from '../../log';
import {
canAccessRepositoryUsingSshAsync,
runGitCloneAsync,
runGitPushAsync,
} from '../../onboarding/git';
import { installDependenciesAsync } from '../../onboarding/installDependencies';
import { runCommandAsync } from '../../onboarding/runCommand';
import { RequestedPlatform } from '../../platform';
import { ExpoConfigOptions, getPrivateExpoConfig } from '../../project/expoConfig';
import { promptAsync } from '../../prompts';
import { Actor } from '../../user/User';
import { easCliVersion } from '../../utils/easCli';
import GitClient from '../../vcs/clients/git';
export default class Onboarding extends EasCommand {
static override aliases = ['init:onboarding', 'onboarding'];
static override description =
'continue onboarding process started on the https://expo.new website.';
static override flags = {};
static override args = [{ name: 'TARGET_PROJECT_DIRECTORY' }];
static override contextDefinition = {
...this.ContextOptions.LoggedIn,
...this.ContextOptions.Analytics,
};
async runAsync(): Promise<void> {
const {
args: { TARGET_PROJECT_DIRECTORY: targetProjectDirInput },
} = await this.parse(Onboarding);
const {
loggedIn: { actor, graphqlClient },
analytics,
} = await this.getContextAsync(Onboarding, {
nonInteractive: false,
});
if (actor.__typename === 'Robot') {
throw new Error(
'This command is not available for robot users. Make sure you are not using a robot token and try again.'
);
}
if (!actor.preferences.onboarding) {
throw new Error(
'This command can only be run as part of the onboarding process started on the Expo website. Visit https://expo.new to start a new project.'
);
}
if (!actor.preferences.onboarding.platform) {
throw new Error(
'This command can only be run as part of the onboarding process started on the Expo website. It seems like you started an onboarding process, but we are missing some information needed to be filled in before running the eas init:onboarding command (selected platform). Continue the onboarding process on the Expo website.'
);
}
if (!actor.preferences.onboarding.environment) {
throw new Error(
'This command can only be run as part of the onboarding process started on the Expo website. It seems like you started an onboarding process, but we are missing some information needed to be filled in before running the eas init:onboarding command (selected environment). Continue the onboarding process on the Expo website.'
);
}
if (!actor.preferences.onboarding.deviceType) {
throw new Error(
'This command can only be run as part of the onboarding process started on the Expo website. It seems like you started an onboarding process, but we are missing some information needed to be filled in before running the eas init:onboarding command (selected device type). Continue the onboarding process on the Expo website.'
);
}
if (
new Date(actor.preferences.onboarding.lastUsed) < new Date(Date.now() - 1000 * 60 * 60 * 24)
) {
Log.warn(
'It seems like you started an onboarding process, but it has been a while since you last used it. If you want to start a new onboarding process, visit https://expo.new.'
);
Log.log();
}
const platform =
actor.preferences.onboarding.platform === AppPlatform.Android
? Platform.ANDROID
: Platform.IOS;
const app = await AppQuery.byIdAsync(graphqlClient, actor.preferences.onboarding.appId);
const githubUsername = app.githubRepository
? app.githubRepository.metadata.githubRepoOwnerName
: 'expo';
const githubRepositoryName = app.githubRepository
? app.githubRepository.metadata.githubRepoName
: 'expo-template-default';
Log.log(`👋 Welcome to Expo, ${actor.username}!`);
Log.log();
Log.log('✨ We will continue your onboarding process in EAS CLI');
Log.log();
Log.log(
`🚚 Let's start by cloning ${
app.githubRepository
? `your project (${githubUsername}/${githubRepositoryName})`
: `default Expo template project (${githubUsername}/${githubRepositoryName})`
} from GitHub and installing dependencies.`
);
Log.log();
let initialTargetProjectDirectory: string;
if (targetProjectDirInput) {
initialTargetProjectDirectory = targetProjectDirInput;
Log.log(`📂 Cloning the project to ${initialTargetProjectDirectory}`);
} else {
const { selectedTargetProjectDirectory } = await promptAsync({
type: 'text',
name: 'selectedTargetProjectDirectory',
message: app.githubRepository
? '📂 Where would you like to clone the project to?'
: '📂 Where would you like to create your new project directory?',
initial: app.githubRepository
? path.join(process.cwd(), githubRepositoryName)
: path.join(process.cwd(), `${actor.username}-first-project`),
});
initialTargetProjectDirectory = selectedTargetProjectDirectory;
}
Log.log();
const cloneMethod = (await canAccessRepositoryUsingSshAsync({
githubUsername,
githubRepositoryName,
}))
? 'ssh'
: 'https';
Log.log(chalk.dim(`We detected that ${cloneMethod} is your preffered git clone method`));
Log.log();
const { targetProjectDir: finalTargetProjectDirectory } = await runGitCloneAsync({
githubUsername,
githubRepositoryName,
targetProjectDir: initialTargetProjectDirectory,
cloneMethod,
});
const vcsClient = new GitClient(finalTargetProjectDirectory);
if (!app.githubRepository) {
await fs.remove(path.join(finalTargetProjectDirectory, '.git'));
await runCommandAsync({
cwd: finalTargetProjectDirectory,
command: 'git',
args: ['init'],
});
Log.log();
await configureProjectFromBareDefaultExpoTemplateAsync({
app,
vcsClient,
targetDir: finalTargetProjectDirectory,
});
}
await installDependenciesAsync({
projectDir: finalTargetProjectDirectory,
});
const exp = await getPrivateExpoConfigWithProjectIdAsync({
projectDir: finalTargetProjectDirectory,
graphqlClient,
actor,
});
const getDynamicProjectConfigFn = getDynamicPrivateProjectConfigGetter({
projectDir: finalTargetProjectDirectory,
graphqlClient,
actor,
});
if (!app.githubRepository) {
await runCommandAsync({
cwd: finalTargetProjectDirectory,
command: 'npx',
args: ['expo', 'install', 'expo-updates'],
});
Log.log();
await runCommandAsync({
cwd: finalTargetProjectDirectory,
command: 'npx',
args: ['expo', 'install', 'expo-insights'],
});
Log.log();
await runCommandAsync({
cwd: finalTargetProjectDirectory,
command: 'npx',
args: ['expo', 'install', 'expo-dev-client'],
});
Log.log();
}
await vcsClient.trackFileAsync('package-lock.json');
const shouldSetupCredentials =
((platform === Platform.IOS &&
actor.preferences.onboarding.deviceType === OnboardingDeviceType.Device) ||
platform === Platform.ANDROID) &&
actor.preferences.onboarding.environment === OnboardingEnvironment.DevBuild;
if (shouldSetupCredentials) {
Log.log('🔑 Now we need to set up build credentials for your project:');
await new SetUpBuildCredentialsCommandAction(
actor,
graphqlClient,
vcsClient,
analytics,
exp,
getDynamicProjectConfigFn,
platform,
actor.preferences.onboarding.deviceType === OnboardingDeviceType.Simulator
? 'development-simulator'
: 'development',
finalTargetProjectDirectory
).runAsync();
}
if (app.githubRepository && (await vcsClient.hasUncommittedChangesAsync())) {
Log.log(
'📦 We will now commit the changes made by the configuration process and push them to GitHub:'
);
Log.log();
Log.log('🔍 Checking for changes in the repository...');
await vcsClient.showChangedFilesAsync();
await reviewAndCommitChangesAsync(
vcsClient,
`[eas-onboarding] Install dependencies${
shouldSetupCredentials ? ' and set up build credentials' : ''
}`,
{ nonInteractive: false }
);
Log.log('📤 Pushing changes to GitHub...');
await runGitPushAsync({
targetProjectDir: finalTargetProjectDirectory,
});
} else if (!app.githubRepository) {
await runCommandAsync({
cwd: finalTargetProjectDirectory,
command: 'git',
args: ['add', '.'],
});
Log.log();
await runCommandAsync({
cwd: finalTargetProjectDirectory,
command: 'git',
args: ['commit', '-m', 'Initial commit'],
});
Log.log();
}
Log.log();
Log.log('🎉 We finished configuring your project.');
Log.log();
if (
app.githubRepository ||
actor.preferences.onboarding.environment === OnboardingEnvironment.ExpoGo
) {
Log.log('🚀 You can now go back to the website to continue:');
const url = new URL(
`/onboarding/develop/set-up-project-on-your-machine?project=${app.slug}&accountId=${app.ownerAccount.id}`,
getExpoWebsiteBaseUrl()
).toString();
Log.log(`👉 ${link(url)}`);
} else {
Log.log('🚀 Now we are going to trigger your first build');
Log.log();
const { buildIds } = await runBuildAndSubmitAsync(
graphqlClient,
analytics,
vcsClient,
finalTargetProjectDirectory,
{
nonInteractive: true,
requestedPlatform:
platform === Platform.ANDROID ? RequestedPlatform.Android : RequestedPlatform.Ios,
profile:
actor.preferences.onboarding.deviceType === OnboardingDeviceType.Simulator
? 'development-simulator'
: 'development',
wait: false,
clearCache: false,
json: false,
autoSubmit: false,
localBuildOptions: {},
freezeCredentials: false,
repack: true,
},
actor,
getDynamicProjectConfigFn
);
const buildId = buildIds[0];
Log.log();
Log.log('🚀 You can now go back to the website to continue:');
const url = new URL(
`/onboarding/develop/set-up-project-on-your-machine?project=${app.slug}&accountId=${app.ownerAccount.id}&buildId=${buildId}`,
getExpoWebsiteBaseUrl()
).toString();
Log.log(`👉 ${link(url)}`);
}
const { __typename, ...previousPreferences } = actor.preferences.onboarding;
await UserPreferencesMutation.markCliDoneInOnboardingUserPreferencesAsync(graphqlClient, {
...previousPreferences,
appId: app.id,
});
}
}
// we can't get this automated by using command context because when we run a command the project directory doesn't exist yet
async function getPrivateExpoConfigWithProjectIdAsync({
projectDir,
graphqlClient,
actor,
options,
}: {
projectDir: string;
graphqlClient: ExpoGraphqlClient;
actor: Actor;
options?: ExpoConfigOptions;
}): Promise<CredentialsContextProjectInfo> {
const expBefore = getPrivateExpoConfig(projectDir, options);
const projectId = await validateOrSetProjectIdAsync({
exp: expBefore,
graphqlClient,
actor,
options: {
nonInteractive: false,
},
cwd: projectDir,
});
const exp = getPrivateExpoConfig(projectDir, options);
return {
exp,
projectId,
};
}
// we can't get this automated by using command context because when we run a command the project directory doesn't exist yet
function getDynamicPrivateProjectConfigGetter({
projectDir,
graphqlClient,
actor,
}: {
projectDir: string;
graphqlClient: ExpoGraphqlClient;
actor: Actor;
}): DynamicConfigContextFn {
return async (options?: ExpoConfigOptions) => {
return {
...(await getPrivateExpoConfigWithProjectIdAsync({
projectDir,
graphqlClient,
actor,
options,
})),
projectDir,
};
};
}
async function configureProjectFromBareDefaultExpoTemplateAsync({
app,
vcsClient,
targetDir,
}: {
app: AppFragment;
vcsClient: GitClient;
targetDir: string;
}): Promise<void> {
// Android package name requires each component to start with a lowercase letter.
const isUsernameValidSegment = /^[^a-z]/.test(app.ownerAccount.name);
const userPrefix = isUsernameValidSegment ? 'user' : '';
const isSlugValidSegment = /^[^a-z]/.test(app.slug);
const slugPrefix = isSlugValidSegment ? 'app' : '';
const bundleIdentifier = `com.${userPrefix}${stripInvalidCharactersForBundleIdentifier(
app.ownerAccount.name
)}.${slugPrefix}${stripInvalidCharactersForBundleIdentifier(app.slug)}`;
const updateUrl = getEASUpdateURL(app.id);
const easBuildGitHubConfig = {
android: {
image: 'latest',
},
ios: {
image: 'latest',
},
};
const easJson: EasJson = {
cli: {
version: `>= ${easCliVersion}`,
},
build: {
development: {
developmentClient: true,
distribution: 'internal',
...easBuildGitHubConfig,
},
'development-simulator': {
extends: 'development',
ios: {
simulator: true,
},
},
preview: {
distribution: 'internal',
channel: 'main',
...easBuildGitHubConfig,
},
production: {
channel: 'production',
...easBuildGitHubConfig,
},
},
submit: {
production: {},
},
};
const easJsonPath = path.join(targetDir, 'eas.json');
await fs.writeFile(easJsonPath, `${JSON.stringify(easJson, null, 2)}\n`);
await vcsClient.trackFileAsync(easJsonPath);
Log.log(
`✅ Generated ${chalk.bold('eas.json')}. ${learnMore(
'https://docs.expo.dev/build-reference/eas-json/'
)}`
);
Log.log();
const baseExpoConfig = JSON.parse(await fs.readFile(path.join(targetDir, 'app.json'), 'utf8'))
.expo as ExpoConfig;
const expoConfig: ExpoConfig = {
...baseExpoConfig,
name: app.name ?? app.slug,
slug: app.slug,
extra: {
eas: {
projectId: app.id,
},
},
owner: app.ownerAccount.name,
updates: {
url: updateUrl,
},
runtimeVersion: {
policy: 'appVersion',
},
ios: {
...baseExpoConfig.ios,
bundleIdentifier,
},
android: {
...baseExpoConfig.android,
package: bundleIdentifier,
},
};
const appJsonPath = path.join(targetDir, 'app.json');
await fs.writeFile(appJsonPath, `${JSON.stringify({ expo: expoConfig }, null, 2)}\n`);
await vcsClient.trackFileAsync(appJsonPath);
Log.log(
`✅ Generated ${chalk.bold('app.json')}. ${learnMore(
'https://docs.expo.dev/versions/latest/config/app/'
)}`
);
Log.log();
}
function stripInvalidCharactersForBundleIdentifier(string: string): string {
return string.replaceAll(/[^A-Za-z0-9]/g, '');
}
+9
View File
@@ -33,6 +33,7 @@ interface RawCommandFlags {
verbose: boolean; verbose: boolean;
wait: boolean; wait: boolean;
'non-interactive': boolean; 'non-interactive': boolean;
'verbose-fastlane': boolean;
} }
interface CommandFlags { interface CommandFlags {
@@ -42,6 +43,7 @@ interface CommandFlags {
verbose: boolean; verbose: boolean;
wait: boolean; wait: boolean;
nonInteractive: boolean; nonInteractive: boolean;
isVerboseFastlaneEnabled: boolean;
} }
export default class Submit extends EasCommand { export default class Submit extends EasCommand {
@@ -83,6 +85,10 @@ export default class Submit extends EasCommand {
default: true, default: true,
allowNo: true, allowNo: true,
}), }),
'verbose-fastlane': Flags.boolean({
default: false,
description: 'Enable verbose logging for the submission process',
}),
'non-interactive': Flags.boolean({ 'non-interactive': Flags.boolean({
default: false, default: false,
description: 'Run command in non-interactive mode', description: 'Run command in non-interactive mode',
@@ -132,6 +138,7 @@ export default class Submit extends EasCommand {
profile: submissionProfile.profile, profile: submissionProfile.profile,
archiveFlags: flagsWithPlatform.archiveFlags, archiveFlags: flagsWithPlatform.archiveFlags,
nonInteractive: flagsWithPlatform.nonInteractive, nonInteractive: flagsWithPlatform.nonInteractive,
isVerboseFastlaneEnabled: flagsWithPlatform.isVerboseFastlaneEnabled,
actor, actor,
graphqlClient, graphqlClient,
analytics, analytics,
@@ -175,6 +182,7 @@ export default class Submit extends EasCommand {
wait, wait,
profile, profile,
'non-interactive': nonInteractive, 'non-interactive': nonInteractive,
'verbose-fastlane': isVerboseFastlaneEnabled,
...archiveFlags ...archiveFlags
} = flags; } = flags;
@@ -195,6 +203,7 @@ export default class Submit extends EasCommand {
wait, wait,
profile, profile,
nonInteractive, nonInteractive,
isVerboseFastlaneEnabled,
}; };
} }
@@ -1,30 +0,0 @@
import { ExpoConfig } from '@expo/config';
import { instance, mock } from 'ts-mockito';
import { ExpoGraphqlClient } from '../../../commandUtils/context/contextUtils/createGraphqlClient';
import { ensureEASUpdateIsConfiguredAsync } from '../../../update/configure';
import { Client } from '../../../vcs/vcs';
describe(ensureEASUpdateIsConfiguredAsync, () => {
it('errors with "useClassicUpdates" set and no app.json', async () => {
const graphqlClient = instance(mock<ExpoGraphqlClient>({}));
const vcsClient = instance(mock<Client>({}));
const exp: ExpoConfig = {
name: 'test',
slug: 'test',
updates: { useClassicUpdates: true },
};
await expect(async () => {
await ensureEASUpdateIsConfiguredAsync(graphqlClient, {
exp,
projectId: 'test',
projectDir: '/tmp/test',
platform: null,
vcsClient,
});
}).rejects.toThrow(
`Your app config sets "updates.useClassicUpdates" but EAS Update does not support classic updates. Remove "useClassicUpdates" from your app config and run this command again.`
);
});
});
@@ -12,6 +12,7 @@ import {
DynamicPublicProjectConfigContextField, DynamicPublicProjectConfigContextField,
} from '../../../commandUtils/context/DynamicProjectConfigContextField'; } from '../../../commandUtils/context/DynamicProjectConfigContextField';
import LoggedInContextField from '../../../commandUtils/context/LoggedInContextField'; import LoggedInContextField from '../../../commandUtils/context/LoggedInContextField';
import VcsClientContextField from '../../../commandUtils/context/VcsClientContextField';
import { ExpoGraphqlClient } from '../../../commandUtils/context/contextUtils/createGraphqlClient'; import { ExpoGraphqlClient } from '../../../commandUtils/context/contextUtils/createGraphqlClient';
import FeatureGateEnvOverrides from '../../../commandUtils/gating/FeatureGateEnvOverrides'; import FeatureGateEnvOverrides from '../../../commandUtils/gating/FeatureGateEnvOverrides';
import FeatureGating from '../../../commandUtils/gating/FeatureGating'; import FeatureGating from '../../../commandUtils/gating/FeatureGating';
@@ -21,6 +22,7 @@ import { PublishMutation } from '../../../graphql/mutations/PublishMutation';
import { AppQuery } from '../../../graphql/queries/AppQuery'; import { AppQuery } from '../../../graphql/queries/AppQuery';
import { collectAssetsAsync, uploadAssetsAsync } from '../../../project/publish'; import { collectAssetsAsync, uploadAssetsAsync } from '../../../project/publish';
import { getBranchNameFromChannelNameAsync } from '../../../update/getBranchNameFromChannelNameAsync'; import { getBranchNameFromChannelNameAsync } from '../../../update/getBranchNameFromChannelNameAsync';
import { resolveVcsClient } from '../../../vcs';
const projectRoot = '/test-project'; const projectRoot = '/test-project';
const commandOptions = { root: projectRoot } as any; const commandOptions = { root: projectRoot } as any;
@@ -265,10 +267,14 @@ function mockTestProject({
featureGating: new FeatureGating({}, new FeatureGateEnvOverrides()), featureGating: new FeatureGating({}, new FeatureGateEnvOverrides()),
graphqlClient, graphqlClient,
}); });
jest
.spyOn(VcsClientContextField.prototype, 'getValueAsync')
.mockResolvedValue(resolveVcsClient());
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({ jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
id: '1234', id: '1234',
slug: 'testing-123', slug: 'testing-123',
name: 'testing-123',
fullName: '@jester/testing-123', fullName: '@jester/testing-123',
ownerAccount: jester.accounts[0], ownerAccount: jester.accounts[0],
}); });
@@ -324,7 +330,7 @@ function mockTestExport({
uniqueUploadedAssetPaths: [], uniqueUploadedAssetPaths: [],
}); });
jest.mocked(Updates.getRuntimeVersion).mockReturnValue(runtimeVersion); jest.mocked(Updates.getRuntimeVersionAsync).mockResolvedValue(runtimeVersion);
return { inputDir: exportDir, platforms, runtimeVersion }; return { inputDir: exportDir, platforms, runtimeVersion };
} }
@@ -367,6 +367,7 @@ function mockTestProject({
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({ jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
id: '1234', id: '1234',
slug: 'testing-123', slug: 'testing-123',
name: 'testing-123',
fullName: '@jester/testing-123', fullName: '@jester/testing-123',
ownerAccount: jester.accounts[0], ownerAccount: jester.accounts[0],
}); });
@@ -11,6 +11,7 @@ import {
DynamicPublicProjectConfigContextField, DynamicPublicProjectConfigContextField,
} from '../../../commandUtils/context/DynamicProjectConfigContextField'; } from '../../../commandUtils/context/DynamicProjectConfigContextField';
import LoggedInContextField from '../../../commandUtils/context/LoggedInContextField'; import LoggedInContextField from '../../../commandUtils/context/LoggedInContextField';
import VcsClientContextField from '../../../commandUtils/context/VcsClientContextField';
import { ExpoGraphqlClient } from '../../../commandUtils/context/contextUtils/createGraphqlClient'; import { ExpoGraphqlClient } from '../../../commandUtils/context/contextUtils/createGraphqlClient';
import FeatureGateEnvOverrides from '../../../commandUtils/gating/FeatureGateEnvOverrides'; import FeatureGateEnvOverrides from '../../../commandUtils/gating/FeatureGateEnvOverrides';
import FeatureGating from '../../../commandUtils/gating/FeatureGating'; import FeatureGating from '../../../commandUtils/gating/FeatureGating';
@@ -19,6 +20,7 @@ import { UpdateFragment } from '../../../graphql/generated';
import { PublishMutation } from '../../../graphql/mutations/PublishMutation'; import { PublishMutation } from '../../../graphql/mutations/PublishMutation';
import { AppQuery } from '../../../graphql/queries/AppQuery'; import { AppQuery } from '../../../graphql/queries/AppQuery';
import { getBranchNameFromChannelNameAsync } from '../../../update/getBranchNameFromChannelNameAsync'; import { getBranchNameFromChannelNameAsync } from '../../../update/getBranchNameFromChannelNameAsync';
import { resolveVcsClient } from '../../../vcs';
import UpdateRollBackToEmbedded from '../roll-back-to-embedded'; import UpdateRollBackToEmbedded from '../roll-back-to-embedded';
const projectRoot = '/test-project'; const projectRoot = '/test-project';
@@ -84,7 +86,7 @@ describe(UpdateRollBackToEmbedded.name, () => {
mockTestProject(); mockTestProject();
const platforms = ['android', 'ios']; const platforms = ['android', 'ios'];
const runtimeVersion = 'exposdk:47.0.0'; const runtimeVersion = 'exposdk:47.0.0';
jest.mocked(Updates.getRuntimeVersion).mockReturnValue(runtimeVersion); jest.mocked(Updates.getRuntimeVersionAsync).mockResolvedValue(runtimeVersion);
jest.mocked(ensureBranchExistsAsync).mockResolvedValue({ jest.mocked(ensureBranchExistsAsync).mockResolvedValue({
branchId: 'branch123', branchId: 'branch123',
@@ -106,7 +108,7 @@ describe(UpdateRollBackToEmbedded.name, () => {
const { projectId } = mockTestProject(); const { projectId } = mockTestProject();
const platforms = ['android', 'ios']; const platforms = ['android', 'ios'];
const runtimeVersion = 'exposdk:47.0.0'; const runtimeVersion = 'exposdk:47.0.0';
jest.mocked(Updates.getRuntimeVersion).mockReturnValue(runtimeVersion); jest.mocked(Updates.getRuntimeVersionAsync).mockResolvedValue(runtimeVersion);
jest.mocked(getBranchNameFromChannelNameAsync).mockResolvedValue('branchFromChannel'); jest.mocked(getBranchNameFromChannelNameAsync).mockResolvedValue('branchFromChannel');
jest.mocked(ensureBranchExistsAsync).mockResolvedValue({ jest.mocked(ensureBranchExistsAsync).mockResolvedValue({
@@ -154,7 +156,7 @@ describe(UpdateRollBackToEmbedded.name, () => {
const platforms = ['ios']; const platforms = ['ios'];
const runtimeVersion = 'exposdk:47.0.0'; const runtimeVersion = 'exposdk:47.0.0';
jest.mocked(Updates.getRuntimeVersion).mockReturnValue(runtimeVersion); jest.mocked(Updates.getRuntimeVersionAsync).mockResolvedValue(runtimeVersion);
// Mock an existing branch, so we don't create a new one // Mock an existing branch, so we don't create a new one
jest.mocked(ensureBranchExistsAsync).mockResolvedValue({ jest.mocked(ensureBranchExistsAsync).mockResolvedValue({
@@ -250,10 +252,14 @@ function mockTestProject({
featureGating: new FeatureGating({}, new FeatureGateEnvOverrides()), featureGating: new FeatureGating({}, new FeatureGateEnvOverrides()),
graphqlClient, graphqlClient,
}); });
jest
.spyOn(VcsClientContextField.prototype, 'getValueAsync')
.mockResolvedValue(resolveVcsClient());
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({ jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
id: '1234', id: '1234',
slug: 'testing-123', slug: 'testing-123',
name: 'testing-123',
fullName: '@jester/testing-123', fullName: '@jester/testing-123',
ownerAccount: jester.accounts[0], ownerAccount: jester.accounts[0],
}); });
@@ -35,7 +35,6 @@ export default class UpdateConfigure extends EasCommand {
const platform = flags.platform as RequestedPlatform; const platform = flags.platform as RequestedPlatform;
const { const {
privateProjectConfig: { projectId, exp, projectDir }, privateProjectConfig: { projectId, exp, projectDir },
loggedIn: { graphqlClient },
vcsClient, vcsClient,
} = await this.getContextAsync(UpdateConfigure, { } = await this.getContextAsync(UpdateConfigure, {
nonInteractive: flags['non-interactive'], nonInteractive: flags['non-interactive'],
@@ -47,12 +46,13 @@ export default class UpdateConfigure extends EasCommand {
await vcsClient.ensureRepoExistsAsync(); await vcsClient.ensureRepoExistsAsync();
await ensureEASUpdateIsConfiguredAsync(graphqlClient, { await ensureEASUpdateIsConfiguredAsync({
exp, exp,
projectId, projectId,
projectDir, projectDir,
platform, platform,
vcsClient, vcsClient,
env: undefined,
}); });
await ensureEASUpdateIsConfiguredInEasJsonAsync(projectDir); await ensureEASUpdateIsConfiguredInEasJsonAsync(projectDir);
+38 -35
View File
@@ -1,11 +1,14 @@
import { Platform as PublishPlatform } from '@expo/config'; import { Platform as PublishPlatform } from '@expo/config';
import { Workflow } from '@expo/eas-build-job';
import { Errors, Flags } from '@oclif/core'; import { Errors, Flags } from '@oclif/core';
import chalk from 'chalk'; import chalk from 'chalk';
import indentString from 'indent-string';
import nullthrows from 'nullthrows'; import nullthrows from 'nullthrows';
import qrcodeTerminal from 'qrcode-terminal';
import { ensureBranchExistsAsync } from '../../branch/queries'; import { ensureBranchExistsAsync } from '../../branch/queries';
import { getUpdateGroupUrl } from '../../build/utils/url'; import { ensureRepoIsCleanAsync } from '../../build/utils/repository';
import { ensureChannelExistsAsync } from '../../channel/queries'; import { getUpdateGroupUrl, getUpdatePreviewUrl } from '../../build/utils/url';
import EasCommand from '../../commandUtils/EasCommand'; import EasCommand from '../../commandUtils/EasCommand';
import { EasNonInteractiveAndJsonFlags } from '../../commandUtils/flags'; import { EasNonInteractiveAndJsonFlags } from '../../commandUtils/flags';
import { getPaginatedQueryOptions } from '../../commandUtils/pagination'; import { getPaginatedQueryOptions } from '../../commandUtils/pagination';
@@ -29,7 +32,6 @@ import {
collectAssetsAsync, collectAssetsAsync,
defaultPublishPlatforms, defaultPublishPlatforms,
filterExportedPlatformsByFlag, filterExportedPlatformsByFlag,
generateEasMetadataAsync,
getBranchNameForCommandAsync, getBranchNameForCommandAsync,
getRequestedPlatform, getRequestedPlatform,
getRuntimeToPlatformMappingFromRuntimeVersions, getRuntimeToPlatformMappingFromRuntimeVersions,
@@ -40,6 +42,7 @@ import {
resolveInputDirectoryAsync, resolveInputDirectoryAsync,
uploadAssetsAsync, uploadAssetsAsync,
} from '../../project/publish'; } from '../../project/publish';
import { resolveWorkflowPerPlatformAsync } from '../../project/workflow';
import { ensureEASUpdateIsConfiguredAsync } from '../../update/configure'; import { ensureEASUpdateIsConfiguredAsync } from '../../update/configure';
import { getUpdateJsonInfosForUpdates } from '../../update/utils'; import { getUpdateJsonInfosForUpdates } from '../../update/utils';
import { import {
@@ -56,7 +59,6 @@ import { maybeWarnAboutEasOutagesAsync } from '../../utils/statuspageService';
type RawUpdateFlags = { type RawUpdateFlags = {
auto: boolean; auto: boolean;
dev: boolean;
branch?: string; branch?: string;
channel?: string; channel?: string;
message?: string; message?: string;
@@ -75,7 +77,6 @@ type RawUpdateFlags = {
type UpdateFlags = { type UpdateFlags = {
auto: boolean; auto: boolean;
dev: boolean;
platform: ExpoCLIExportPlatformFlag; platform: ExpoCLIExportPlatformFlag;
branchName?: string; branchName?: string;
channelName?: string; channelName?: string;
@@ -136,17 +137,13 @@ export default class UpdatePublish extends EasCommand {
default: 'all', default: 'all',
required: false, required: false,
}), }),
dev: Flags.boolean({
description: 'Publish a development bundle',
default: false,
}),
auto: Flags.boolean({ auto: Flags.boolean({
description: description:
'Use the current git branch and commit message for the EAS branch and update message', 'Use the current git branch and commit message for the EAS branch and update message',
default: false, default: false,
}), }),
'private-key-path': Flags.string({ 'private-key-path': Flags.string({
description: `File containing the PEM-encoded private key corresponding to the certificate in expo-updates' configuration. Defaults to a file named "private-key.pem" in the certificate's directory.`, description: `File containing the PEM-encoded private key corresponding to the certificate in expo-updates' configuration. Defaults to a file named "private-key.pem" in the certificate's directory. Only relevant if you are using code signing: https://docs.expo.dev/eas-update/code-signing/`,
required: false, required: false,
}), }),
...EasNonInteractiveAndJsonFlags, ...EasNonInteractiveAndJsonFlags,
@@ -165,7 +162,6 @@ export default class UpdatePublish extends EasCommand {
auto: autoFlag, auto: autoFlag,
platform: platformFlag, platform: platformFlag,
channelName: channelNameArg, channelName: channelNameArg,
dev,
updateMessage: updateMessageArg, updateMessage: updateMessageArg,
inputDir, inputDir,
skipBundler, skipBundler,
@@ -189,6 +185,9 @@ export default class UpdatePublish extends EasCommand {
enableJsonOutput(); enableJsonOutput();
} }
await vcsClient.ensureRepoExistsAsync();
await ensureRepoIsCleanAsync(vcsClient, nonInteractive);
const { const {
exp: expPossiblyWithoutEasUpdateConfigured, exp: expPossiblyWithoutEasUpdateConfigured,
projectId, projectId,
@@ -197,12 +196,13 @@ export default class UpdatePublish extends EasCommand {
await maybeWarnAboutEasOutagesAsync(graphqlClient, [StatuspageServiceName.EasUpdate]); await maybeWarnAboutEasOutagesAsync(graphqlClient, [StatuspageServiceName.EasUpdate]);
await ensureEASUpdateIsConfiguredAsync(graphqlClient, { await ensureEASUpdateIsConfiguredAsync({
exp: expPossiblyWithoutEasUpdateConfigured, exp: expPossiblyWithoutEasUpdateConfigured,
platform: getRequestedPlatform(platformFlag), platform: getRequestedPlatform(platformFlag),
projectDir, projectDir,
projectId, projectId,
vcsClient, vcsClient,
env: undefined,
}); });
const { exp } = await getDynamicPublicProjectConfigAsync(); const { exp } = await getDynamicPublicProjectConfigAsync();
@@ -231,7 +231,7 @@ export default class UpdatePublish extends EasCommand {
if (!skipBundler) { if (!skipBundler) {
const bundleSpinner = ora().start('Exporting...'); const bundleSpinner = ora().start('Exporting...');
try { try {
await buildBundlesAsync({ projectDir, inputDir, dev, exp, platformFlag, clearCache }); await buildBundlesAsync({ projectDir, inputDir, exp, platformFlag, clearCache });
bundleSpinner.succeed('Exported bundle(s)'); bundleSpinner.succeed('Exported bundle(s)');
} catch (e) { } catch (e) {
bundleSpinner.fail('Export failed'); bundleSpinner.fail('Export failed');
@@ -355,7 +355,7 @@ export default class UpdatePublish extends EasCommand {
Log.withInfo( Log.withInfo(
`${platformString} (maximum: ${assetLimitPerUpdateGroup} total per update). ${learnMore( `${platformString} (maximum: ${assetLimitPerUpdateGroup} total per update). ${learnMore(
'https://expo.fyi/eas-update-asset-limits', 'https://expo.fyi/eas-update-asset-limits',
{ learnMoreMessage: 'Learn more about asset limits.' } { learnMoreMessage: 'Learn more about asset limits' }
)}` )}`
); );
} catch (e) { } catch (e) {
@@ -363,29 +363,24 @@ export default class UpdatePublish extends EasCommand {
throw e; throw e;
} }
const runtimeVersions = await getRuntimeVersionObjectAsync( const workflows = await resolveWorkflowPerPlatformAsync(projectDir, vcsClient);
const runtimeVersions = await getRuntimeVersionObjectAsync({
exp, exp,
realizedPlatforms, platforms: realizedPlatforms,
projectDir, projectDir,
vcsClient workflows: {
); ...workflows,
web: Workflow.UNKNOWN,
},
env: undefined,
});
const runtimeToPlatformMapping = const runtimeToPlatformMapping =
getRuntimeToPlatformMappingFromRuntimeVersions(runtimeVersions); getRuntimeToPlatformMappingFromRuntimeVersions(runtimeVersions);
const { branchId, createdBranch } = await ensureBranchExistsAsync(graphqlClient, { const { branchId } = await ensureBranchExistsAsync(graphqlClient, {
appId: projectId, appId: projectId,
branchName, branchName,
}); });
if (createdBranch) {
await ensureChannelExistsAsync(graphqlClient, {
appId: projectId,
branchId,
channelName: branchName,
});
Log.withTick(
`Channel: ${chalk.bold(branchName)} pointed at branch: ${chalk.bold(branchName)}`
);
}
const gitCommitHash = await vcsClient.getCommitHashAsync(); const gitCommitHash = await vcsClient.getCommitHashAsync();
const isGitWorkingTreeDirty = await vcsClient.hasUncommittedChangesAsync(); const isGitWorkingTreeDirty = await vcsClient.hasUncommittedChangesAsync();
@@ -469,9 +464,6 @@ export default class UpdatePublish extends EasCommand {
throw e; throw e;
} }
if (!skipBundler) {
await generateEasMetadataAsync(distRoot, getUpdateJsonInfosForUpdates(newUpdates));
}
if (jsonFlag) { if (jsonFlag) {
printJsonOnlyOutput(getUpdateJsonInfosForUpdates(newUpdates)); printJsonOnlyOutput(getUpdateJsonInfosForUpdates(newUpdates));
} else { } else {
@@ -504,6 +496,15 @@ export default class UpdatePublish extends EasCommand {
const accountName = (await getOwnerAccountForProjectIdAsync(graphqlClient, projectId)).name; const accountName = (await getOwnerAccountForProjectIdAsync(graphqlClient, projectId)).name;
const updateGroupUrl = getUpdateGroupUrl(accountName, projectName, updateGroupId); const updateGroupUrl = getUpdateGroupUrl(accountName, projectName, updateGroupId);
const updateGroupLink = link(updateGroupUrl, { dim: false }); const updateGroupLink = link(updateGroupUrl, { dim: false });
const updateCreatedAt = (newAndroidUpdate ?? newIosUpdate)?.createdAt;
const updateQrCodeUrl = getUpdatePreviewUrl({
message: updateMessage,
updateRuntimeVersion: runtime.runtimeVersion,
createdAt: updateCreatedAt.toString(),
slug: projectName, // todo check this
projectId,
group: updateGroupId,
});
Log.log( Log.log(
formatFields([ formatFields([
@@ -524,9 +525,12 @@ export default class UpdatePublish extends EasCommand {
}, },
] ]
: []), : []),
{ label: 'Website link', value: updateGroupLink }, { label: 'EAS Dashboard', value: updateGroupLink },
]) ])
); );
qrcodeTerminal.generate(updateQrCodeUrl, { small: true }, code =>
Log.log(`${indentString(code, 2)}\n`)
);
Log.addNewLineIfNone(); Log.addNewLineIfNone();
if ( if (
isUploadedAssetCountAboveWarningThreshold(uploadedAssetCount, assetLimitPerUpdateGroup) isUploadedAssetCountAboveWarningThreshold(uploadedAssetCount, assetLimitPerUpdateGroup)
@@ -547,7 +551,7 @@ export default class UpdatePublish extends EasCommand {
private sanitizeFlags(flags: RawUpdateFlags): UpdateFlags { private sanitizeFlags(flags: RawUpdateFlags): UpdateFlags {
const nonInteractive = flags['non-interactive'] ?? false; const nonInteractive = flags['non-interactive'] ?? false;
const { auto, branch: branchName, channel: channelName, dev, message: updateMessage } = flags; const { auto, branch: branchName, channel: channelName, message: updateMessage } = flags;
if (nonInteractive && !auto && !(updateMessage && (branchName || channelName))) { if (nonInteractive && !auto && !(updateMessage && (branchName || channelName))) {
Errors.error( Errors.error(
'--branch and --message, or --channel and --message are required when updating in non-interactive mode unless --auto is specified', '--branch and --message, or --channel and --message are required when updating in non-interactive mode unless --auto is specified',
@@ -576,7 +580,6 @@ export default class UpdatePublish extends EasCommand {
auto, auto,
branchName, branchName,
channelName, channelName,
dev,
updateMessage, updateMessage,
inputDir: flags['input-dir'], inputDir: flags['input-dir'],
skipBundler: flags['skip-bundler'], skipBundler: flags['skip-bundler'],
@@ -69,7 +69,7 @@ export default class UpdateRepublish extends EasCommand {
required: false, required: false,
}), }),
'private-key-path': Flags.string({ 'private-key-path': Flags.string({
description: `File containing the PEM-encoded private key corresponding to the certificate in expo-updates' configuration. Defaults to a file named "private-key.pem" in the certificate's directory.`, description: `File containing the PEM-encoded private key corresponding to the certificate in expo-updates' configuration. Defaults to a file named "private-key.pem" in the certificate's directory. Only relevant if you are using code signing: https://docs.expo.dev/eas-update/code-signing/`,
required: false, required: false,
}), }),
...EasNonInteractiveAndJsonFlags, ...EasNonInteractiveAndJsonFlags,
@@ -1,11 +1,10 @@
import { Platform as PublishPlatform } from '@expo/config'; import { Platform as PublishPlatform } from '@expo/config';
import { Workflow } from '@expo/eas-build-job';
import { Errors, Flags } from '@oclif/core'; import { Errors, Flags } from '@oclif/core';
import chalk from 'chalk';
import nullthrows from 'nullthrows'; import nullthrows from 'nullthrows';
import { ensureBranchExistsAsync } from '../../branch/queries'; import { ensureBranchExistsAsync } from '../../branch/queries';
import { getUpdateGroupUrl } from '../../build/utils/url'; import { getUpdateGroupUrl } from '../../build/utils/url';
import { ensureChannelExistsAsync } from '../../channel/queries';
import EasCommand from '../../commandUtils/EasCommand'; import EasCommand from '../../commandUtils/EasCommand';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient'; import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
import { EasNonInteractiveAndJsonFlags } from '../../commandUtils/flags'; import { EasNonInteractiveAndJsonFlags } from '../../commandUtils/flags';
@@ -33,6 +32,7 @@ import {
getRuntimeVersionObjectAsync, getRuntimeVersionObjectAsync,
getUpdateMessageForCommandAsync, getUpdateMessageForCommandAsync,
} from '../../project/publish'; } from '../../project/publish';
import { resolveWorkflowPerPlatformAsync } from '../../project/workflow';
import { ensureEASUpdateIsConfiguredAsync } from '../../update/configure'; import { ensureEASUpdateIsConfiguredAsync } from '../../update/configure';
import { getUpdateJsonInfosForUpdates } from '../../update/utils'; import { getUpdateJsonInfosForUpdates } from '../../update/utils';
import { import {
@@ -101,7 +101,7 @@ export default class UpdateRollBackToEmbedded extends EasCommand {
default: false, default: false,
}), }),
'private-key-path': Flags.string({ 'private-key-path': Flags.string({
description: `File containing the PEM-encoded private key corresponding to the certificate in expo-updates' configuration. Defaults to a file named "private-key.pem" in the certificate's directory.`, description: `File containing the PEM-encoded private key corresponding to the certificate in expo-updates' configuration. Defaults to a file named "private-key.pem" in the certificate's directory. Only relevant if you are using code signing: https://docs.expo.dev/eas-update/code-signing/`,
required: false, required: false,
}), }),
...EasNonInteractiveAndJsonFlags, ...EasNonInteractiveAndJsonFlags,
@@ -148,12 +148,13 @@ export default class UpdateRollBackToEmbedded extends EasCommand {
await maybeWarnAboutEasOutagesAsync(graphqlClient, [StatuspageServiceName.EasUpdate]); await maybeWarnAboutEasOutagesAsync(graphqlClient, [StatuspageServiceName.EasUpdate]);
await ensureEASUpdateIsConfiguredAsync(graphqlClient, { await ensureEASUpdateIsConfiguredAsync({
exp: expPossiblyWithoutEasUpdateConfigured, exp: expPossiblyWithoutEasUpdateConfigured,
platform: getRequestedPlatform(platformFlag), platform: getRequestedPlatform(platformFlag),
projectDir, projectDir,
projectId, projectId,
vcsClient, vcsClient,
env: undefined,
}); });
// check that the expo-updates package version supports roll back to embedded // check that the expo-updates package version supports roll back to embedded
@@ -184,29 +185,25 @@ export default class UpdateRollBackToEmbedded extends EasCommand {
const realizedPlatforms: PublishPlatform[] = const realizedPlatforms: PublishPlatform[] =
platformFlag === 'all' ? defaultPublishPlatforms : [platformFlag]; platformFlag === 'all' ? defaultPublishPlatforms : [platformFlag];
const { branchId, createdBranch } = await ensureBranchExistsAsync(graphqlClient, { const { branchId } = await ensureBranchExistsAsync(graphqlClient, {
appId: projectId, appId: projectId,
branchName, branchName,
}); });
if (createdBranch) {
await ensureChannelExistsAsync(graphqlClient, {
appId: projectId,
branchId,
channelName: branchName,
});
}
Log.withTick(`Channel: ${chalk.bold(branchName)} pointed at branch: ${chalk.bold(branchName)}`);
const gitCommitHash = await vcsClient.getCommitHashAsync(); const gitCommitHash = await vcsClient.getCommitHashAsync();
const isGitWorkingTreeDirty = await vcsClient.hasUncommittedChangesAsync(); const isGitWorkingTreeDirty = await vcsClient.hasUncommittedChangesAsync();
const runtimeVersions = await getRuntimeVersionObjectAsync( const workflows = await resolveWorkflowPerPlatformAsync(projectDir, vcsClient);
const runtimeVersions = await getRuntimeVersionObjectAsync({
exp, exp,
realizedPlatforms, platforms: realizedPlatforms,
projectDir, projectDir,
vcsClient workflows: {
); ...workflows,
web: Workflow.UNKNOWN,
},
env: undefined,
});
let newUpdates: UpdatePublishMutation['updateBranch']['publishUpdateGroups']; let newUpdates: UpdatePublishMutation['updateBranch']['publishUpdateGroups'];
const publishSpinner = ora('Publishing...').start(); const publishSpinner = ora('Publishing...').start();
@@ -279,7 +276,7 @@ export default class UpdateRollBackToEmbedded extends EasCommand {
}, },
] ]
: []), : []),
{ label: 'Website link', value: updateGroupLink }, { label: 'EAS Dashboard', value: updateGroupLink },
]) ])
); );
Log.addNewLineIfNone(); Log.addNewLineIfNone();
@@ -10,7 +10,7 @@ export default class UpdateRollback extends EasCommand {
static override flags = { static override flags = {
'private-key-path': Flags.string({ 'private-key-path': Flags.string({
description: `File containing the PEM-encoded private key corresponding to the certificate in expo-updates' configuration. Defaults to a file named "private-key.pem" in the certificate's directory.`, description: `File containing the PEM-encoded private key corresponding to the certificate in expo-updates' configuration. Defaults to a file named "private-key.pem" in the certificate's directory. Only relevant if you are using code signing: https://docs.expo.dev/eas-update/code-signing/`,
required: false, required: false,
}), }),
}; };
@@ -55,6 +55,7 @@ export const testPKCS12EmptyPasswordKeystore: Keystore = {
export const testAppFragment: AppFragment = { export const testAppFragment: AppFragment = {
id: 'test-app-id', id: 'test-app-id',
fullName: '@testuser/testapp', fullName: '@testuser/testapp',
name: 'testapp',
slug: 'testapp', slug: 'testapp',
ownerAccount: { ownerAccount: {
id: 'test-account-id', id: 'test-account-id',
@@ -1,5 +1,5 @@
import AppStoreApi from '../ios/appstore/AppStoreApi'; import AppStoreApi from '../ios/appstore/AppStoreApi';
import { AuthCtx } from '../ios/appstore/authenticateTypes'; import { AuthCtx, AuthenticationMode } from '../ios/appstore/authenticateTypes';
export const testAuthCtx: AuthCtx = { export const testAuthCtx: AuthCtx = {
appleId: 'test-apple-id', appleId: 'test-apple-id',
@@ -9,6 +9,7 @@ export const testAuthCtx: AuthCtx = {
export function getAppstoreMock(): AppStoreApi { export function getAppstoreMock(): AppStoreApi {
return { return {
defaultAuthenticationMode: AuthenticationMode.USER,
ensureAuthenticatedAsync: jest.fn(), ensureAuthenticatedAsync: jest.fn(),
ensureBundleIdExistsAsync: jest.fn(), ensureBundleIdExistsAsync: jest.fn(),
listDistributionCertificatesAsync: jest.fn(), listDistributionCertificatesAsync: jest.fn(),
@@ -1,3 +1,5 @@
import assert from 'node:assert';
import { AppFragment, Role } from '../../graphql/generated'; import { AppFragment, Role } from '../../graphql/generated';
import { Actor } from '../../user/User'; import { Actor } from '../../user/User';
@@ -24,6 +26,7 @@ export const jester: Actor = {
], ],
isExpoAdmin: false, isExpoAdmin: false,
featureGates: {}, featureGates: {},
preferences: {},
}; };
export const jester2 = { export const jester2 = {
@@ -41,6 +44,7 @@ export const jester2 = {
featureGates: {}, featureGates: {},
}; };
assert(jester.__typename === 'User');
export const testUsername = jester.username; export const testUsername = jester.username;
export const testSlug = 'testApp'; export const testSlug = 'testApp';
export const testProjectId = '7ef93448-3bc7-4b57-be32-99326dcf24f0'; export const testProjectId = '7ef93448-3bc7-4b57-be32-99326dcf24f0';
@@ -76,6 +80,7 @@ export const testAppJsonWithDifferentOwner = {
export const testAppQueryByIdResponse: AppFragment = { export const testAppQueryByIdResponse: AppFragment = {
id: testProjectId, id: testProjectId,
slug: testSlug, slug: testSlug,
name: 'testing 123',
fullName: testExperienceName, fullName: testExperienceName,
ownerAccount: jester.accounts[0], ownerAccount: jester.accounts[0],
}; };
@@ -55,6 +55,7 @@ export const testAppleAppIdentifierFragment: AppleAppIdentifierFragment = {
export const testAppFragment: AppFragment = { export const testAppFragment: AppFragment = {
id: 'test-app-id', id: 'test-app-id',
fullName: '@testuser/testapp', fullName: '@testuser/testapp',
name: 'testapp',
slug: 'testapp', slug: 'testapp',
ownerAccount: { ownerAccount: {
id: 'test-account-id', id: 'test-account-id',
@@ -0,0 +1,33 @@
import {
CommonAndroidAppCredentialsFragment,
GoogleServiceAccountKeyFragment,
} from '../../../graphql/generated';
import Log from '../../../log';
import { CredentialsContext } from '../../context';
import { AppLookupParams } from '../api/GraphqlClient';
export class AssignGoogleServiceAccountKeyForFcmV1 {
constructor(private app: AppLookupParams) {}
public async runAsync(
ctx: CredentialsContext,
googleServiceAccountKey: GoogleServiceAccountKeyFragment
): Promise<CommonAndroidAppCredentialsFragment> {
const appCredentials =
await ctx.android.createOrGetExistingAndroidAppCredentialsWithBuildCredentialsAsync(
ctx.graphqlClient,
this.app
);
const updatedAppCredentials = await ctx.android.updateAndroidAppCredentialsAsync(
ctx.graphqlClient,
appCredentials,
{
googleServiceAccountKeyForFcmV1Id: googleServiceAccountKey.id,
}
);
Log.succeed(
`Google Service Account Key assigned to ${this.app.androidApplicationIdentifier} for FCM V1`
);
return updatedAppCredentials;
}
}
@@ -6,7 +6,7 @@ import Log from '../../../log';
import { CredentialsContext } from '../../context'; import { CredentialsContext } from '../../context';
import { AppLookupParams } from '../api/GraphqlClient'; import { AppLookupParams } from '../api/GraphqlClient';
export class AssignGoogleServiceAccountKey { export class AssignGoogleServiceAccountKeyForSubmissions {
constructor(private app: AppLookupParams) {} constructor(private app: AppLookupParams) {}
public async runAsync( public async runAsync(
@@ -46,7 +46,7 @@ export class CreateGoogleServiceAccountKey {
Log.log( Log.log(
`${chalk.bold( `${chalk.bold(
'A Google Service Account JSON key is required to upload your app to Google Play Store' 'A Google Service Account JSON key is required for uploading your app to Google Play Store, and for sending Android Notifications via FCM V1.'
)}.\n` + )}.\n` +
`If you're not sure what this is or how to create one, ${learnMore( `If you're not sure what this is or how to create one, ${learnMore(
'https://expo.fyi/creating-google-service-account', 'https://expo.fyi/creating-google-service-account',
@@ -0,0 +1,87 @@
import nullthrows from 'nullthrows';
import { AssignGoogleServiceAccountKeyForFcmV1 } from './AssignGoogleServiceAccountKeyForFcmV1';
import { CreateGoogleServiceAccountKey } from './CreateGoogleServiceAccountKey';
import { UseExistingGoogleServiceAccountKey } from './UseExistingGoogleServiceAccountKey';
import {
CommonAndroidAppCredentialsFragment,
GoogleServiceAccountKeyFragment,
} from '../../../graphql/generated';
import Log from '../../../log';
import { promptAsync } from '../../../prompts';
import { CredentialsContext } from '../../context';
import { MissingCredentialsNonInteractiveError } from '../../errors';
import { AppLookupParams } from '../api/GraphqlClient';
export class SetUpGoogleServiceAccountKeyForFcmV1 {
constructor(private app: AppLookupParams) {}
public async runAsync(ctx: CredentialsContext): Promise<CommonAndroidAppCredentialsFragment> {
const isKeySetup = await this.isGoogleServiceAccountKeySetupAsync(ctx);
if (isKeySetup) {
Log.succeed('Google Service Account Key for FCM V1 already set up.');
return nullthrows(
await ctx.android.getAndroidAppCredentialsWithCommonFieldsAsync(
ctx.graphqlClient,
this.app
),
'androidAppCredentials cannot be null if google service account key is already set up'
);
}
if (ctx.nonInteractive) {
throw new MissingCredentialsNonInteractiveError(
'Google Service Account Keys cannot be set up in --non-interactive mode.'
);
}
const keysForAccount = await ctx.android.getGoogleServiceAccountKeysForAccountAsync(
ctx.graphqlClient,
this.app.account
);
let googleServiceAccountKey = null;
if (keysForAccount.length === 0) {
googleServiceAccountKey = await new CreateGoogleServiceAccountKey(this.app.account).runAsync(
ctx
);
} else {
googleServiceAccountKey = await this.createOrUseExistingKeyAsync(ctx);
}
return await new AssignGoogleServiceAccountKeyForFcmV1(this.app).runAsync(
ctx,
googleServiceAccountKey
);
}
private async isGoogleServiceAccountKeySetupAsync(ctx: CredentialsContext): Promise<boolean> {
const appCredentials = await ctx.android.getAndroidAppCredentialsWithCommonFieldsAsync(
ctx.graphqlClient,
this.app
);
return !!appCredentials?.googleServiceAccountKeyForFcmV1;
}
private async createOrUseExistingKeyAsync(
ctx: CredentialsContext
): Promise<GoogleServiceAccountKeyFragment> {
const { action } = await promptAsync({
type: 'select',
name: 'action',
message: 'Select the Google Service Account Key to use for FCM V1:',
choices: [
{
title: '[Choose an existing key]',
value: 'CHOOSE_EXISTING',
},
{ title: '[Upload a new service account key]', value: 'GENERATE' },
],
});
if (action === 'GENERATE') {
return await new CreateGoogleServiceAccountKey(this.app.account).runAsync(ctx);
}
return (
(await new UseExistingGoogleServiceAccountKey(this.app.account).runAsync(ctx)) ??
(await this.createOrUseExistingKeyAsync(ctx))
);
}
}
@@ -1,6 +1,6 @@
import nullthrows from 'nullthrows'; import nullthrows from 'nullthrows';
import { AssignGoogleServiceAccountKey } from './AssignGoogleServiceAccountKey'; import { AssignGoogleServiceAccountKeyForSubmissions } from './AssignGoogleServiceAccountKeyForSubmissions';
import { CreateGoogleServiceAccountKey } from './CreateGoogleServiceAccountKey'; import { CreateGoogleServiceAccountKey } from './CreateGoogleServiceAccountKey';
import { UseExistingGoogleServiceAccountKey } from './UseExistingGoogleServiceAccountKey'; import { UseExistingGoogleServiceAccountKey } from './UseExistingGoogleServiceAccountKey';
import { import {
@@ -13,7 +13,7 @@ import { CredentialsContext } from '../../context';
import { MissingCredentialsNonInteractiveError } from '../../errors'; import { MissingCredentialsNonInteractiveError } from '../../errors';
import { AppLookupParams } from '../api/GraphqlClient'; import { AppLookupParams } from '../api/GraphqlClient';
export class SetUpGoogleServiceAccountKey { export class SetUpGoogleServiceAccountKeyForSubmissions {
constructor(private app: AppLookupParams) {} constructor(private app: AppLookupParams) {}
public async runAsync(ctx: CredentialsContext): Promise<CommonAndroidAppCredentialsFragment> { public async runAsync(ctx: CredentialsContext): Promise<CommonAndroidAppCredentialsFragment> {
@@ -46,7 +46,10 @@ export class SetUpGoogleServiceAccountKey {
} else { } else {
googleServiceAccountKey = await this.createOrUseExistingKeyAsync(ctx); googleServiceAccountKey = await this.createOrUseExistingKeyAsync(ctx);
} }
return await new AssignGoogleServiceAccountKey(this.app).runAsync(ctx, googleServiceAccountKey); return await new AssignGoogleServiceAccountKeyForSubmissions(this.app).runAsync(
ctx,
googleServiceAccountKey
);
} }
private async isGoogleServiceAccountKeySetupAsync(ctx: CredentialsContext): Promise<boolean> { private async isGoogleServiceAccountKeySetupAsync(ctx: CredentialsContext): Promise<boolean> {
@@ -2,12 +2,12 @@ import { AppQuery } from '../../../../graphql/queries/AppQuery';
import { testGoogleServiceAccountKeyFragment } from '../../../__tests__/fixtures-android'; import { testGoogleServiceAccountKeyFragment } from '../../../__tests__/fixtures-android';
import { testAppQueryByIdResponse } from '../../../__tests__/fixtures-constants'; import { testAppQueryByIdResponse } from '../../../__tests__/fixtures-constants';
import { createCtxMock } from '../../../__tests__/fixtures-context'; import { createCtxMock } from '../../../__tests__/fixtures-context';
import { AssignGoogleServiceAccountKey } from '../AssignGoogleServiceAccountKey'; import { AssignGoogleServiceAccountKeyForSubmissions } from '../AssignGoogleServiceAccountKeyForSubmissions';
import { getAppLookupParamsFromContextAsync } from '../BuildCredentialsUtils'; import { getAppLookupParamsFromContextAsync } from '../BuildCredentialsUtils';
jest.mock('../../../../graphql/queries/AppQuery'); jest.mock('../../../../graphql/queries/AppQuery');
describe(AssignGoogleServiceAccountKey, () => { describe(AssignGoogleServiceAccountKeyForSubmissions, () => {
beforeEach(() => { beforeEach(() => {
jest.mocked(AppQuery.byIdAsync).mockResolvedValue(testAppQueryByIdResponse); jest.mocked(AppQuery.byIdAsync).mockResolvedValue(testAppQueryByIdResponse);
}); });
@@ -16,7 +16,9 @@ describe(AssignGoogleServiceAccountKey, () => {
nonInteractive: false, nonInteractive: false,
}); });
const appLookupParams = await getAppLookupParamsFromContextAsync(ctx); const appLookupParams = await getAppLookupParamsFromContextAsync(ctx);
const assignGoogleServiceAccountKeyAction = new AssignGoogleServiceAccountKey(appLookupParams); const assignGoogleServiceAccountKeyAction = new AssignGoogleServiceAccountKeyForSubmissions(
appLookupParams
);
await assignGoogleServiceAccountKeyAction.runAsync(ctx, testGoogleServiceAccountKeyFragment); await assignGoogleServiceAccountKeyAction.runAsync(ctx, testGoogleServiceAccountKeyFragment);
// expect app credentials to be fetched/created, then updated // expect app credentials to be fetched/created, then updated
@@ -30,7 +32,9 @@ describe(AssignGoogleServiceAccountKey, () => {
nonInteractive: true, nonInteractive: true,
}); });
const appLookupParams = await getAppLookupParamsFromContextAsync(ctx); const appLookupParams = await getAppLookupParamsFromContextAsync(ctx);
const assignGoogleServiceAccountKeyAction = new AssignGoogleServiceAccountKey(appLookupParams); const assignGoogleServiceAccountKeyAction = new AssignGoogleServiceAccountKeyForSubmissions(
appLookupParams
);
// dont fail if users are running in non-interactive mode // dont fail if users are running in non-interactive mode
await expect( await expect(
@@ -11,7 +11,7 @@ import { testAppQueryByIdResponse } from '../../../__tests__/fixtures-constants'
import { createCtxMock } from '../../../__tests__/fixtures-context'; import { createCtxMock } from '../../../__tests__/fixtures-context';
import { MissingCredentialsNonInteractiveError } from '../../../errors'; import { MissingCredentialsNonInteractiveError } from '../../../errors';
import { getAppLookupParamsFromContextAsync } from '../BuildCredentialsUtils'; import { getAppLookupParamsFromContextAsync } from '../BuildCredentialsUtils';
import { SetUpGoogleServiceAccountKey } from '../SetUpGoogleServiceAccountKey'; import { SetUpGoogleServiceAccountKeyForSubmissions } from '../SetUpGoogleServiceAccountKeyForSubmissions';
jest.mock('../../../../prompts'); jest.mock('../../../../prompts');
jest.mock('fs'); jest.mock('fs');
@@ -24,7 +24,7 @@ beforeEach(() => {
vol.reset(); vol.reset();
}); });
describe(SetUpGoogleServiceAccountKey, () => { describe(SetUpGoogleServiceAccountKeyForSubmissions, () => {
beforeEach(() => { beforeEach(() => {
jest.mocked(AppQuery.byIdAsync).mockResolvedValue(testAppQueryByIdResponse); jest.mocked(AppQuery.byIdAsync).mockResolvedValue(testAppQueryByIdResponse);
}); });
@@ -39,7 +39,9 @@ describe(SetUpGoogleServiceAccountKey, () => {
}, },
}); });
const appLookupParams = await getAppLookupParamsFromContextAsync(ctx); const appLookupParams = await getAppLookupParamsFromContextAsync(ctx);
const setupGoogleServiceAccountKeyAction = new SetUpGoogleServiceAccountKey(appLookupParams); const setupGoogleServiceAccountKeyAction = new SetUpGoogleServiceAccountKeyForSubmissions(
appLookupParams
);
await setupGoogleServiceAccountKeyAction.runAsync(ctx); await setupGoogleServiceAccountKeyAction.runAsync(ctx);
expect(ctx.android.createGoogleServiceAccountKeyAsync).not.toHaveBeenCalled(); expect(ctx.android.createGoogleServiceAccountKeyAsync).not.toHaveBeenCalled();
@@ -62,7 +64,9 @@ describe(SetUpGoogleServiceAccountKey, () => {
}, },
}); });
const appLookupParams = await getAppLookupParamsFromContextAsync(ctx); const appLookupParams = await getAppLookupParamsFromContextAsync(ctx);
const setupGoogleServiceAccountKeyAction = new SetUpGoogleServiceAccountKey(appLookupParams); const setupGoogleServiceAccountKeyAction = new SetUpGoogleServiceAccountKeyForSubmissions(
appLookupParams
);
await setupGoogleServiceAccountKeyAction.runAsync(ctx); await setupGoogleServiceAccountKeyAction.runAsync(ctx);
expect(ctx.android.createGoogleServiceAccountKeyAsync).toHaveBeenCalledTimes(1); expect(ctx.android.createGoogleServiceAccountKeyAsync).toHaveBeenCalledTimes(1);
@@ -73,7 +77,9 @@ describe(SetUpGoogleServiceAccountKey, () => {
nonInteractive: true, nonInteractive: true,
}); });
const appLookupParams = await getAppLookupParamsFromContextAsync(ctx); const appLookupParams = await getAppLookupParamsFromContextAsync(ctx);
const setupGoogleServiceAccountKeyAction = new SetUpGoogleServiceAccountKey(appLookupParams); const setupGoogleServiceAccountKeyAction = new SetUpGoogleServiceAccountKeyForSubmissions(
appLookupParams
);
await expect(setupGoogleServiceAccountKeyAction.runAsync(ctx)).rejects.toThrowError( await expect(setupGoogleServiceAccountKeyAction.runAsync(ctx)).rejects.toThrowError(
MissingCredentialsNonInteractiveError MissingCredentialsNonInteractiveError
); );
@@ -106,9 +106,11 @@ export async function updateAndroidAppCredentialsAsync(
{ {
androidFcmId, androidFcmId,
googleServiceAccountKeyForSubmissionsId, googleServiceAccountKeyForSubmissionsId,
googleServiceAccountKeyForFcmV1Id,
}: { }: {
androidFcmId?: string; androidFcmId?: string;
googleServiceAccountKeyForSubmissionsId?: string; googleServiceAccountKeyForSubmissionsId?: string;
googleServiceAccountKeyForFcmV1Id?: string;
} }
): Promise<CommonAndroidAppCredentialsFragment> { ): Promise<CommonAndroidAppCredentialsFragment> {
let updatedAppCredentials = appCredentials; let updatedAppCredentials = appCredentials;
@@ -127,6 +129,14 @@ export async function updateAndroidAppCredentialsAsync(
googleServiceAccountKeyForSubmissionsId googleServiceAccountKeyForSubmissionsId
); );
} }
if (googleServiceAccountKeyForFcmV1Id) {
updatedAppCredentials =
await AndroidAppCredentialsMutation.setGoogleServiceAccountKeyForFcmV1Async(
graphqlClient,
appCredentials.id,
googleServiceAccountKeyForFcmV1Id
);
}
return updatedAppCredentials; return updatedAppCredentials;
} }
@@ -8,6 +8,7 @@ import {
CommonAndroidAppCredentialsFragment, CommonAndroidAppCredentialsFragment,
CreateAndroidAppCredentialsMutation, CreateAndroidAppCredentialsMutation,
SetFcmMutation, SetFcmMutation,
SetGoogleServiceAccountKeyForFcmV1Mutation,
SetGoogleServiceAccountKeyForSubmissionsMutation, SetGoogleServiceAccountKeyForSubmissionsMutation,
} from '../../../../../graphql/generated'; } from '../../../../../graphql/generated';
import { CommonAndroidAppCredentialsFragmentNode } from '../../../../../graphql/types/credentials/AndroidAppCredentials'; import { CommonAndroidAppCredentialsFragmentNode } from '../../../../../graphql/types/credentials/AndroidAppCredentials';
@@ -124,4 +125,42 @@ export const AndroidAppCredentialsMutation = {
); );
return data.androidAppCredentials.setGoogleServiceAccountKeyForSubmissions; return data.androidAppCredentials.setGoogleServiceAccountKeyForSubmissions;
}, },
async setGoogleServiceAccountKeyForFcmV1Async(
graphqlClient: ExpoGraphqlClient,
androidAppCredentialsId: string,
googleServiceAccountKeyId: string
): Promise<CommonAndroidAppCredentialsFragment> {
const data = await withErrorHandlingAsync(
graphqlClient
.mutation<SetGoogleServiceAccountKeyForFcmV1Mutation>(
gql`
mutation SetGoogleServiceAccountKeyForFcmV1Mutation(
$androidAppCredentialsId: ID!
$googleServiceAccountKeyId: ID!
) {
androidAppCredentials {
setGoogleServiceAccountKeyForFcmV1(
id: $androidAppCredentialsId
googleServiceAccountKeyId: $googleServiceAccountKeyId
) {
id
...CommonAndroidAppCredentialsFragment
}
}
}
${print(CommonAndroidAppCredentialsFragmentNode)}
`,
{
androidAppCredentialsId,
googleServiceAccountKeyId,
}
)
.toPromise()
);
assert(
data.androidAppCredentials.setGoogleServiceAccountKeyForFcmV1,
'GraphQL: `setGoogleServiceAccountKeyForFcmV1` not defined in server response'
);
return data.androidAppCredentials.setGoogleServiceAccountKeyForFcmV1;
},
}; };
@@ -4,35 +4,88 @@ import gql from 'graphql-tag';
import { ExpoGraphqlClient } from '../../../../../commandUtils/context/contextUtils/createGraphqlClient'; import { ExpoGraphqlClient } from '../../../../../commandUtils/context/contextUtils/createGraphqlClient';
import { withErrorHandlingAsync } from '../../../../../graphql/client'; import { withErrorHandlingAsync } from '../../../../../graphql/client';
import { import {
GoogleServiceAccountKeyByAccountQuery,
GoogleServiceAccountKeyFragment, GoogleServiceAccountKeyFragment,
GoogleServiceAccountKeysPaginatedByAccountQuery,
} from '../../../../../graphql/generated'; } from '../../../../../graphql/generated';
import { GoogleServiceAccountKeyFragmentNode } from '../../../../../graphql/types/credentials/GoogleServiceAccountKey'; import { GoogleServiceAccountKeyFragmentNode } from '../../../../../graphql/types/credentials/GoogleServiceAccountKey';
import { Connection, QueryParams, fetchEntireDatasetAsync } from '../../../../../utils/relay';
export const GoogleServiceAccountKeyQuery = { export const GoogleServiceAccountKeyQuery = {
async getAllForAccountAsync( async getAllForAccountAsync(
graphqlClient: ExpoGraphqlClient, graphqlClient: ExpoGraphqlClient,
accountName: string accountName: string
): Promise<GoogleServiceAccountKeyFragment[]> { ): Promise<GoogleServiceAccountKeyFragment[]> {
const paginatedGetterAsync = async (
relayArgs: QueryParams
): Promise<Connection<GoogleServiceAccountKeyFragment>> => {
return await GoogleServiceAccountKeyQuery.getAllForAccountPaginatedAsync(
graphqlClient,
accountName,
relayArgs
);
};
return await fetchEntireDatasetAsync({
paginatedGetterAsync,
progressBarLabel: 'fetching Google Service Account Keys...',
});
},
async getAllForAccountPaginatedAsync(
graphqlClient: ExpoGraphqlClient,
accountName: string,
{
after,
first,
before,
last,
}: { after?: string; first?: number; before?: string; last?: number }
): Promise<
GoogleServiceAccountKeysPaginatedByAccountQuery['account']['byName']['googleServiceAccountKeysPaginated']
> {
const data = await withErrorHandlingAsync( const data = await withErrorHandlingAsync(
graphqlClient graphqlClient
.query<GoogleServiceAccountKeyByAccountQuery>( .query<GoogleServiceAccountKeysPaginatedByAccountQuery>(
gql` gql`
query GoogleServiceAccountKeyByAccountQuery($accountName: String!) { query GoogleServiceAccountKeysPaginatedByAccountQuery(
$accountName: String!
$after: String
$first: Int
$before: String
$last: Int
) {
account { account {
byName(accountName: $accountName) { byName(accountName: $accountName) {
id id
googleServiceAccountKeys { googleServiceAccountKeysPaginated(
after: $after
first: $first
before: $before
last: $last
) {
edges {
cursor
node {
id id
...GoogleServiceAccountKeyFragment ...GoogleServiceAccountKeyFragment
} }
} }
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
}
}
} }
} }
${print(GoogleServiceAccountKeyFragmentNode)} ${print(GoogleServiceAccountKeyFragmentNode)}
`, `,
{ {
accountName, accountName,
after,
first,
before,
last,
}, },
{ {
additionalTypenames: ['GoogleServiceAccountKey'], additionalTypenames: ['GoogleServiceAccountKey'],
@@ -40,6 +93,6 @@ export const GoogleServiceAccountKeyQuery = {
) )
.toPromise() .toPromise()
); );
return data.account.byName.googleServiceAccountKeys; return data.account.byName.googleServiceAccountKeysPaginated;
}, },
}; };
@@ -3,8 +3,8 @@
exports[`print credentials prints the AndroidAppCredentials fragment 1`] = ` exports[`print credentials prints the AndroidAppCredentials fragment 1`] = `
"Android Credentials "Android Credentials
Project testApp Project testApp
Application Identifier test.com.appPush Notifications (FCM) Key abcd...efgh Application Identifier test.com.appPush Notifications (FCM Legacy) Key abcd...efgh
Updated 0 second agoGoogle Service Account Key For Submissions Project ID sdf.sdf.sdf Updated 0 second agoPush Notifications (FCM V1): Google Service Account Key For FCM V1 None assigned yetSubmissions: Google Service Account Key for Play Store Submissions Project ID sdf.sdf.sdf
Client Email [email protected] Client Email [email protected]
Client ID test-client-identifier Client ID test-client-identifier
Private Key ID test-private-key-identifier Private Key ID test-private-key-identifier
@@ -13,7 +13,11 @@ import { getAppLookupParamsFromContextAsync } from '../../actions/BuildCredentia
import { displayAndroidAppCredentials } from '../printCredentials'; import { displayAndroidAppCredentials } from '../printCredentials';
jest.mock('../../../../log'); jest.mock('../../../../log');
jest.mock('chalk', () => ({ bold: jest.fn(log => log), cyan: { bold: jest.fn(log => log) } })); jest.mock('chalk', () => ({
bold: jest.fn(log => log),
cyan: { bold: jest.fn(log => log) },
dim: jest.fn(log => log),
}));
jest.mock('../../../../graphql/queries/AppQuery'); jest.mock('../../../../graphql/queries/AppQuery');
mockdate.set(testLegacyAndroidFcmFragment.updatedAt); mockdate.set(testLegacyAndroidFcmFragment.updatedAt);
@@ -96,7 +96,7 @@ export async function detectGoogleServiceAccountKeyPathAsync(
): Promise<string | null> { ): Promise<string | null> {
const foundFilePaths = await glob('**/*.json', { const foundFilePaths = await glob('**/*.json', {
cwd: projectDir, cwd: projectDir,
ignore: ['app.json', 'package*.json', 'tsconfig.json', 'node_modules'], ignore: ['app.json', 'package*.json', 'tsconfig.json', 'node_modules', 'google-services.json'],
}); });
const googleServiceFiles = foundFilePaths const googleServiceFiles = foundFilePaths
@@ -29,7 +29,7 @@ export function displayEmptyAndroidCredentials(appLookupParams: AppLookupParams)
function displayAndroidFcmCredentials(appCredentials: CommonAndroidAppCredentialsFragment): void { function displayAndroidFcmCredentials(appCredentials: CommonAndroidAppCredentialsFragment): void {
const maybeFcm = appCredentials.androidFcm; const maybeFcm = appCredentials.androidFcm;
Log.log( Log.log(
formatFields([{ label: 'Push Notifications (FCM)', value: '' }], { formatFields([{ label: 'Push Notifications (FCM Legacy)', value: '' }], {
labelFormat: chalk.cyan.bold, labelFormat: chalk.cyan.bold,
}) })
); );
@@ -60,9 +60,43 @@ function displayGoogleServiceAccountKeyForSubmissions(
): void { ): void {
const maybeGsaKey = appCredentials.googleServiceAccountKeyForSubmissions; const maybeGsaKey = appCredentials.googleServiceAccountKeyForSubmissions;
Log.log( Log.log(
formatFields([{ label: 'Google Service Account Key For Submissions', value: '' }], { formatFields(
[{ label: 'Submissions: Google Service Account Key for Play Store Submissions', value: '' }],
{
labelFormat: chalk.cyan.bold, labelFormat: chalk.cyan.bold,
}) }
)
);
if (!maybeGsaKey) {
Log.log(formatFields([{ label: '', value: 'None assigned yet' }]));
Log.newLine();
return;
}
const { projectIdentifier, privateKeyIdentifier, clientEmail, clientIdentifier, updatedAt } =
maybeGsaKey;
const fields = [
{ label: 'Project ID', value: projectIdentifier },
{ label: 'Client Email', value: clientEmail },
{ label: 'Client ID', value: clientIdentifier },
{ label: 'Private Key ID', value: privateKeyIdentifier },
{ label: 'Updated', value: `${fromNow(new Date(updatedAt))} ago` },
];
Log.log(formatFields(fields, { labelFormat: chalk.cyan.bold }));
Log.newLine();
}
function displayGoogleServiceAccountKeyForFcmV1(
appCredentials: CommonAndroidAppCredentialsFragment
): void {
const maybeGsaKey = appCredentials.googleServiceAccountKeyForFcmV1;
Log.log(
formatFields(
[{ label: 'Push Notifications (FCM V1): Google Service Account Key For FCM V1', value: '' }],
{
labelFormat: chalk.cyan.bold,
}
)
); );
if (!maybeGsaKey) { if (!maybeGsaKey) {
Log.log(formatFields([{ label: '', value: 'None assigned yet' }])); Log.log(formatFields([{ label: '', value: 'None assigned yet' }]));
@@ -87,6 +121,7 @@ function displayEASAndroidAppCredentials(
appCredentials: CommonAndroidAppCredentialsFragment appCredentials: CommonAndroidAppCredentialsFragment
): void { ): void {
displayAndroidFcmCredentials(appCredentials); displayAndroidFcmCredentials(appCredentials);
displayGoogleServiceAccountKeyForFcmV1(appCredentials);
displayGoogleServiceAccountKeyForSubmissions(appCredentials); displayGoogleServiceAccountKeyForSubmissions(appCredentials);
const sortedBuildCredentialsList = sortBuildCredentials( const sortedBuildCredentialsList = sortBuildCredentials(
appCredentials.androidAppBuildCredentialsList appCredentials.androidAppBuildCredentialsList
@@ -25,6 +25,7 @@ export class CredentialsContext {
public readonly appStore = new AppStoreApi(); public readonly appStore = new AppStoreApi();
public readonly ios = IosGraphqlClient; public readonly ios = IosGraphqlClient;
public readonly nonInteractive: boolean; public readonly nonInteractive: boolean;
public readonly freezeCredentials: boolean = false;
public readonly projectDir: string; public readonly projectDir: string;
public readonly user: Actor; public readonly user: Actor;
public readonly graphqlClient: ExpoGraphqlClient; public readonly graphqlClient: ExpoGraphqlClient;
@@ -47,6 +48,7 @@ export class CredentialsContext {
graphqlClient: ExpoGraphqlClient; graphqlClient: ExpoGraphqlClient;
analytics: Analytics; analytics: Analytics;
vcsClient: Client; vcsClient: Client;
freezeCredentials?: boolean;
env?: Env; env?: Env;
} }
) { ) {
@@ -58,6 +60,7 @@ export class CredentialsContext {
this.vcsClient = options.vcsClient; this.vcsClient = options.vcsClient;
this.nonInteractive = options.nonInteractive ?? false; this.nonInteractive = options.nonInteractive ?? false;
this.projectInfo = options.projectInfo; this.projectInfo = options.projectInfo;
this.freezeCredentials = options.freezeCredentials ?? false;
} }
get hasProjectContext(): boolean { get hasProjectContext(): boolean {
@@ -1,9 +1,31 @@
import { learnMore } from '../log';
export class MissingCredentialsNonInteractiveError extends Error { export class MissingCredentialsNonInteractiveError extends Error {
constructor(message?: string) { constructor(message?: string) {
super(message ?? 'Credentials are not set up. Run this command again in interactive mode.'); super(message ?? 'Credentials are not set up. Run this command again in interactive mode.');
} }
} }
export class InsufficientAuthenticationNonInteractiveError extends Error {
constructor(message?: string) {
super(
message ??
`Authentication with an ASC API key is required in non-interactive mode. ${learnMore(
'https://docs.expo.dev/build/building-on-ci/#optional-provide-an-asc-api-token-for-your-apple-team'
)}`
);
}
}
export class ForbidCredentialModificationError extends Error {
constructor(message?: string) {
super(
message ??
'Credentials cannot be modified. Run this command again without the --freeze-credentials flag.'
);
}
}
export class MissingCredentialsError extends Error { export class MissingCredentialsError extends Error {
constructor(message?: string) { constructor(message?: string) {
super(message ?? 'Credentials are not set up.'); super(message ?? 'Credentials are not set up.');
@@ -14,6 +14,7 @@ import { isAdHocProfile, isEnterpriseUniversalProfile } from './utils/provisioni
import { CommonIosAppCredentialsFragment } from '../../graphql/generated'; import { CommonIosAppCredentialsFragment } from '../../graphql/generated';
import Log from '../../log'; import Log from '../../log';
import { findApplicationTarget } from '../../project/ios/target'; import { findApplicationTarget } from '../../project/ios/target';
import { isExpoNotificationsInstalled } from '../../project/projectUtils';
import { selectAsync } from '../../prompts'; import { selectAsync } from '../../prompts';
import { CredentialsContext } from '../context'; import { CredentialsContext } from '../context';
import * as credentialsJsonReader from '../credentialsJson/read'; import * as credentialsJsonReader from '../credentialsJson/read';
@@ -105,6 +106,11 @@ export default class IosCredentialsProvider {
if (ctx.easJsonCliConfig?.promptToConfigurePushNotifications === false) { if (ctx.easJsonCliConfig?.promptToConfigurePushNotifications === false) {
return null; return null;
} else if (
ctx.easJsonCliConfig?.promptToConfigurePushNotifications === undefined &&
!(await isExpoNotificationsInstalled(ctx.projectDir))
) {
return null;
} }
const setupOption = await selectAsync( const setupOption = await selectAsync(
@@ -5,15 +5,18 @@ import {
AppleDistributionCertificateFragment, AppleDistributionCertificateFragment,
AppleProvisioningProfileFragment, AppleProvisioningProfileFragment,
} from '../../../graphql/generated'; } from '../../../graphql/generated';
import Log from '../../../log'; import Log, { learnMore } from '../../../log';
import { ora } from '../../../ora'; import { ora } from '../../../ora';
import { getApplePlatformFromTarget } from '../../../project/ios/target'; import { getApplePlatformFromTarget } from '../../../project/ios/target';
import { CredentialsContext } from '../../context'; import { CredentialsContext } from '../../context';
import { MissingCredentialsNonInteractiveError } from '../../errors'; import {
ForbidCredentialModificationError,
InsufficientAuthenticationNonInteractiveError,
} from '../../errors';
import { AppleProvisioningProfileMutationResult } from '../api/graphql/mutations/AppleProvisioningProfileMutation'; import { AppleProvisioningProfileMutationResult } from '../api/graphql/mutations/AppleProvisioningProfileMutation';
import { AppLookupParams } from '../api/graphql/types/AppLookupParams'; import { AppLookupParams } from '../api/graphql/types/AppLookupParams';
import { ProvisioningProfileStoreInfo } from '../appstore/Credentials.types'; import { ProvisioningProfileStoreInfo } from '../appstore/Credentials.types';
import { AuthCtx } from '../appstore/authenticateTypes'; import { AuthCtx, AuthenticationMode } from '../appstore/authenticateTypes';
import { Target } from '../types'; import { Target } from '../types';
export class ConfigureProvisioningProfile { export class ConfigureProvisioningProfile {
@@ -27,9 +30,18 @@ export class ConfigureProvisioningProfile {
public async runAsync( public async runAsync(
ctx: CredentialsContext ctx: CredentialsContext
): Promise<AppleProvisioningProfileMutationResult | null> { ): Promise<AppleProvisioningProfileMutationResult | null> {
if (ctx.nonInteractive) { if (ctx.freezeCredentials) {
throw new MissingCredentialsNonInteractiveError( throw new ForbidCredentialModificationError(
'Configuring Provisioning Profiles is only supported in interactive mode.' 'Remove the --freeze-credentials flag to configure a Provisioning Profile.'
);
} else if (
ctx.nonInteractive &&
ctx.appStore.defaultAuthenticationMode !== AuthenticationMode.API_KEY
) {
throw new InsufficientAuthenticationNonInteractiveError(
`In order to configure your Provisioning Profile, authentication with an ASC API key is required in non-interactive mode. ${learnMore(
'https://docs.expo.dev/build/building-on-ci/#optional-provide-an-asc-api-token-for-your-apple-team'
)}`
); );
} }
const { developerPortalIdentifier, provisioningProfile } = this.originalProvisioningProfile; const { developerPortalIdentifier, provisioningProfile } = this.originalProvisioningProfile;
@@ -46,7 +58,7 @@ export class ConfigureProvisioningProfile {
return null; return null;
} }
const applePlatform = await getApplePlatformFromTarget(this.target); const applePlatform = getApplePlatformFromTarget(this.target);
const profilesFromApple = await ctx.appStore.listProvisioningProfilesAsync( const profilesFromApple = await ctx.appStore.listProvisioningProfilesAsync(
this.app.bundleIdentifier, this.app.bundleIdentifier,
applePlatform applePlatform
@@ -1,6 +1,5 @@
import { AppStoreApiKeyPurpose, provideOrGenerateAscApiKeyAsync } from './AscApiKeyUtils'; import { AppStoreApiKeyPurpose, provideOrGenerateAscApiKeyAsync } from './AscApiKeyUtils';
import { AccountFragment, AppStoreConnectApiKeyFragment } from '../../../graphql/generated'; import { AccountFragment, AppStoreConnectApiKeyFragment } from '../../../graphql/generated';
import Log from '../../../log';
import { CredentialsContext } from '../../context'; import { CredentialsContext } from '../../context';
export class CreateAscApiKey { export class CreateAscApiKey {
@@ -15,8 +14,6 @@ export class CreateAscApiKey {
} }
const ascApiKey = await provideOrGenerateAscApiKeyAsync(ctx, purpose); const ascApiKey = await provideOrGenerateAscApiKeyAsync(ctx, purpose);
const result = await ctx.ios.createAscApiKeyAsync(ctx.graphqlClient, this.account, ascApiKey); return await ctx.ios.createAscApiKeyAsync(ctx.graphqlClient, this.account, ascApiKey);
Log.succeed('Created App Store Connect API Key');
return result;
} }
} }
@@ -4,14 +4,17 @@ import nullthrows from 'nullthrows';
import { resolveAppleTeamIfAuthenticatedAsync } from './AppleTeamUtils'; import { resolveAppleTeamIfAuthenticatedAsync } from './AppleTeamUtils';
import { generateProvisioningProfileAsync } from './ProvisioningProfileUtils'; import { generateProvisioningProfileAsync } from './ProvisioningProfileUtils';
import { AppleDistributionCertificateFragment } from '../../../graphql/generated'; import { AppleDistributionCertificateFragment } from '../../../graphql/generated';
import Log from '../../../log'; import Log, { learnMore } from '../../../log';
import { CredentialsContext } from '../../context'; import { CredentialsContext } from '../../context';
import { MissingCredentialsNonInteractiveError } from '../../errors'; import {
ForbidCredentialModificationError,
InsufficientAuthenticationNonInteractiveError,
} from '../../errors';
import { askForUserProvidedAsync } from '../../utils/promptForCredentials'; import { askForUserProvidedAsync } from '../../utils/promptForCredentials';
import { AppleProvisioningProfileMutationResult } from '../api/graphql/mutations/AppleProvisioningProfileMutation'; import { AppleProvisioningProfileMutationResult } from '../api/graphql/mutations/AppleProvisioningProfileMutation';
import { AppLookupParams } from '../api/graphql/types/AppLookupParams'; import { AppLookupParams } from '../api/graphql/types/AppLookupParams';
import { ProvisioningProfile } from '../appstore/Credentials.types'; import { ProvisioningProfile } from '../appstore/Credentials.types';
import { AuthCtx } from '../appstore/authenticateTypes'; import { AuthCtx, AuthenticationMode } from '../appstore/authenticateTypes';
import { provisioningProfileSchema } from '../credentials'; import { provisioningProfileSchema } from '../credentials';
import { Target } from '../types'; import { Target } from '../types';
@@ -23,9 +26,18 @@ export class CreateProvisioningProfile {
) {} ) {}
async runAsync(ctx: CredentialsContext): Promise<AppleProvisioningProfileMutationResult> { async runAsync(ctx: CredentialsContext): Promise<AppleProvisioningProfileMutationResult> {
if (ctx.nonInteractive) { if (ctx.freezeCredentials) {
throw new MissingCredentialsNonInteractiveError( throw new ForbidCredentialModificationError(
'Creating Provisioning Profiles is only supported in interactive mode.' 'Run this command again without the --freeze-credentials flag in order to generate a new Provisioning Profile.'
);
} else if (
ctx.nonInteractive &&
ctx.appStore.defaultAuthenticationMode !== AuthenticationMode.API_KEY
) {
throw new InsufficientAuthenticationNonInteractiveError(
`In order to generate a new Provisioning Profile, authentication with an ASC API key is required in non-interactive mode. ${learnMore(
'https://docs.expo.dev/build/building-on-ci/#optional-provide-an-asc-api-token-for-your-apple-team'
)}`
); );
} }
const appleAuthCtx = await ctx.appStore.ensureAuthenticatedAsync(); const appleAuthCtx = await ctx.appStore.ensureAuthenticatedAsync();
@@ -49,16 +61,31 @@ export class CreateProvisioningProfile {
return provisioningProfileMutationResult; return provisioningProfileMutationResult;
} }
private async provideOrGenerateAsync( private async maybeGetUserProvidedAsync(
ctx: CredentialsContext, ctx: CredentialsContext
appleAuthCtx: AuthCtx ): Promise<ProvisioningProfile | null> {
): Promise<ProvisioningProfile> { if (ctx.nonInteractive) {
return null;
}
const userProvided = await askForUserProvidedAsync(provisioningProfileSchema); const userProvided = await askForUserProvidedAsync(provisioningProfileSchema);
if (userProvided) { if (userProvided) {
// userProvided profiles don't come with ProvisioningProfileId's (only accessible from Apple Portal API) // userProvided profiles don't come with ProvisioningProfileId's (only accessible from Apple Portal API)
Log.warn('Provisioning profile: Unable to validate specified profile.'); Log.warn('Provisioning profile: Unable to validate specified profile.');
return userProvided; return userProvided;
} }
return null;
}
private async provideOrGenerateAsync(
ctx: CredentialsContext,
appleAuthCtx: AuthCtx
): Promise<ProvisioningProfile> {
const maybeUserProvided = await this.maybeGetUserProvidedAsync(ctx);
if (maybeUserProvided) {
// userProvided profiles don't come with ProvisioningProfileId's (only accessible from Apple Portal API)
Log.warn('Provisioning profile: Unable to validate specified profile.');
return maybeUserProvided;
}
assert( assert(
this.distributionCertificate.certificateP12, this.distributionCertificate.certificateP12,
'Distribution Certificate must have p12 certificate' 'Distribution Certificate must have p12 certificate'
@@ -48,8 +48,13 @@ export function formatDistributionCertificate(
buildCredentials => buildCredentials.iosAppCredentials.app buildCredentials => buildCredentials.iosAppCredentials.app
); );
if (apps.length) { if (apps.length) {
const appFullNames = apps.map(app => app.fullName).join(','); // iosAppBuildCredentialsList is capped at 20 on www
line += chalk.gray(`\n 📲 Used by: ${appFullNames}`); const appFullNames = apps
.map(app => app.fullName)
.slice(0, 19)
.join(',');
const andMaybeMore = apps.length > 19 ? ' (and more)' : '';
line += chalk.gray(`\n 📲 Used by: ${appFullNames}${andMaybeMore}`);
} }
if (validSerialNumbers?.includes(serialNumber)) { if (validSerialNumbers?.includes(serialNumber)) {
@@ -254,6 +259,10 @@ function formatDistributionCertificateFromApple(
const { name, status, id, expires, created, ownerName, serialNumber } = appleInfo; const { name, status, id, expires, created, ownerName, serialNumber } = appleInfo;
const expiresDate = new Date(expires * 1000).toDateString(); const expiresDate = new Date(expires * 1000).toDateString();
const createdDate = new Date(created * 1000).toDateString(); const createdDate = new Date(created * 1000).toDateString();
return `${name} (${status}) - Cert ID: ${id}, Serial number: ${serialNumber}, Team ID: ${appleInfo.ownerId}, Team name: ${ownerName} return [
expires: ${expiresDate}, created: ${createdDate}`; `🍏 ${chalk.bold(name)} (${status})`,
`${chalk.bold('ID:')} ${id} ${chalk.bold('Serial Number:')} ${serialNumber}`,
`${chalk.bold('Apple Team:')} ${appleInfo.ownerId} (${ownerName})`,
`${chalk.bold('Expires:')} ${expiresDate} ${chalk.bold('Created:')} ${createdDate}`,
].join('\n\t');
} }
@@ -185,8 +185,13 @@ export function formatPushKey(
const apps = pushKey.iosAppCredentialsList.map(appCredentials => appCredentials.app); const apps = pushKey.iosAppCredentialsList.map(appCredentials => appCredentials.app);
if (apps.length) { if (apps.length) {
const appFullNames = apps.map(app => app.fullName).join(','); // iosAppCredentialsList is capped at 20 on www
line += chalk.gray(`\n 📲 Used by: ${appFullNames}`); const appFullNames = apps
.map(app => app.fullName)
.slice(0, 19)
.join(',');
const andMaybeMore = apps.length > 19 ? ' (and more)' : '';
line += chalk.gray(`\n 📲 Used by: ${appFullNames}${andMaybeMore}`);
} }
if (validPushKeyIdentifiers?.includes(keyIdentifier)) { if (validPushKeyIdentifiers?.includes(keyIdentifier)) {
Loaded 100 of 197 files, more files were not shown because too many files have changed in this diff. Show more