Compare commits

..
Author SHA1 Message Date
Szymon Dziedzic a2219beaba v12.2.0 2024-09-09 17:25:30 +02:00
90a2612792 Added --non-interactive and --force support when --id is not passed to eas init command (#1983)
* Added --non-interactive and --force support when --id is not passed to eas init command

* Removed id dependency from init command flags

* Bump undici from 5.19.1 to 5.26.3

Bumps [undici](https://github.com/nodejs/undici) from 5.19.1 to 5.26.3.
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v5.19.1...v5.26.3)

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

Signed-off-by: dependabot[bot] <[email protected]>

* Revert "Bump undici from 5.19.1 to 5.26.3"

* Apply suggestions from code review

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

* Fixed initializeWithoutExplicitIDAsync not being used

* Require force flag to use default account when no account name is specified in non-interactive mode

* Changed error message when user has access to multiple accounts in non-interactive mode

* Added changelog entry

* Update CHANGELOG.md

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

---------

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ryan Button <[email protected]>
Co-authored-by: Szymon Dziedzic <[email protected]>
2024-09-09 17:23:53 +02:00
Expo CI d94b57c1b7 update CHANGELOG.md 2024-09-09 15:01:14 +00:00
Szymon Dziedzic d63fc1f01e v12.1.1 2024-09-09 16:54:42 +02:00
Szymon Dziedzic 57e7481a68 fix changelog 2024-09-09 16:54:21 +02:00
HarrisandHarris Han 7bb18e2489 [eas-cli] Fix entitlements resolution for multiple iOS targets (#2532)
* [fix]: correctly retrieve entitlements for extensions using their own target name

Fixed an issue where extensions were incorrectly retrieving the main app's entitlements instead of their own. Updated the code to use `dependency.name` for fetching the correct entitlements.

* update CHANGELOG.md

---------

Co-authored-by: Harris Han <[email protected]>
2024-09-09 16:50:08 +02:00
Expo CI 359464d55c update CHANGELOG.md 2024-09-06 13:13:04 +00:00
Phil Pluckthun e993e9a370 v12.1.0 2024-09-06 14:07:33 +01:00
75046b0b35 feat(eas-cli): Implement initial worker:deploy command (#2447)
* Update generated schema

* Add initial structure for worker code

* Add generated types to mutation

* Add initial command implementation

* Fix linting

* [ENG-12738] prompt for dev domain name (#2452)

* Add a dist folder check

* Prompt adding dev domain name on the CLI

* Validate for dev domain name taken

* Add progress indicator and 413 error message

* feat: Implement new upload process with new `deployment-api` endpoints (#2487)

* Add utilities for new worker upload process

* Add updated upload method

* Add server/client folder errors

* Implement new upload process

* Delete code for old upload process

* Fix fetch helper obfuscating errors

* Add server text to error

* Temporarily disable compression

* Apply lints

* refactor(worker): Implement batched uploads and improved progress output (#2490)

* Add refactored upload and batched upload utilities

* Switch to batch uploading utilities

* Add console output

* Apply lints

* Fix typo

* Fix error output

* Ignore system files while uploading (#2492)

* Mark worker:deploy as hidden command

* Replace ts-ignore directive comments

* Add changelog entry

* Apply suggestions from code review

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

* Switch to dynamic project config

* Remove superfluous formatSourcemap code

* Add async suffix

* Add max file-size note

* Normalise to throws

* Apply lints

* Log out eas url after deploy

* feat(eas-cli): Add support for static worker deployments (#2536)

* Add fallback logic for static projects

* Read project config for web.output mode

* Update GraphQL codegen'd files

---------

Co-authored-by: Kadi Kraman <[email protected]>
Co-authored-by: Szymon Dziedzic <[email protected]>
Co-authored-by: Cedric van Putten <[email protected]>
2024-09-06 13:39:44 +01:00
Szymon Dziedzic 3d55a4df40 [eas-cli] fix env vars loading issue and be more verbose about where the given env var comes from (#2534)
<!-- 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 had an invalid type guard that caused our GQL requests to fetch env vars to fail because of the environment enum option being in lowercase vs uppercase.

# How

Fix the issue and type guard.

Be more verbose about the source of the env vars being loaded to make it easier to understand what's going on

# Test Plan

Before

![Screenshot 2024-09-04 at 12.40.15.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/9YRXgAETSTRMfjZ0IP35/32d06cbf-c605-4a34-a336-9a715792da9c.png)

After

![Screenshot 2024-09-04 at 13.51.01.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/9YRXgAETSTRMfjZ0IP35/9a1451c3-c6b7-4f2f-9f86-e1254e0580a8.png)

![Screenshot 2024-09-04 at 13.54.12.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/9YRXgAETSTRMfjZ0IP35/c5da456a-7c9e-4c42-b69d-592f3e76909a.png)
2024-09-06 10:48:36 +02:00
Will Schurman b32ff2e733 [eas-cli] Upload fingeprint source as part of eas update command (#2533) 2024-09-05 11:59:58 -07:00
Expo CI 6245fb418d update CHANGELOG.md 2024-09-04 08:56:25 +00:00
Szymon Dziedzic 50943f333a v12.0.0 2024-09-04 10:50:36 +02:00
Szymon Dziedzic e930383a10 upgrade eas-cli-local-build-plugin to 1.0.135 2024-09-04 10:50:28 +02:00
Radosław KrzemieńandSzymon Dziedzic 8c31825908 [eas-cli] [ENG-11843] Change default appVersionSource to REMOTE (#2411)
* [eas-cli] Update tests

Updated the tests to reflect the change of the default `appVersionSource` value

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* [eas-cli] Update remote version handling

Updated the logic for REMOTE version source to treat undefined `appVersionSource` as REMOTE instead of LOCAL

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* [eas-cli] Refactor tests

Extracted the helper functions overriding the `appVersionSource` in eas.json to utils.ts

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* [eas-cli] Update version source when running builds

Applied the same change to the build command as was applied to version commands

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* update CHANGELOG.md

* [eas-cli] Adjust changelog

After it was correctly pointed out by @sjchmiela, the changelog has been amended to list the current changes not as chores and as breaking change instead

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* [eas-cli] Prompt the user

The user is now prompted when they don't specify `appVersionSource` to either set it automatically to LOCAL/REMOTE or abort the command and configure it manually. This removes the default behaviour alltogether and avoids a situation where some users have been relying on the old default and would now be surprised

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* [eas-cli] Update message

Updated the message displayed to the user when prompting for selection after the review

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* [eas-cli] Update message

Updated the message displayed to the user when prompting for selection after the review

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* [eas-cli] Update default eas.json

Updated the default eas.json created with `configure` command

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* [eas-cli] Update default eas.json

Updated the default eas.json created with `onboarding` command

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* [eas-cli] Check for non-interactive

Made the function prompting the user for selection on what to do with appVersionSource to respect the non-interactive flag, and abort the operation in non-interactive mode since the user can't make a selection

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* [eas-cli] Remove code duplication

Moved the setting of appVersionSource in easJsonCliConfig into the function prompting the user, which allows for implementing that in one place instead of 3

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* [eas-cli] Fix circular dependency

There was a circular dependency introduced with passing of the flags into a function. The definition of the build flags has been moved into the types.ts file to avoid itĻ

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* Update packages/eas-cli/src/project/remoteVersionSource.ts

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

* [eas-cli] Adjust wording

Changed the wording of the message displayed to the user to more accurately describe how app versions are handled

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* [eas-cli] Update default eas.json

Added autoIncrement: true when creating the default eas.json with remote appVersionSource

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* [eas-cli] Don't implicitly assume remote appVersionSource

The user is required to set appVersionSource in interactive mode so it should always be set. In non-interactive mode it can be not set, and in that case the default remains the same as it was, which is local

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* [eas-cli] Don't implicitly assume remote appVersionSource

The user is required to set appVersionSource in interactive mode so it should always be set. In non-interactive mode it can be not set, and in that case the default remains the same as it was, which is local

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* [eas-cli] Set autoIncrement

When creating the default eas.json set autoIncrement: true

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* [eas-cli] Set appVersionSource to local for non-interactive

To not break CIs that the users built for their apps in non-interactive mode we need to select the appVersionSource automatically in those cases. And since they may be counting on it being local since that was the previous default we need to keep setting it to local even if the new default is remote

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* [eas-cli] Handle autoIncrement != true

Do not ensure `appVersionSource` is set if the user has `autoIncrement: 'veresion'`. Display a message if the user doesn't have `autoIncrement: true` but don't prompt them to set `appVersionSource`

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* [eas-cli] Add missing quote

Added missing quote sign in the log message

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* [eas-cli] Add comma

Added comma to the log message

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* [eas-cli] Tweak message

Tweaked the log message according to the review comment

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* Update packages/eas-cli/src/build/runBuildAndSubmit.ts

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

* [eas-cli] Don't change eas.json in non-interactive mode

When defaulting the value of `appVersionSource` for commands executed in non-interactive mode the eas.json is not modified and the value is assumed only at runtime. This removes the need to commit changes, which in turn eliminates the risk of mistakenly committing working changes the user might have when executing the command

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* [eas-cli] Update message

Updated the message to correctly state how the version are handled with local appversionsource

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* [eas-cli] Update message

Updated the message to correctly state how the version are handled with remote appversionsource

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* [eas-cli] Update message

Updated the message based on review suggestions

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* Update packages/eas-cli/src/project/remoteVersionSource.ts

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

* [eas-cli] Reformat

Improved formatting

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* Update packages/eas-cli/src/project/remoteVersionSource.ts

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

* Update packages/eas-cli/src/project/remoteVersionSource.ts

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

* Update packages/eas-cli/src/build/runBuildAndSubmit.ts

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

* [eas-cli] Reformat

Improved formatting

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* Update packages/eas-cli/src/project/remoteVersionSource.ts

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

* [eas-cli] Reformat

Improved formatting

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* Update packages/eas-cli/src/project/remoteVersionSource.ts

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

* [eas-cli] Post-merge fix

Fixed issues after merging in the main branch

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* [eas-cli] Update version mentioned

Updated the version number that includes the current changes after a new major version had been released in the meantime

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

* Update packages/eas-cli/src/project/remoteVersionSource.ts

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

* [eas-cli] Lint

Fixed linting error

See: https://linear.app/expo/issue/ENG-11843/change-default-appversionsource-to-remote

---------

Co-authored-by: Szymon Dziedzic <[email protected]>
2024-09-03 14:12:12 +02:00
Expo Bot fbc39240a5 Upgrade eas-build dependencies (#2531)
⬆️ Upgrades [`eas-build`](https://github.com/expo/eas-build) dependencies.
2024-09-02 19:32:08 +02:00
Szymon Dziedzic f31054c5a5 [eas-cli] add new entitlements added after Xcode 15.0+ (#2525)
<!-- 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

companion to https://github.com/expo/third-party/pull/104

# How

This is my first PR adding new capabilities so please double-check if I did everything correctly, I based it on 6389f52

I got new entitlements from https://developer.apple.com/documentation/bundleresources/entitlements?changes=latest_major and added all available capabilities corresponding to these.

# Test Plan

Run prod build manually, add new entitlements for new capabilities to app config, and verify that they were enabled on the provisioning profile
2024-09-02 15:51:01 +02:00
Expo CI 7af8b62a7b update CHANGELOG.md 2024-08-31 09:25:14 +00:00
Szymon Dziedzic 56d492cbac v11.0.3 2024-08-31 11:20:03 +02:00
Szymon Dziedzic 4f53ce353c Revert "[eas-cli] Upgrade packages to SDK 51 release (#2498)" (#2524)
<!-- 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

https://exponent-internal.slack.com/archives/C02123T524U/p1724909908574979

It seems like SDK 51 config-related packages update broke builds for older SDKs

# How

I believe we didn't add any new config-related features in SDK 51, so resolving the config using the package version for SDK 50 should be ok for now and shouldn't cause any trouble.

Revert #2498

# Test Plan

Tests
2024-08-31 11:18:52 +02:00
Expo CI 736552b358 update CHANGELOG.md 2024-08-27 13:29:59 +00:00
Szymon Dziedzic b4a3f5b526 v11.0.2 2024-08-27 15:24:27 +02:00
Szymon Dziedzic 28592f27fa [eas-cli] remove unnecessary static project config context definition from eas build command (#2521)
<!-- 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

https://github.com/expo/eas-cli/issues/2519

I was able to reproduce the issue and it is indeed true. It seems like we mistakenly added a static project config definition to the `eas build` command context in https://github.com/expo/eas-cli/commit/56510f092527e458aa9dca19feac0b5d425dac56#diff-cd2e00f4d286a4714f8736e14c635f4c3b98c402367cd71a83e4cd743034bd79. The output from it wasn't really used anywhere, but adding it caused the app configs to be evaluated without `buildProfile.env` in the first pass when trying the resolve project ID and slug at the begging of command execution and our slug/project ID assertions to fail. It only affected people with dynamic project IDs and slug fields.

# How

Remove unnecessary static context from context definitions, therefore avoid resolving project ID and slug from app config without env vars as a first thing when the `eas build` command is executed.

# Test Plan

Tested manually
2024-08-27 15:23:15 +02:00
63 changed files with 6139 additions and 910 deletions

No files matched your search

+37
View File
@@ -8,10 +8,47 @@ This is the log of notable changes to EAS CLI and related packages.
### 🎉 New features
- Add `--non-interactive` and `--force` support when `--id` is not passed to the `eas init` command. ([#1983](https://github.com/expo/eas-cli/pull/1983) by [@mymattcarroll](https://github.com/mymattcarroll))
### 🐛 Bug fixes
### 🧹 Chores
## [12.1.1](https://github.com/expo/eas-cli/releases/tag/v12.1.1) - 2024-09-09
### 🐛 Bug fixes
- Fixed an issue where extensions retrieved the main app's entitlements instead of their own. ([#2532](https://github.com/expo/eas-cli/pull/2532) by [@HarrisHan](https://github.com/HarrisHan))
## [12.1.0](https://github.com/expo/eas-cli/releases/tag/v12.1.0) - 2024-09-06
### 🎉 New features
- **Internal/Experimental:** Add EAS Worker command ([#2447](https://github.com/expo/eas-cli/pull/2447) by [@kitten](https://github.com/kitten))
- Upload fingeprint source as part of eas update command. ([#2533](https://github.com/expo/eas-cli/pull/2533) by [@wschurman](https://github.com/wschurman))
## [12.0.0](https://github.com/expo/eas-cli/releases/tag/v12.0.0) - 2024-09-04
### 🛠 Breaking changes
- Prompt the users to set `appVersionSource`, while mentioning that `remote` is the default. ([#2411](https://github.com/expo/eas-cli/pull/2411) by [@radoslawkrzemien](https://github.com/radoslawkrzemien))
### 🎉 New features
- Add support for syncing Journaling Suggestions, Managed App Installation UI, and 5G Network Slicing capabilities. ([#2525](https://github.com/expo/eas-cli/pull/2525) by [@szdziedzic](https://github.com/szdziedzic))
## [11.0.3](https://github.com/expo/eas-cli/releases/tag/v11.0.3) - 2024-08-31
### 🐛 Bug fixes
- Revert config-related packages to SDK 50 version from SDK 51 version to fix broken entitlements behavior for older SDKs. ([#2524](https://github.com/expo/eas-cli/pull/2524) by [@szdziedzic](https://github.com/szdziedzic))
## [11.0.2](https://github.com/expo/eas-cli/releases/tag/v11.0.2) - 2024-08-27
### 🐛 Bug fixes
- Remove unncessary static project config context definition from `eas build` command context, to fix resolving dynamic projest ID and slug for dynamic app configs. ([#2521](https://github.com/expo/eas-cli/pull/2521) by [@szdziedzic](https://github.com/szdziedzic))
## [11.0.1](https://github.com/expo/eas-cli/releases/tag/v11.0.1) - 2024-08-26
### 🐛 Bug fixes
+1 -1
View File
@@ -1,5 +1,5 @@
{
"npmClient": "yarn",
"version": "11.0.1",
"version": "12.2.0",
"$schema": "node_modules/lerna/schemas/lerna-schema.json"
}
+66 -64
View File
@@ -143,7 +143,7 @@ ALIASES
$ eas login
```
_See code: [packages/eas-cli/src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/account/login.ts)_
_See code: [packages/eas-cli/src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/account/login.ts)_
## `eas account:logout`
@@ -160,7 +160,7 @@ ALIASES
$ eas logout
```
_See code: [packages/eas-cli/src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/account/logout.ts)_
_See code: [packages/eas-cli/src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/account/logout.ts)_
## `eas account:view`
@@ -177,7 +177,7 @@ ALIASES
$ eas whoami
```
_See code: [packages/eas-cli/src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/account/view.ts)_
_See code: [packages/eas-cli/src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/account/view.ts)_
## `eas analytics [STATUS]`
@@ -191,7 +191,7 @@ DESCRIPTION
display or change analytics settings
```
_See code: [packages/eas-cli/src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/analytics.ts)_
_See code: [packages/eas-cli/src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/analytics.ts)_
## `eas autocomplete [SHELL]`
@@ -243,7 +243,7 @@ DESCRIPTION
create a branch
```
_See code: [packages/eas-cli/src/commands/branch/create.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/branch/create.ts)_
_See code: [packages/eas-cli/src/commands/branch/create.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/branch/create.ts)_
## `eas branch:delete [NAME]`
@@ -264,7 +264,7 @@ DESCRIPTION
delete a branch
```
_See code: [packages/eas-cli/src/commands/branch/delete.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/branch/delete.ts)_
_See code: [packages/eas-cli/src/commands/branch/delete.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/branch/delete.ts)_
## `eas branch:list`
@@ -284,7 +284,7 @@ DESCRIPTION
list all branches
```
_See code: [packages/eas-cli/src/commands/branch/list.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/branch/list.ts)_
_See code: [packages/eas-cli/src/commands/branch/list.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/branch/list.ts)_
## `eas branch:rename`
@@ -304,7 +304,7 @@ DESCRIPTION
rename a branch
```
_See code: [packages/eas-cli/src/commands/branch/rename.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/branch/rename.ts)_
_See code: [packages/eas-cli/src/commands/branch/rename.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/branch/rename.ts)_
## `eas branch:view [NAME]`
@@ -327,7 +327,7 @@ DESCRIPTION
view a branch
```
_See code: [packages/eas-cli/src/commands/branch/view.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/branch/view.ts)_
_See code: [packages/eas-cli/src/commands/branch/view.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/branch/view.ts)_
## `eas build`
@@ -364,7 +364,7 @@ DESCRIPTION
start a build
```
_See code: [packages/eas-cli/src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/build/index.ts)_
_See code: [packages/eas-cli/src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/build/index.ts)_
## `eas build:cancel [BUILD_ID]`
@@ -383,7 +383,7 @@ DESCRIPTION
cancel a build
```
_See code: [packages/eas-cli/src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/build/cancel.ts)_
_See code: [packages/eas-cli/src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/build/cancel.ts)_
## `eas build:configure`
@@ -400,7 +400,7 @@ DESCRIPTION
configure the project to support EAS Build
```
_See code: [packages/eas-cli/src/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/build/configure.ts)_
_See code: [packages/eas-cli/src/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/build/configure.ts)_
## `eas build:delete [BUILD_ID]`
@@ -419,7 +419,7 @@ DESCRIPTION
delete a build
```
_See code: [packages/eas-cli/src/commands/build/delete.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/build/delete.ts)_
_See code: [packages/eas-cli/src/commands/build/delete.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/build/delete.ts)_
## `eas build:inspect`
@@ -454,7 +454,7 @@ DESCRIPTION
inspect the state of the project at specific build stages, useful for troubleshooting
```
_See code: [packages/eas-cli/src/commands/build/inspect.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/build/inspect.ts)_
_See code: [packages/eas-cli/src/commands/build/inspect.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/build/inspect.ts)_
## `eas build:list`
@@ -504,7 +504,7 @@ DESCRIPTION
list all builds for your project
```
_See code: [packages/eas-cli/src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/build/list.ts)_
_See code: [packages/eas-cli/src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/build/list.ts)_
## `eas build:resign`
@@ -533,7 +533,7 @@ DESCRIPTION
re-sign a build archive
```
_See code: [packages/eas-cli/src/commands/build/resign.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/build/resign.ts)_
_See code: [packages/eas-cli/src/commands/build/resign.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/build/resign.ts)_
## `eas build:run`
@@ -559,7 +559,7 @@ DESCRIPTION
run simulator/emulator builds from eas-cli
```
_See code: [packages/eas-cli/src/commands/build/run.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/build/run.ts)_
_See code: [packages/eas-cli/src/commands/build/run.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/build/run.ts)_
## `eas build:submit`
@@ -609,7 +609,7 @@ DESCRIPTION
get the latest version from EAS servers
```
_See code: [packages/eas-cli/src/commands/build/version/get.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/build/version/get.ts)_
_See code: [packages/eas-cli/src/commands/build/version/get.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/build/version/get.ts)_
## `eas build:version:set`
@@ -628,7 +628,7 @@ DESCRIPTION
update version of an app
```
_See code: [packages/eas-cli/src/commands/build/version/set.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/build/version/set.ts)_
_See code: [packages/eas-cli/src/commands/build/version/set.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/build/version/set.ts)_
## `eas build:version:sync`
@@ -647,7 +647,7 @@ DESCRIPTION
update a version in native code with a value stored on EAS servers
```
_See code: [packages/eas-cli/src/commands/build/version/sync.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/build/version/sync.ts)_
_See code: [packages/eas-cli/src/commands/build/version/sync.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/build/version/sync.ts)_
## `eas build:view [BUILD_ID]`
@@ -664,7 +664,7 @@ DESCRIPTION
view a build for your project
```
_See code: [packages/eas-cli/src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/build/view.ts)_
_See code: [packages/eas-cli/src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/build/view.ts)_
## `eas channel:create [NAME]`
@@ -685,7 +685,7 @@ DESCRIPTION
create a channel
```
_See code: [packages/eas-cli/src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/channel/create.ts)_
_See code: [packages/eas-cli/src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/channel/create.ts)_
## `eas channel:edit [NAME]`
@@ -707,7 +707,7 @@ DESCRIPTION
point a channel at a new branch
```
_See code: [packages/eas-cli/src/commands/channel/edit.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/channel/edit.ts)_
_See code: [packages/eas-cli/src/commands/channel/edit.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/channel/edit.ts)_
## `eas channel:list`
@@ -727,7 +727,7 @@ DESCRIPTION
list all channels
```
_See code: [packages/eas-cli/src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/channel/list.ts)_
_See code: [packages/eas-cli/src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/channel/list.ts)_
## `eas channel:rollout [CHANNEL]`
@@ -760,7 +760,7 @@ DESCRIPTION
Roll a new branch out on a channel incrementally.
```
_See code: [packages/eas-cli/src/commands/channel/rollout.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/channel/rollout.ts)_
_See code: [packages/eas-cli/src/commands/channel/rollout.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/channel/rollout.ts)_
## `eas channel:view [NAME]`
@@ -783,7 +783,7 @@ DESCRIPTION
view a channel
```
_See code: [packages/eas-cli/src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/channel/view.ts)_
_See code: [packages/eas-cli/src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/channel/view.ts)_
## `eas config`
@@ -804,7 +804,7 @@ DESCRIPTION
display project configuration (app.json + eas.json)
```
_See code: [packages/eas-cli/src/commands/config.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/config.ts)_
_See code: [packages/eas-cli/src/commands/config.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/config.ts)_
## `eas credentials`
@@ -821,7 +821,7 @@ DESCRIPTION
manage credentials
```
_See code: [packages/eas-cli/src/commands/credentials/index.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/credentials/index.ts)_
_See code: [packages/eas-cli/src/commands/credentials/index.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/credentials/index.ts)_
## `eas credentials:configure-build`
@@ -839,7 +839,7 @@ 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/v11.0.1/packages/eas-cli/src/commands/credentials/configure-build.ts)_
_See code: [packages/eas-cli/src/commands/credentials/configure-build.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/credentials/configure-build.ts)_
## `eas device:create`
@@ -853,7 +853,7 @@ DESCRIPTION
register new Apple Devices to use for internal distribution
```
_See code: [packages/eas-cli/src/commands/device/create.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/device/create.ts)_
_See code: [packages/eas-cli/src/commands/device/create.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/device/create.ts)_
## `eas device:delete`
@@ -873,7 +873,7 @@ DESCRIPTION
remove a registered device from your account
```
_See code: [packages/eas-cli/src/commands/device/delete.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/device/delete.ts)_
_See code: [packages/eas-cli/src/commands/device/delete.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/device/delete.ts)_
## `eas device:list`
@@ -894,7 +894,7 @@ DESCRIPTION
list all registered devices for your account
```
_See code: [packages/eas-cli/src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/device/list.ts)_
_See code: [packages/eas-cli/src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/device/list.ts)_
## `eas device:rename`
@@ -915,7 +915,7 @@ DESCRIPTION
rename a registered device
```
_See code: [packages/eas-cli/src/commands/device/rename.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/device/rename.ts)_
_See code: [packages/eas-cli/src/commands/device/rename.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/device/rename.ts)_
## `eas device:view [UDID]`
@@ -929,7 +929,7 @@ DESCRIPTION
view a device for your project
```
_See code: [packages/eas-cli/src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/device/view.ts)_
_See code: [packages/eas-cli/src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/device/view.ts)_
## `eas diagnostics`
@@ -943,7 +943,7 @@ DESCRIPTION
display environment info
```
_See code: [packages/eas-cli/src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/diagnostics.ts)_
_See code: [packages/eas-cli/src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/diagnostics.ts)_
## `eas help [COMMAND]`
@@ -971,10 +971,11 @@ create or link an EAS project
```
USAGE
$ eas init [--force --id <value>] [--non-interactive ]
$ eas init [--id <value>] [--force] [--non-interactive]
FLAGS
--force Whether to overwrite any existing project ID
--force Whether to create a new project/link an existing project without additional prompts or overwrite
any existing project ID when running with --id flag
--id=<value> ID of the EAS project to link
--non-interactive Run the command in non-interactive mode.
@@ -1050,7 +1051,7 @@ DESCRIPTION
validate the local store configuration
```
_See code: [packages/eas-cli/src/commands/metadata/lint.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/metadata/lint.ts)_
_See code: [packages/eas-cli/src/commands/metadata/lint.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/metadata/lint.ts)_
## `eas metadata:pull`
@@ -1067,7 +1068,7 @@ DESCRIPTION
generate the local store configuration from the app stores
```
_See code: [packages/eas-cli/src/commands/metadata/pull.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/metadata/pull.ts)_
_See code: [packages/eas-cli/src/commands/metadata/pull.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/metadata/pull.ts)_
## `eas metadata:push`
@@ -1084,7 +1085,7 @@ DESCRIPTION
sync the local store configuration to the app stores
```
_See code: [packages/eas-cli/src/commands/metadata/push.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/metadata/push.ts)_
_See code: [packages/eas-cli/src/commands/metadata/push.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/metadata/push.ts)_
## `eas onboarding [TARGET_PROJECT_DIRECTORY]`
@@ -1114,7 +1115,7 @@ DESCRIPTION
open the project page in a web browser
```
_See code: [packages/eas-cli/src/commands/open.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/open.ts)_
_See code: [packages/eas-cli/src/commands/open.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/open.ts)_
## `eas project:info`
@@ -1128,7 +1129,7 @@ DESCRIPTION
information about the current project
```
_See code: [packages/eas-cli/src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/project/info.ts)_
_See code: [packages/eas-cli/src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/project/info.ts)_
## `eas project:init`
@@ -1136,10 +1137,11 @@ create or link an EAS project
```
USAGE
$ eas project:init [--force --id <value>] [--non-interactive ]
$ eas project:init [--id <value>] [--force] [--non-interactive]
FLAGS
--force Whether to overwrite any existing project ID
--force Whether to create a new project/link an existing project without additional prompts or overwrite
any existing project ID when running with --id flag
--id=<value> ID of the EAS project to link
--non-interactive Run the command in non-interactive mode.
@@ -1150,7 +1152,7 @@ ALIASES
$ eas init
```
_See code: [packages/eas-cli/src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/project/init.ts)_
_See code: [packages/eas-cli/src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/project/init.ts)_
## `eas project:onboarding [TARGET_PROJECT_DIRECTORY]`
@@ -1168,7 +1170,7 @@ ALIASES
$ eas onboarding
```
_See code: [packages/eas-cli/src/commands/project/onboarding.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/project/onboarding.ts)_
_See code: [packages/eas-cli/src/commands/project/onboarding.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/project/onboarding.ts)_
## `eas secret:create`
@@ -1191,7 +1193,7 @@ DESCRIPTION
create an environment secret on the current project or owner account
```
_See code: [packages/eas-cli/src/commands/secret/create.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/secret/create.ts)_
_See code: [packages/eas-cli/src/commands/secret/create.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/secret/create.ts)_
## `eas secret:delete`
@@ -1209,7 +1211,7 @@ DESCRIPTION
delete an environment secret by ID
```
_See code: [packages/eas-cli/src/commands/secret/delete.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/secret/delete.ts)_
_See code: [packages/eas-cli/src/commands/secret/delete.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/secret/delete.ts)_
## `eas secret:list`
@@ -1223,7 +1225,7 @@ DESCRIPTION
list environment secrets available for your current app
```
_See code: [packages/eas-cli/src/commands/secret/list.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/secret/list.ts)_
_See code: [packages/eas-cli/src/commands/secret/list.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/secret/list.ts)_
## `eas secret:push`
@@ -1243,7 +1245,7 @@ DESCRIPTION
read environment secrets from env file and store on the server
```
_See code: [packages/eas-cli/src/commands/secret/push.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/secret/push.ts)_
_See code: [packages/eas-cli/src/commands/secret/push.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/secret/push.ts)_
## `eas submit`
@@ -1274,7 +1276,7 @@ ALIASES
$ eas build:submit
```
_See code: [packages/eas-cli/src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/submit.ts)_
_See code: [packages/eas-cli/src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/submit.ts)_
## `eas update`
@@ -1308,7 +1310,7 @@ DESCRIPTION
publish an update group
```
_See code: [packages/eas-cli/src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/update/index.ts)_
_See code: [packages/eas-cli/src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/update/index.ts)_
## `eas update:configure`
@@ -1326,7 +1328,7 @@ DESCRIPTION
configure the project to support EAS Update
```
_See code: [packages/eas-cli/src/commands/update/configure.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/update/configure.ts)_
_See code: [packages/eas-cli/src/commands/update/configure.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/update/configure.ts)_
## `eas update:delete GROUPID`
@@ -1347,7 +1349,7 @@ DESCRIPTION
delete all the updates in an update group
```
_See code: [packages/eas-cli/src/commands/update/delete.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/update/delete.ts)_
_See code: [packages/eas-cli/src/commands/update/delete.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/update/delete.ts)_
## `eas update:list`
@@ -1369,7 +1371,7 @@ DESCRIPTION
view the recent updates
```
_See code: [packages/eas-cli/src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/update/list.ts)_
_See code: [packages/eas-cli/src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/update/list.ts)_
## `eas update:republish`
@@ -1397,7 +1399,7 @@ DESCRIPTION
roll back to an existing update
```
_See code: [packages/eas-cli/src/commands/update/republish.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/update/republish.ts)_
_See code: [packages/eas-cli/src/commands/update/republish.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/update/republish.ts)_
## `eas update:roll-back-to-embedded`
@@ -1425,7 +1427,7 @@ DESCRIPTION
roll back to the embedded update
```
_See code: [packages/eas-cli/src/commands/update/roll-back-to-embedded.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/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/v12.2.0/packages/eas-cli/src/commands/update/roll-back-to-embedded.ts)_
## `eas update:rollback`
@@ -1445,7 +1447,7 @@ DESCRIPTION
roll back to an embedded update or an existing update
```
_See code: [packages/eas-cli/src/commands/update/rollback.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/update/rollback.ts)_
_See code: [packages/eas-cli/src/commands/update/rollback.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/update/rollback.ts)_
## `eas update:view GROUPID`
@@ -1465,7 +1467,7 @@ DESCRIPTION
update group details
```
_See code: [packages/eas-cli/src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/update/view.ts)_
_See code: [packages/eas-cli/src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/update/view.ts)_
## `eas webhook:create`
@@ -1486,7 +1488,7 @@ DESCRIPTION
create a webhook
```
_See code: [packages/eas-cli/src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/webhook/create.ts)_
_See code: [packages/eas-cli/src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/webhook/create.ts)_
## `eas webhook:delete [ID]`
@@ -1506,7 +1508,7 @@ DESCRIPTION
delete a webhook
```
_See code: [packages/eas-cli/src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/webhook/delete.ts)_
_See code: [packages/eas-cli/src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/webhook/delete.ts)_
## `eas webhook:list`
@@ -1524,7 +1526,7 @@ DESCRIPTION
list webhooks
```
_See code: [packages/eas-cli/src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/webhook/list.ts)_
_See code: [packages/eas-cli/src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/webhook/list.ts)_
## `eas webhook:update`
@@ -1546,7 +1548,7 @@ DESCRIPTION
update a webhook
```
_See code: [packages/eas-cli/src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/webhook/update.ts)_
_See code: [packages/eas-cli/src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/webhook/update.ts)_
## `eas webhook:view ID`
@@ -1563,7 +1565,7 @@ DESCRIPTION
view a webhook
```
_See code: [packages/eas-cli/src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v11.0.1/packages/eas-cli/src/commands/webhook/view.ts)_
_See code: [packages/eas-cli/src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v12.2.0/packages/eas-cli/src/commands/webhook/view.ts)_
## `eas whoami`
+1
View File
@@ -7,6 +7,7 @@ documents:
- 'src/commands/**/*.ts'
- 'src/branch/**/*.ts'
- 'src/channel/**/*.ts'
- 'src/worker/**/*.ts'
generates:
src/graphql/generated.ts:
plugins:
+2962 -274
View File
File diff suppressed because it is too large. Load diff
+17 -14
View File
@@ -1,34 +1,34 @@
{
"name": "eas-cli",
"description": "EAS command line tool",
"version": "11.0.1",
"version": "12.2.0",
"author": "Expo <[email protected]>",
"bin": {
"eas": "./bin/run"
},
"bugs": "https://github.com/expo/eas-cli/issues",
"dependencies": {
"@expo/apple-utils": "1.7.1",
"@expo/apple-utils": "1.8.0",
"@expo/code-signing-certificates": "0.0.5",
"@expo/config": "9.0.3",
"@expo/config-plugins": "8.0.8",
"@expo/config-types": "51.0.2",
"@expo/config": "8.5.4",
"@expo/config-plugins": "7.8.4",
"@expo/config-types": "50.0.0",
"@expo/eas-build-job": "1.0.133",
"@expo/eas-json": "11.0.0",
"@expo/json-file": "8.3.3",
"@expo/eas-json": "12.0.0",
"@expo/json-file": "8.2.37",
"@expo/logger": "1.0.117",
"@expo/multipart-body-parser": "1.1.0",
"@expo/osascript": "2.1.3",
"@expo/package-manager": "1.5.2",
"@expo/pkcs12": "0.1.2",
"@expo/plist": "0.1.3",
"@expo/osascript": "2.0.33",
"@expo/package-manager": "1.1.2",
"@expo/pkcs12": "0.0.8",
"@expo/plist": "0.0.20",
"@expo/plugin-help": "5.1.23",
"@expo/plugin-warn-if-update-available": "2.5.1",
"@expo/prebuild-config": "7.0.8",
"@expo/prebuild-config": "6.7.3",
"@expo/results": "1.0.0",
"@expo/rudder-sdk-node": "1.1.1",
"@expo/spawn-async": "1.7.2",
"@expo/steps": "1.0.130",
"@expo/spawn-async": "1.7.0",
"@expo/steps": "1.0.134",
"@expo/timeago.js": "1.0.0",
"@oclif/core": "^1.26.2",
"@oclif/plugin-autocomplete": "^2.3.10",
@@ -63,6 +63,7 @@
"log-symbols": "4.1.0",
"mime": "3.0.0",
"minimatch": "5.1.2",
"minizlib": "3.0.1",
"nanoid": "3.3.4",
"node-fetch": "2.6.7",
"node-forge": "1.3.1",
@@ -78,6 +79,7 @@
"semver": "7.5.4",
"slash": "3.0.0",
"tar": "6.2.1",
"tar-stream": "3.1.7",
"terminal-link": "2.1.1",
"tslib": "2.6.2",
"turndown": "7.1.2",
@@ -105,6 +107,7 @@
"@types/prompts": "2.4.2",
"@types/semver": "7.5.6",
"@types/tar": "6.1.10",
"@types/tar-stream": "3.1.3",
"@types/tough-cookie": "4.0.2",
"@types/uuid": "9.0.7",
"@types/wrap-ansi": "3.0.0",
@@ -1,3 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`BuildVersionGetView reading version aborts when the appVersionSource is not specified and the user chooses to set it to LOCAL 1`] = `"Aborting..."`;
exports[`BuildVersionGetView reading version when appVersionSource is set to local 1`] = `"This project is not configured for using remote version source. Add {"cli": { "appVersionSource": "remote" }} in eas.json or re-run this command without "--non-interactive" flag."`;
@@ -1,10 +1,18 @@
import { AppVersionSource, EasJson } from '@expo/eas-json';
import chalk from 'chalk';
import { getMockEasJson, mockCommandContext, mockProjectId, mockTestCommand } from './utils';
import {
getMockEasJson,
mockCommandContext,
mockProjectId,
mockTestCommand,
withLocalVersionSource,
withRemoteVersionSource,
} from './utils';
import BuildVersionGetView from '../../commands/build/version/get';
import { AppVersionQuery } from '../../graphql/queries/AppVersionQuery';
import Log from '../../log';
import { AppVersionSourceUpdateOption } from '../../project/remoteVersionSource';
import * as prompts from '../../prompts';
import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
jest.mock('../../project/applicationIdentifier');
@@ -12,16 +20,7 @@ jest.mock('fs');
jest.mock('../../log');
jest.mock('../../utils/json');
jest.mock('../../graphql/queries/AppVersionQuery');
function withRemoteVersionSource(easJson: EasJson): EasJson {
return {
...easJson,
cli: {
...easJson.cli,
appVersionSource: AppVersionSource.REMOTE,
},
};
}
jest.mock('../../prompts');
describe(BuildVersionGetView, () => {
afterEach(() => {
@@ -49,6 +48,29 @@ describe(BuildVersionGetView, () => {
expect(printJsonOnlyOutput).not.toHaveBeenCalled();
});
test('reading version for platform android when the appVersionSource is not specified and the user chooses to set it to REMOTE', async () => {
const ctx = mockCommandContext(BuildVersionGetView, {});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => ({
buildVersion: '100',
storeVersion: '1.0.0',
}));
const cmd = mockTestCommand(BuildVersionGetView, ['--platform=android'], ctx);
jest
.mocked(prompts.selectAsync)
.mockImplementationOnce(async () => AppVersionSourceUpdateOption.SET_TO_REMOTE);
await cmd.run();
expect(AppVersionQuery.latestVersionAsync).toHaveBeenCalledWith(
ctx.loggedIn.graphqlClient,
mockProjectId,
'ANDROID',
'eas.test.com'
);
expect(Log.log).toHaveBeenCalledWith(`Android versionCode - ${chalk.bold('100')}`);
expect(enableJsonOutput).not.toHaveBeenCalled();
expect(printJsonOnlyOutput).not.toHaveBeenCalled();
});
test('reading version for platform android when no remote version is set', async () => {
const ctx = mockCommandContext(BuildVersionGetView, {
easJson: withRemoteVersionSource(getMockEasJson()),
@@ -145,7 +167,9 @@ describe(BuildVersionGetView, () => {
});
test('reading version when appVersionSource is set to local ', async () => {
const ctx = mockCommandContext(BuildVersionGetView, {});
const ctx = mockCommandContext(BuildVersionGetView, {
easJson: withLocalVersionSource(getMockEasJson()),
});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => ({
buildVersion: '100',
storeVersion: '1.0.0',
@@ -158,4 +182,51 @@ describe(BuildVersionGetView, () => {
);
await expect(cmd.run()).rejects.toThrowErrorMatchingSnapshot();
});
test('reading version aborts when the appVersionSource is not specified and the user chooses to set it to LOCAL', async () => {
const ctx = mockCommandContext(BuildVersionGetView, {});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => ({
buildVersion: '100',
storeVersion: '1.0.0',
}));
jest
.mocked(prompts.selectAsync)
.mockImplementationOnce(async () => AppVersionSourceUpdateOption.SET_TO_LOCAL);
const cmd = mockTestCommand(BuildVersionGetView, ['--platform=android'], ctx);
await expect(cmd.run()).rejects.toThrowErrorMatchingSnapshot();
});
test('reading version aborts when the appVersionSource is not specified and the user chooses to configure it manually', async () => {
const ctx = mockCommandContext(BuildVersionGetView, {});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => ({
buildVersion: '100',
storeVersion: '1.0.0',
}));
jest
.mocked(prompts.selectAsync)
.mockImplementationOnce(async () => AppVersionSourceUpdateOption.ABORT);
const cmd = mockTestCommand(BuildVersionGetView, ['--platform=android'], ctx);
await expect(cmd.run()).rejects.toThrowError('Aborted.');
});
test('reading version sets appVersionSource to LOCAL and aborts when the appVersionSource is not specified and is run in non-interactive mode', async () => {
const ctx = mockCommandContext(BuildVersionGetView, {});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => ({
buildVersion: '100',
storeVersion: '1.0.0',
}));
const cmd = mockTestCommand(
BuildVersionGetView,
['--non-interactive', '--json', '--platform=android'],
ctx
);
await expect(cmd.run()).rejects.toThrowError(
`This project is not configured for using remote version source. Add ${chalk.bold(
'{"cli": { "appVersionSource": "remote" }}'
)} in eas.json or re-run this command without "--non-interactive" flag.`
);
});
});
@@ -1,4 +1,3 @@
import { AppVersionSource, EasJson } from '@expo/eas-json';
import fs from 'fs-extra';
import path from 'path';
@@ -8,12 +7,15 @@ import {
mockCommandContext,
mockProjectId,
mockTestCommand,
withLocalVersionSource,
withRemoteVersionSource,
} from './utils';
import BuildVersionSetView from '../../commands/build/version/set';
import { AppVersionMutation } from '../../graphql/mutations/AppVersionMutation';
import { AppQuery } from '../../graphql/queries/AppQuery';
import { AppVersionQuery } from '../../graphql/queries/AppVersionQuery';
import Log from '../../log';
import { AppVersionSourceUpdateOption } from '../../project/remoteVersionSource';
import * as prompts from '../../prompts';
jest.mock('../../project/applicationIdentifier');
@@ -25,16 +27,6 @@ jest.mock('../../log');
jest.mock('../../prompts');
jest.mock('../../utils/json');
function withRemoteVersionSource(easJson: EasJson): EasJson {
return {
...easJson,
cli: {
...easJson.cli,
appVersionSource: AppVersionSource.REMOTE,
},
};
}
describe(BuildVersionSetView, () => {
afterEach(() => {
jest.clearAllMocks();
@@ -67,6 +59,34 @@ describe(BuildVersionSetView, () => {
);
});
test('setting version for platform android when the appVersionSource is not specified and the user chooses to set it to REMOTE', async () => {
const ctx = mockCommandContext(BuildVersionSetView, {});
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => null);
jest.mocked(prompts.promptAsync).mockImplementationOnce(async () => ({
version: '1000',
}));
jest
.mocked(prompts.selectAsync)
.mockImplementationOnce(async () => AppVersionSourceUpdateOption.SET_TO_REMOTE);
const cmd = mockTestCommand(BuildVersionSetView, ['--platform=android'], ctx);
await cmd.run();
expect(AppVersionQuery.latestVersionAsync).toHaveBeenCalledWith(
ctx.loggedIn.graphqlClient,
mockProjectId,
'ANDROID',
'eas.test.com'
);
expect(AppVersionMutation.createAppVersionAsync).toHaveBeenCalledWith(
ctx.loggedIn.graphqlClient,
expect.objectContaining({
buildVersion: '1000',
storeVersion: '1.0.0',
})
);
});
test('printing current remote version before prompting for a new one', async () => {
const ctx = mockCommandContext(BuildVersionSetView, {
easJson: withRemoteVersionSource(getMockEasJson()),
@@ -115,7 +135,9 @@ describe(BuildVersionSetView, () => {
});
test('setting version aborts when appVersionSource is set to local and users refuse auto configuration', async () => {
const ctx = mockCommandContext(BuildVersionSetView, {});
const ctx = mockCommandContext(BuildVersionSetView, {
easJson: withLocalVersionSource(getMockEasJson()),
});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => null);
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest.mocked(prompts.confirmAsync).mockImplementation(async () => false);
@@ -125,10 +147,26 @@ describe(BuildVersionSetView, () => {
expect(AppVersionMutation.createAppVersionAsync).not.toHaveBeenCalledWith();
});
test('setting version when appVersionSource is set to local and user allows auto configuration', async () => {
test('setting version aborts when the appVersionSource is not specified and the user chooses to set it to LOCAL, and they refuse auto configuration', async () => {
const ctx = mockCommandContext(BuildVersionSetView, {});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => null);
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest
.mocked(prompts.selectAsync)
.mockImplementationOnce(async () => AppVersionSourceUpdateOption.SET_TO_LOCAL);
jest.mocked(prompts.confirmAsync).mockImplementationOnce(async () => false);
const cmd = mockTestCommand(BuildVersionSetView, ['--platform=android'], ctx);
await expect(cmd.run()).rejects.toThrowError('Aborting...');
expect(AppVersionMutation.createAppVersionAsync).not.toHaveBeenCalledWith();
});
test('setting version when appVersionSource is set to local and user allows auto configuration', async () => {
const ctx = mockCommandContext(BuildVersionSetView, {
easJson: withLocalVersionSource(getMockEasJson()),
});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => null);
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest.mocked(prompts.confirmAsync).mockImplementation(async () => true);
const cmd = mockTestCommand(BuildVersionSetView, ['--platform=android'], ctx);
@@ -137,4 +175,33 @@ describe(BuildVersionSetView, () => {
const easJsonAfterCmd = await fs.readJson(path.join(ctx.projectDir, 'eas.json'));
expect(easJsonAfterCmd.cli.appVersionSource).toBe('remote');
});
test('setting version when the appVersionSource is not specified and the user chooses to set it to LOCAL, and they allow auto configuration', async () => {
const ctx = mockCommandContext(BuildVersionSetView, {});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => null);
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest
.mocked(prompts.selectAsync)
.mockImplementationOnce(async () => AppVersionSourceUpdateOption.SET_TO_LOCAL);
jest.mocked(prompts.confirmAsync).mockImplementationOnce(async () => true);
const cmd = mockTestCommand(BuildVersionSetView, ['--platform=android'], ctx);
await cmd.run();
const easJsonAfterCmd = await fs.readJson(path.join(ctx.projectDir, 'eas.json'));
expect(easJsonAfterCmd.cli.appVersionSource).toBe('remote');
});
test('setting version aborts when the appVersionSource is not specified and the user chooses to configure manually', async () => {
const ctx = mockCommandContext(BuildVersionSetView, {});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => null);
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest
.mocked(prompts.selectAsync)
.mockImplementationOnce(async () => AppVersionSourceUpdateOption.ABORT);
const cmd = mockTestCommand(BuildVersionSetView, ['--platform=android'], ctx);
await expect(cmd.run()).rejects.toThrowError('Aborted.');
expect(AppVersionMutation.createAppVersionAsync).not.toHaveBeenCalledWith();
});
});
@@ -1,5 +1,4 @@
import { Workflow } from '@expo/eas-build-job';
import { AppVersionSource, EasJson } from '@expo/eas-json';
import fs from 'fs-extra';
import path from 'path';
@@ -9,6 +8,8 @@ import {
mockCommandContext,
mockProjectId,
mockTestCommand,
withLocalVersionSource,
withRemoteVersionSource,
} from './utils';
import { updateNativeVersionsAsync as updateAndroidNativeVersionsAsync } from '../../build/android/version';
import { updateNativeVersionsAsync as updateIosNativeVersionsAsync } from '../../build/ios/version';
@@ -19,6 +20,7 @@ import { AppQuery } from '../../graphql/queries/AppQuery';
import { AppVersionQuery } from '../../graphql/queries/AppVersionQuery';
import { getAppBuildGradleAsync } from '../../project/android/gradleUtils';
import { resolveTargetsAsync } from '../../project/ios/target';
import { AppVersionSourceUpdateOption } from '../../project/remoteVersionSource';
import { resolveWorkflowAsync } from '../../project/workflow';
import * as prompts from '../../prompts';
@@ -37,16 +39,6 @@ jest.mock('../../log');
jest.mock('../../prompts');
jest.mock('../../utils/json');
function withRemoteVersionSource(easJson: EasJson): EasJson {
return {
...easJson,
cli: {
...easJson.cli,
appVersionSource: AppVersionSource.REMOTE,
},
};
}
describe(BuildVersionSyncView, () => {
afterEach(() => {
jest.clearAllMocks();
@@ -79,6 +71,34 @@ describe(BuildVersionSyncView, () => {
expect(syncAndroidAsync).not.toHaveBeenCalled();
});
test('syncing version for managed project on platform android when appVersionSource is not set and the user chooses to set it to REMOTE', async () => {
const ctx = mockCommandContext(BuildVersionSyncView, {});
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => ({
buildVersion: '1000',
storeVersion: '0.0.1',
}));
jest.mocked(prompts.promptAsync).mockImplementationOnce(async () => ({
version: '1000',
}));
jest
.mocked(prompts.selectAsync)
.mockImplementationOnce(async () => AppVersionSourceUpdateOption.SET_TO_REMOTE);
jest.mocked(resolveWorkflowAsync).mockImplementation(async () => Workflow.MANAGED);
const cmd = mockTestCommand(BuildVersionSyncView, ['--platform=android'], ctx);
const syncAndroidAsync = jest.spyOn(cmd, 'syncAndroidAsync' as any);
await cmd.run();
expect(AppVersionQuery.latestVersionAsync).toHaveBeenCalledWith(
ctx.loggedIn.graphqlClient,
mockProjectId,
'ANDROID',
'eas.test.com'
);
expect(syncAndroidAsync).not.toHaveBeenCalled();
});
test('syncing version for bare project on platform android', async () => {
const ctx = mockCommandContext(BuildVersionSyncView, {
easJson: withRemoteVersionSource(getMockEasJson()),
@@ -179,7 +199,9 @@ describe(BuildVersionSyncView, () => {
});
test('syncing version aborts when appVersionSource is set to local and users refuse auto configuration', async () => {
const ctx = mockCommandContext(BuildVersionSyncView, {});
const ctx = mockCommandContext(BuildVersionSyncView, {
easJson: withLocalVersionSource(getMockEasJson()),
});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => null);
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest.mocked(prompts.confirmAsync).mockImplementation(async () => false);
@@ -189,10 +211,26 @@ describe(BuildVersionSyncView, () => {
expect(AppVersionMutation.createAppVersionAsync).not.toHaveBeenCalledWith();
});
test('syncing version when appVersionSource is set to local and user allows auto configuration', async () => {
test('syncing version aborts when appVersionSource is not set and the user chooses to set it to LOCAL, and they refuse auto configuration', async () => {
const ctx = mockCommandContext(BuildVersionSyncView, {});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => null);
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest
.mocked(prompts.selectAsync)
.mockImplementationOnce(async () => AppVersionSourceUpdateOption.SET_TO_LOCAL);
jest.mocked(prompts.confirmAsync).mockImplementation(async () => false);
const cmd = mockTestCommand(BuildVersionSyncView, ['--platform=android'], ctx);
await expect(cmd.run()).rejects.toThrowError('Aborting...');
expect(AppVersionMutation.createAppVersionAsync).not.toHaveBeenCalledWith();
});
test('syncing version when appVersionSource is set to local and user allows auto configuration', async () => {
const ctx = mockCommandContext(BuildVersionSyncView, {
easJson: withLocalVersionSource(getMockEasJson()),
});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => null);
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest.mocked(prompts.confirmAsync).mockImplementation(async () => true);
const cmd = mockTestCommand(BuildVersionSyncView, ['--platform=android'], ctx);
@@ -201,4 +239,33 @@ describe(BuildVersionSyncView, () => {
const easJsonAfterCmd = await fs.readJson(path.join(ctx.projectDir, 'eas.json'));
expect(easJsonAfterCmd.cli.appVersionSource).toBe('remote');
});
test('syncing version when appVersionSource is not set and the user chooses to set it to LOCAL and they allow auto configuration', async () => {
const ctx = mockCommandContext(BuildVersionSyncView, {});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => null);
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest
.mocked(prompts.selectAsync)
.mockImplementationOnce(async () => AppVersionSourceUpdateOption.SET_TO_LOCAL);
jest.mocked(prompts.confirmAsync).mockImplementation(async () => true);
const cmd = mockTestCommand(BuildVersionSyncView, ['--platform=android'], ctx);
await cmd.run();
const easJsonAfterCmd = await fs.readJson(path.join(ctx.projectDir, 'eas.json'));
expect(easJsonAfterCmd.cli.appVersionSource).toBe('remote');
});
test('syncing version aborts when appVersionSource is not set and the user chooses to configure manually', async () => {
const ctx = mockCommandContext(BuildVersionSyncView, {});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => null);
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest
.mocked(prompts.selectAsync)
.mockImplementationOnce(async () => AppVersionSourceUpdateOption.ABORT);
const cmd = mockTestCommand(BuildVersionSyncView, ['--platform=android'], ctx);
await expect(cmd.run()).rejects.toThrowError('Aborted.');
expect(AppVersionMutation.createAppVersionAsync).not.toHaveBeenCalledWith();
});
});
@@ -1,5 +1,5 @@
import { ExpoConfig } from '@expo/config-types';
import { EasJson } from '@expo/eas-json';
import { AppVersionSource, EasJson } from '@expo/eas-json';
import { Command, Config } from '@oclif/core';
import { vol } from 'memfs';
import path from 'path';
@@ -148,3 +148,23 @@ export const getError = <TError = any>(call: () => unknown): TError | NoErrorThr
return error as TError;
}
};
export function withRemoteVersionSource(easJson: EasJson): EasJson {
return {
...easJson,
cli: {
...easJson.cli,
appVersionSource: AppVersionSource.REMOTE,
},
};
}
export function withLocalVersionSource(easJson: EasJson): EasJson {
return {
...easJson,
cli: {
...easJson.cli,
appVersionSource: AppVersionSource.LOCAL,
},
};
}
@@ -0,0 +1,77 @@
import { AppVersionSource, EasJsonAccessor } from '@expo/eas-json';
import fs from 'fs-extra';
import { vol } from 'memfs';
import { easCliVersion } from '../../utils/easCli';
import GitClient from '../../vcs/clients/git';
import { Client } from '../../vcs/vcs';
import { ensureProjectConfiguredAsync } from '../configure';
jest.mock('fs');
jest.mock('../../vcs/vcs');
jest.mock('../../vcs/clients/git');
beforeEach(async () => {
vol.reset();
});
describe(ensureProjectConfiguredAsync, () => {
it('returns false and does not configure if eas.json exists', async () => {
vol.fromJSON({
'./eas.json': JSON.stringify({
cli: {
version: `>= ${easCliVersion}`,
},
build: {
development: {
developmentClient: true,
distribution: 'internal',
},
preview: {
distribution: 'internal',
},
production: {},
},
submit: {
production: {},
},
}),
});
await expect(fs.pathExists(EasJsonAccessor.formatEasJsonPath('.'))).resolves.toBeTruthy();
const vcsClientMock = jest.mocked(new GitClient());
vcsClientMock.showChangedFilesAsync.mockImplementation(async () => {});
vcsClientMock.isCommitRequiredAsync.mockImplementation(async () => false);
vcsClientMock.trackFileAsync.mockImplementation(async () => {});
const result = await ensureProjectConfiguredAsync({
projectDir: '.',
nonInteractive: false,
vcsClient: vcsClientMock as unknown as Client,
});
expect(result).toBeFalsy();
await expect(fs.pathExists(EasJsonAccessor.formatEasJsonPath('.'))).resolves.toBeTruthy();
});
it('returns true and configures if eas.json does not exist', async () => {
const writeFileMock = jest.spyOn(fs, 'writeFile');
writeFileMock.mockImplementation(async (...args) => {
const easJsonPath = args[0] as string;
const easJsonData = args[1] as string;
vol.fromJSON({
[easJsonPath]: easJsonData,
});
});
await expect(fs.pathExists(EasJsonAccessor.formatEasJsonPath('.'))).resolves.toBeFalsy();
const vcsClientMock = jest.mocked(new GitClient());
vcsClientMock.showChangedFilesAsync.mockImplementation(async () => {});
vcsClientMock.isCommitRequiredAsync.mockImplementation(async () => false);
vcsClientMock.trackFileAsync.mockImplementation(async () => {});
const result = await ensureProjectConfiguredAsync({
projectDir: '.',
nonInteractive: false,
vcsClient: vcsClientMock as unknown as Client,
});
expect(result).toBeTruthy();
await expect(fs.pathExists(EasJsonAccessor.formatEasJsonPath('.'))).resolves.toBeTruthy();
const easJson = await EasJsonAccessor.fromProjectPath('.').readAsync();
expect(easJson.cli?.appVersionSource).toEqual(AppVersionSource.REMOTE);
});
});
+1 -1
View File
@@ -107,7 +107,7 @@ export async function prepareAndroidBuildAsync(
? false
: ctx.buildProfile.autoIncrement,
vcsClient: ctx.vcsClient,
env: ctx.buildProfile.env,
env: ctx.env,
});
},
prepareJobAsync: async (
+12 -57
View File
@@ -2,7 +2,7 @@ import {
ArchiveSource,
ArchiveSourceType,
BuildJob,
FingerprintSourceType,
FingerprintSource,
Metadata,
Platform,
} from '@expo/eas-build-job';
@@ -13,8 +13,6 @@ import cliProgress from 'cli-progress';
import fs from 'fs-extra';
import { GraphQLError } from 'graphql/error';
import nullthrows from 'nullthrows';
import path from 'path';
import { v4 as uuidv4 } from 'uuid';
import { BuildContext } from './context';
import {
@@ -64,11 +62,11 @@ import {
appPlatformEmojis,
requestedPlatformDisplayNames,
} from '../platform';
import { maybeUploadFingerprintAsync } from '../project/maybeUploadFingerprintAsync';
import { resolveRuntimeVersionAsync } from '../project/resolveRuntimeVersionAsync';
import { uploadFileAtPathToGCSAsync } from '../uploads';
import { formatBytes } from '../utils/files';
import { printJsonOnlyOutput } from '../utils/json';
import { getTmpDirectory } from '../utils/paths';
import { createProgressTracker } from '../utils/progress';
import { sleepAsync } from '../utils/promise';
@@ -186,7 +184,7 @@ export async function prepareBuildRequestForPlatformAsync<
return async () => {
if (ctx.localBuildOptions.localBuildMode === LocalBuildMode.LOCAL_BUILD_PLUGIN) {
await runLocalBuildAsync(job, metadata, ctx.localBuildOptions);
await runLocalBuildAsync(job, metadata, ctx.localBuildOptions, ctx.env);
return undefined;
} else if (ctx.localBuildOptions.localBuildMode === LocalBuildMode.INTERNAL) {
await BuildMutation.updateBuildMetadataAsync(ctx.graphqlClient, {
@@ -669,14 +667,14 @@ async function createAndMaybeUploadFingerprintAsync<T extends Platform>(
ctx: BuildContext<T>
): Promise<{
runtimeVersion?: string;
fingerprintSource?: Metadata['fingerprintSource'];
fingerprintSource?: FingerprintSource;
}> {
const resolvedRuntimeVersion = await resolveRuntimeVersionAsync({
exp: ctx.exp,
platform: ctx.platform,
workflow: ctx.workflow,
projectDir: ctx.projectDir,
env: ctx.buildProfile.env,
env: ctx.env,
cwd: ctx.projectDir,
});
@@ -685,62 +683,19 @@ async function createAndMaybeUploadFingerprintAsync<T extends Platform>(
}
/**
* It's ok for fingerprintSources to be empty
* It's ok for fingerprintSources or runtimeVersion to be empty
* fingerprintSources only exist if the project is using runtimeVersion.policy: fingerprint
*/
if (!resolvedRuntimeVersion.fingerprint) {
if (!resolvedRuntimeVersion.fingerprint || !resolvedRuntimeVersion.runtimeVersion) {
return {
runtimeVersion: resolvedRuntimeVersion.runtimeVersion ?? undefined,
};
}
await fs.mkdirp(getTmpDirectory());
const fingerprintLocation = path.join(getTmpDirectory(), `${uuidv4()}-runtime-fingerprint.json`);
await fs.writeJSON(fingerprintLocation, {
hash: resolvedRuntimeVersion.runtimeVersion,
sources: resolvedRuntimeVersion.fingerprint.fingerprintSources,
return await maybeUploadFingerprintAsync({
runtimeVersion: resolvedRuntimeVersion.runtimeVersion,
fingerprint: resolvedRuntimeVersion.fingerprint,
graphqlClient: ctx.graphqlClient,
localBuildMode: ctx.localBuildOptions.localBuildMode,
});
if (ctx.localBuildOptions.localBuildMode === LocalBuildMode.LOCAL_BUILD_PLUGIN) {
return {
runtimeVersion: resolvedRuntimeVersion.runtimeVersion ?? undefined,
fingerprintSource: {
type: FingerprintSourceType.PATH,
path: fingerprintLocation,
isDebugFingerprint: resolvedRuntimeVersion.fingerprint.isDebugFingerprintSource,
},
};
}
let fingerprintGCSBucketKey = undefined;
try {
fingerprintGCSBucketKey = await uploadFileAtPathToGCSAsync(
ctx.graphqlClient,
UploadSessionType.EasUpdateFingerprint,
fingerprintLocation
);
} catch (err: any) {
let errMessage = 'Failed to upload fingerprint to EAS';
if (err.message) {
errMessage += `\n\nReason: ${err.message}`;
}
Log.warn(errMessage);
return {
runtimeVersion: resolvedRuntimeVersion.runtimeVersion ?? undefined,
};
} finally {
await fs.remove(fingerprintLocation);
}
return {
runtimeVersion: resolvedRuntimeVersion.runtimeVersion ?? undefined,
fingerprintSource: {
type: FingerprintSourceType.GCS,
bucketKey: fingerprintGCSBucketKey,
isDebugFingerprint: resolvedRuntimeVersion.fingerprint.isDebugFingerprintSource,
},
};
}
+5 -2
View File
@@ -1,4 +1,4 @@
import { EasJson, EasJsonAccessor } from '@expo/eas-json';
import { AppVersionSource, EasJson, EasJsonAccessor } from '@expo/eas-json';
import chalk from 'chalk';
import fs from 'fs-extra';
@@ -55,6 +55,7 @@ async function configureAsync({
const EAS_JSON_DEFAULT: EasJson = {
cli: {
version: `>= ${easCliVersion}`,
appVersionSource: AppVersionSource.REMOTE,
},
build: {
development: {
@@ -64,7 +65,9 @@ const EAS_JSON_DEFAULT: EasJson = {
preview: {
distribution: 'internal',
},
production: {},
production: {
autoIncrement: true,
},
},
submit: {
production: {},
+1
View File
@@ -63,4 +63,5 @@ export interface BuildContext<T extends Platform> {
vcsClient: Client;
loggerLevel?: LoggerLevel;
repack: boolean;
env: Record<string, string>;
}
+7 -2
View File
@@ -43,6 +43,7 @@ export async function createBuildContextAsync<T extends Platform>({
buildLoggerLevel,
freezeCredentials,
repack,
env,
}: {
buildProfileName: string;
buildProfile: BuildProfile<T>;
@@ -64,8 +65,11 @@ export async function createBuildContextAsync<T extends Platform>({
buildLoggerLevel?: LoggerLevel;
freezeCredentials: boolean;
repack: boolean;
env: Record<string, string>;
}): Promise<BuildContext<T>> {
const { exp, projectId } = await getDynamicPrivateProjectConfigAsync({ env: buildProfile.env });
const { exp, projectId } = await getDynamicPrivateProjectConfigAsync({
env,
});
const projectName = exp.slug;
const account = await getOwnerAccountForProjectIdAsync(graphqlClient, projectId);
const workflow = await resolveWorkflowAsync(projectDir, platform, vcsClient);
@@ -87,7 +91,7 @@ export async function createBuildContextAsync<T extends Platform>({
user: actor,
graphqlClient,
analytics,
env: buildProfile.env,
env,
easJsonCliConfig,
vcsClient,
freezeCredentials,
@@ -147,6 +151,7 @@ export async function createBuildContextAsync<T extends Platform>({
requiredPackageManager,
loggerLevel: buildLoggerLevel,
repack,
env,
};
if (platform === Platform.ANDROID) {
const common = commonContext as CommonContext<Platform.ANDROID>;
@@ -0,0 +1,116 @@
import { Env } from '@expo/eas-build-job';
import { BuildProfile } from '@expo/eas-json';
import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
import { EnvironmentVariableEnvironment } from '../graphql/generated';
import { EnvironmentVariablesQuery } from '../graphql/queries/EnvironmentVariablesQuery';
import Log, { learnMore } from '../log';
function isEnvironment(env: string): env is EnvironmentVariableEnvironment {
return Object.values(EnvironmentVariableEnvironment).includes(
env as EnvironmentVariableEnvironment
);
}
export async function evaluateConfigWithEnvVarsAsync<Config extends { projectId: string }, Opts>({
flags,
buildProfile,
buildProfileName,
graphqlClient,
getProjectConfig,
opts,
}: {
flags: { environment?: string };
buildProfile: BuildProfile;
buildProfileName: string;
graphqlClient: ExpoGraphqlClient | null;
opts: Opts;
getProjectConfig(opts: Opts): Promise<Config>;
}): Promise<Config & { env: Env }> {
if (!graphqlClient) {
Log.warn('An Expo user account is required to fetch environment variables.');
const config = await getProjectConfig(opts);
return { env: buildProfile.env ?? {}, ...config };
}
const { projectId } = await getProjectConfig({ env: buildProfile.env, ...opts });
const env = await resolveEnvVarsAsync({
flags,
buildProfile,
buildProfileName,
graphqlClient,
projectId,
});
const config = await getProjectConfig({ ...opts, env });
return { env, ...config };
}
async function resolveEnvVarsAsync({
flags,
buildProfile,
buildProfileName,
graphqlClient,
projectId,
}: {
flags: { environment?: string };
buildProfile: BuildProfile;
buildProfileName: string;
graphqlClient: ExpoGraphqlClient;
projectId: string;
}): Promise<Env> {
const environment =
flags.environment ??
buildProfile.environment?.toUpperCase() ??
process.env.EAS_CURRENT_ENVIRONMENT;
if (!environment || !isEnvironment(environment)) {
Log.log(
`Loaded "env" configuration for the "${buildProfileName}" profile: ${
buildProfile.env && Object.keys(buildProfile.env).length > 0
? Object.keys(buildProfile.env).join(', ')
: 'no environment variables specified'
}. ${learnMore('https://docs.expo.dev/build-reference/variables/')}`
);
return { ...buildProfile.env };
}
try {
const environmentVariables = await EnvironmentVariablesQuery.byAppIdWithSensitiveAsync(
graphqlClient,
{
appId: projectId,
environment,
}
);
const serverEnvVars = Object.fromEntries(
environmentVariables
.filter(({ name, value }) => name && value)
.map(({ name, value }) => [name, value])
) as Record<string, string>;
const envVarsWithSource: Record<string, 'build profile' | 'EAS server'> = {
...Object.fromEntries(Object.keys(serverEnvVars).map(key => [key, 'EAS server'])),
...(buildProfile.env
? Object.fromEntries(Object.keys(buildProfile.env).map(key => [key, 'build profile']))
: null),
};
Log.log(
`Loaded "env" configuration for the "${buildProfileName}" profile and "${environment.toLowerCase()}" environment: ${
Object.keys(envVarsWithSource).length > 0
? Object.keys(envVarsWithSource)
.map(key => `${key} (source: ${envVarsWithSource[key]})`)
.join('\n')
: 'no environment variables specified'
}\n${learnMore('https://docs.expo.dev/build-reference/variables/')}`
);
return { ...serverEnvVars, ...buildProfile.env };
} catch (e) {
Log.error(`Failed to pull env variables for environment ${environment} from EAS servers`);
Log.error(e);
Log.error(
'This can possibly be a bug in EAS/EAS CLI. Report it here: https://github.com/expo/eas-cli/issues'
);
return { ...buildProfile.env };
}
}
+19 -1
View File
@@ -3,6 +3,7 @@ import {
ArchiveSourceType,
BuildMode,
BuildTrigger,
FingerprintSourceType,
Metadata,
Workflow,
} from '@expo/eas-build-job';
@@ -15,8 +16,10 @@ import {
BuildMetadataInput,
BuildWorkflow,
DistributionType,
FingerprintSourceInput,
BuildMode as GraphQLBuildMode,
BuildTrigger as GraphQLBuildTrigger,
FingerprintSourceType as GraphQLFingeprintSourceType,
ProjectArchiveSourceInput,
ProjectArchiveSourceType,
WorkerLoggerLevel,
@@ -42,7 +45,8 @@ export function transformProjectArchive(archiveSource: ArchiveSource): ProjectAr
export function transformMetadata(metadata: Metadata): BuildMetadataInput {
return {
...metadata,
fingerprintSource: metadata.fingerprintSource as BuildMetadataInput['fingerprintSource'],
fingerprintSource:
metadata.fingerprintSource && transformFingerprintSource(metadata.fingerprintSource),
credentialsSource:
metadata.credentialsSource && transformCredentialsSource(metadata.credentialsSource),
distribution: metadata.distribution && transformDistribution(metadata.distribution),
@@ -53,6 +57,20 @@ export function transformMetadata(metadata: Metadata): BuildMetadataInput {
};
}
export function transformFingerprintSource(
fingerprintSource: NonNullable<Metadata['fingerprintSource']>
): FingerprintSourceInput | null {
if (fingerprintSource.type !== FingerprintSourceType.GCS) {
return null;
}
return {
type: GraphQLFingeprintSourceType.Gcs,
bucketKey: fingerprintSource.bucketKey,
isDebugFingerprint: fingerprintSource.isDebugFingerprint,
};
}
function transformCredentialsSource(
credentialsSource: Metadata['credentialsSource']
): BuildCredentialsSource {
+3 -3
View File
@@ -24,7 +24,7 @@ import {
export async function createIosContextAsync(
ctx: CommonContext<Platform.IOS>
): Promise<IosBuildContext> {
const { buildProfile } = ctx;
const { buildProfile, env } = ctx;
if (ctx.workflow === Workflow.MANAGED) {
await ensureBundleIdentifierIsDefinedForManagedProjectAsync(ctx);
@@ -47,7 +47,7 @@ export async function createIosContextAsync(
projectDir: ctx.projectDir,
exp: ctx.exp,
xcodeBuildContext,
env: buildProfile.env,
env,
vcsClient: ctx.vcsClient,
});
const applicationTarget = findApplicationTarget(targets);
@@ -89,7 +89,7 @@ export async function prepareIosBuildAsync(
? false
: ctx.buildProfile.autoIncrement,
vcsClient: ctx.vcsClient,
env: ctx.buildProfile.env,
env: ctx.env,
});
},
prepareJobAsync: async (
+4 -2
View File
@@ -6,7 +6,7 @@ import semver from 'semver';
import { ora } from '../ora';
const PLUGIN_PACKAGE_NAME = 'eas-cli-local-build-plugin';
const PLUGIN_PACKAGE_VERSION = '1.0.131';
const PLUGIN_PACKAGE_VERSION = '1.0.135';
export enum LocalBuildMode {
/**
@@ -39,7 +39,8 @@ export interface LocalBuildOptions {
export async function runLocalBuildAsync(
job: Job,
metadata: Metadata,
options: LocalBuildOptions
options: LocalBuildOptions,
env: Record<string, string>
): Promise<void> {
const { command, args } = await getCommandAndArgsAsync(job, metadata);
let spinner;
@@ -57,6 +58,7 @@ export async function runLocalBuildAsync(
const spawnPromise = spawnAsync(command, args, {
stdio: options.verbose ? 'inherit' : 'pipe',
env: {
...env,
...process.env,
EAS_LOCAL_BUILD_WORKINGDIR: options.workingdir ?? process.env.EAS_LOCAL_BUILD_WORKINGDIR,
...(options.skipCleanup || options.skipNativeBuild
+45 -14
View File
@@ -2,7 +2,6 @@ import { ExpoConfig } from '@expo/config-types';
import { Env, Platform, Workflow } from '@expo/eas-build-job';
import {
AppVersionSource,
BuildProfile,
EasJson,
EasJsonAccessor,
EasJsonUtils,
@@ -19,6 +18,7 @@ import { BuildRequestSender, MaybeBuildFragment, waitForBuildEndAsync } from './
import { ensureProjectConfiguredAsync } from './configure';
import { BuildContext } from './context';
import { createBuildContextAsync } from './createContext';
import { evaluateConfigWithEnvVarsAsync } from './evaluateConfigWithEnvVarsAsync';
import { prepareIosBuildAsync } from './ios/build';
import { LocalBuildMode, LocalBuildOptions } from './local';
import { ensureExpoDevClientInstalledForDevClientBuildsAsync } from './utils/devClient';
@@ -33,6 +33,7 @@ import {
BuildFragment,
BuildStatus,
BuildWithSubmissionsFragment,
EnvironmentVariableEnvironment,
SubmissionFragment,
} from '../graphql/generated';
import { BuildQuery } from '../graphql/queries/BuildQuery';
@@ -57,8 +58,9 @@ import {
validateAppVersionRuntimePolicySupportAsync,
} from '../project/projectUtils';
import {
ensureAppVersionSourceIsSetAsync,
validateAppConfigForRemoteVersionSource,
validateBuildProfileVersionSettings,
validateBuildProfileVersionSettingsAsync,
} from '../project/remoteVersionSource';
import { confirmAsync } from '../prompts';
import { runAsync } from '../run/run';
@@ -96,6 +98,7 @@ export interface BuildFlags {
buildLoggerLevel?: LoggerLevel;
freezeCredentials: boolean;
repack: boolean;
environment?: EnvironmentVariableEnvironment;
}
export async function runBuildAndSubmitAsync(
@@ -129,13 +132,6 @@ export async function runBuildAndSubmitAsync(
profileName: flags.profile ?? undefined,
projectDir,
});
Log.log(
`Loaded "env" configuration for the "${buildProfiles[0].profileName}" profile: ${
buildProfiles[0].profile.env
? Object.keys(buildProfiles[0].profile.env).join(', ')
: 'no environment variables specified'
}. ${learnMore('https://docs.expo.dev/build-reference/variables/')}`
);
for (const buildProfile of buildProfiles) {
if (buildProfile.profile.image && ['default', 'stable'].includes(buildProfile.profile.image)) {
@@ -173,7 +169,12 @@ export async function runBuildAndSubmitAsync(
const customBuildConfigMetadataByPlatform: { [p in AppPlatform]?: CustomBuildConfigMetadata } =
{};
for (const buildProfile of buildProfiles) {
validateBuildProfileVersionSettings(buildProfile, easJsonCliConfig);
await validateBuildProfileVersionSettingsAsync(
buildProfile,
easJsonCliConfig,
projectDir,
flags
);
const maybeMetadata = await validateCustomBuildConfigAsync({
projectDir,
profile: buildProfile.profile,
@@ -192,6 +193,16 @@ export async function runBuildAndSubmitAsync(
for (const buildProfile of buildProfiles) {
const platform = toAppPlatform(buildProfile.platform);
const { env } = await evaluateConfigWithEnvVarsAsync({
flags,
buildProfile: buildProfile.profile,
buildProfileName: buildProfile.profileName,
graphqlClient,
getProjectConfig: getDynamicPrivateProjectConfigAsync,
opts: { env: buildProfile.profile.env },
});
const { build: maybeBuild, buildCtx } = await prepareAndStartBuildAsync({
projectDir,
flags,
@@ -204,6 +215,7 @@ export async function runBuildAndSubmitAsync(
vcsClient,
getDynamicPrivateProjectConfigAsync,
customBuildConfigMetadata: customBuildConfigMetadataByPlatform[platform],
env,
});
if (maybeBuild) {
startedBuilds.push({ build: maybeBuild, buildProfile });
@@ -251,7 +263,6 @@ export async function runBuildAndSubmitAsync(
buildCtx: nullthrows(buildCtxByPlatform[startedBuild.build.platform]),
moreBuilds: startedBuilds.length > 1,
projectDir,
buildProfile: startedBuild.buildProfile.profile,
submitProfile,
nonInteractive: flags.nonInteractive,
selectedSubmitProfileName: flags.submitProfile,
@@ -340,6 +351,7 @@ async function prepareAndStartBuildAsync({
vcsClient,
getDynamicPrivateProjectConfigAsync,
customBuildConfigMetadata,
env,
}: {
projectDir: string;
flags: BuildFlags;
@@ -352,6 +364,7 @@ async function prepareAndStartBuildAsync({
vcsClient: Client;
getDynamicPrivateProjectConfigAsync: DynamicConfigContextFn;
customBuildConfigMetadata?: CustomBuildConfigMetadata;
env: Env;
}): Promise<{ build: BuildFragment | undefined; buildCtx: BuildContext<Platform> }> {
const buildCtx = await createBuildContextAsync({
buildProfileName: buildProfile.profileName,
@@ -374,6 +387,7 @@ async function prepareAndStartBuildAsync({
buildLoggerLevel: flags.buildLoggerLevel,
freezeCredentials: flags.freezeCredentials,
repack: flags.repack,
env,
});
if (moreBuilds) {
@@ -412,6 +426,25 @@ async function prepareAndStartBuildAsync({
}
await validateAppVersionRuntimePolicySupportAsync(buildCtx.projectDir, buildCtx.exp);
if (
easJsonCliConfig?.appVersionSource === undefined &&
buildProfile.profile.autoIncrement !== 'version'
) {
if (buildProfile.profile.autoIncrement !== true) {
Log.warn(
`The field "cli.appVersionSource" is not set, but it will be required in the future. ${learnMore(
'https://docs.expo.dev/build-reference/app-versions/'
)}`
);
} else {
const easJsonAccessor = EasJsonAccessor.fromProjectPath(projectDir);
easJsonCliConfig = await ensureAppVersionSourceIsSetAsync(
easJsonAccessor,
easJsonCliConfig,
flags.nonInteractive
);
}
}
if (easJsonCliConfig?.appVersionSource === AppVersionSource.REMOTE) {
validateAppConfigForRemoteVersionSource(buildCtx.exp, buildProfile.platform);
}
@@ -448,7 +481,6 @@ async function prepareAndStartSubmissionAsync({
buildCtx,
moreBuilds,
projectDir,
buildProfile,
submitProfile,
selectedSubmitProfileName,
nonInteractive,
@@ -457,7 +489,6 @@ async function prepareAndStartSubmissionAsync({
buildCtx: BuildContext<Platform>;
moreBuilds: boolean;
projectDir: string;
buildProfile: BuildProfile;
submitProfile: SubmitProfile;
selectedSubmitProfileName?: string;
nonInteractive: boolean;
@@ -469,7 +500,7 @@ async function prepareAndStartSubmissionAsync({
profile: submitProfile,
archiveFlags: { id: build.id },
nonInteractive,
env: buildProfile.env,
env: buildCtx.env,
credentialsCtx: buildCtx.credentialsCtx,
applicationIdentifier: buildCtx.android?.applicationId ?? buildCtx.ios?.bundleIdentifier,
actor: buildCtx.user,
+23
View File
@@ -1,3 +1,9 @@
import { ResourceClass } from '@expo/eas-json';
import { LoggerLevel } from '@expo/logger';
import { LocalBuildOptions } from './local';
import { RequestedPlatform } from '../platform';
export enum BuildStatus {
NEW = 'new',
IN_QUEUE = 'in-queue',
@@ -14,3 +20,20 @@ export enum BuildDistributionType {
/** @deprecated Use simulator flag instead */
SIMULATOR = 'simulator',
}
export interface BuildFlags {
requestedPlatform: RequestedPlatform;
profile?: string;
nonInteractive: boolean;
wait: boolean;
clearCache: boolean;
json: boolean;
autoSubmit: boolean;
submitProfile?: string;
localBuildOptions: LocalBuildOptions;
resourceClass?: ResourceClass;
message?: string;
buildLoggerLevel?: LoggerLevel;
freezeCredentials: boolean;
repack: boolean;
}
+2 -2
View File
@@ -9,9 +9,9 @@ import Log, { learnMore } from '../log';
import { isPNGAsync } from '../utils/image';
export function checkNodeEnvVariable(ctx: CommonContext<Platform>): void {
if (ctx.buildProfile.env?.NODE_ENV === 'production') {
if (ctx.env?.NODE_ENV === 'production') {
Log.warn(
'You set NODE_ENV=production in the build profile. Remember that it will be available during the entire build process. In particular, it will make yarn/npm install only production packages.'
'You set NODE_ENV=production in the build profile or environment variables. Remember that it will be available during the entire build process. In particular, it will make yarn/npm install only production packages.'
);
Log.newLine();
}
@@ -38,6 +38,21 @@ export const EASEnvironmentFlag = {
}),
};
// NOTE: Used in build commands, should be replaced with EASEnvironmentFlag when
// the feature is public
export const EASEnvironmentFlagHidden = {
environment: Flags.enum<EnvironmentVariableEnvironment>({
description: "Environment variable's environment",
parse: upperCaseAsync,
hidden: true,
options: mapToLowercase([
EnvironmentVariableEnvironment.Development,
EnvironmentVariableEnvironment.Preview,
EnvironmentVariableEnvironment.Production,
]),
}),
};
export const EASVariableFormatFlag = {
format: Flags.enum({
description: 'Output format',
+5 -2
View File
@@ -10,8 +10,8 @@ import path from 'path';
import { LocalBuildMode } from '../../build/local';
import { BuildFlags, runBuildAndSubmitAsync } from '../../build/runBuildAndSubmit';
import EasCommand from '../../commandUtils/EasCommand';
import { EasNonInteractiveAndJsonFlags } from '../../commandUtils/flags';
import { StatuspageServiceName } from '../../graphql/generated';
import { EASEnvironmentFlagHidden, EasNonInteractiveAndJsonFlags } from '../../commandUtils/flags';
import { EnvironmentVariableEnvironment, StatuspageServiceName } from '../../graphql/generated';
import Log, { link } from '../../log';
import { RequestedPlatform, selectRequestedPlatformAsync } from '../../platform';
import { selectAsync } from '../../prompts';
@@ -37,6 +37,7 @@ interface RawBuildFlags {
'build-logger-level'?: LoggerLevel;
'freeze-credentials': boolean;
repack: boolean;
environment?: EnvironmentVariableEnvironment;
}
export default class Build extends EasCommand {
@@ -116,6 +117,7 @@ export default class Build extends EasCommand {
description: 'Use the golden dev client build repack flow as it works for onboarding',
}),
...EasNonInteractiveAndJsonFlags,
...EASEnvironmentFlagHidden,
};
static override contextDefinition = {
@@ -230,6 +232,7 @@ export default class Build extends EasCommand {
buildLoggerLevel: flags['build-logger-level'],
freezeCredentials: flags['freeze-credentials'],
repack: flags.repack,
environment: flags.environment,
};
}
+19 -4
View File
@@ -6,13 +6,14 @@ import chalk from 'chalk';
import { handleDeprecatedEasJsonAsync } from '.';
import { waitForBuildEndAsync } from '../../build/build';
import { evaluateConfigWithEnvVarsAsync } from '../../build/evaluateConfigWithEnvVarsAsync';
import { ensureIosCredentialsForBuildResignAsync } from '../../build/ios/credentials';
import { prepareCredentialsToResign } from '../../build/ios/prepareJob';
import { listAndSelectBuildOnAppAsync } from '../../build/queries';
import { printBuildResults, printLogsUrls } from '../../build/utils/printBuildInfo';
import EasCommand from '../../commandUtils/EasCommand';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
import { EasNonInteractiveAndJsonFlags } from '../../commandUtils/flags';
import { EASEnvironmentFlagHidden, EasNonInteractiveAndJsonFlags } from '../../commandUtils/flags';
import { EasPaginatedQueryFlags } from '../../commandUtils/pagination';
import { CredentialsContext } from '../../credentials/context';
import {
@@ -21,6 +22,7 @@ import {
BuildStatus,
BuildWorkflow,
DistributionType,
EnvironmentVariableEnvironment,
IosJobOverridesInput,
ProjectArchiveSourceType,
StatuspageServiceName,
@@ -46,6 +48,7 @@ interface BuildResignFlags {
sourceProfile?: string;
maybeBuildId?: string;
wait: boolean;
environment?: EnvironmentVariableEnvironment;
}
interface RawBuildResignFlags {
json: boolean;
@@ -57,6 +60,7 @@ interface RawBuildResignFlags {
'source-profile': string | undefined;
wait: boolean;
id: string | undefined;
environment: EnvironmentVariableEnvironment | undefined;
}
export default class BuildResign extends EasCommand {
@@ -89,6 +93,7 @@ export default class BuildResign extends EasCommand {
}),
...EasPaginatedQueryFlags,
...EasNonInteractiveAndJsonFlags,
...EASEnvironmentFlagHidden,
};
static override contextDefinition = {
@@ -140,7 +145,16 @@ export default class BuildResign extends EasCommand {
platform,
flags.targetProfile ?? 'production'
);
const { exp, projectId } = await getDynamicPrivateProjectConfigAsync({ env: buildProfile.env });
const { exp, projectId, env } = await evaluateConfigWithEnvVarsAsync({
flags,
buildProfile,
buildProfileName: flags.targetProfile ?? 'production',
graphqlClient,
getProjectConfig: getDynamicPrivateProjectConfigAsync,
opts: { env: buildProfile.env },
});
const account = await getOwnerAccountForProjectIdAsync(graphqlClient, projectId);
const build = await this.ensureBuildSelectedAsync(
{
@@ -161,7 +175,7 @@ export default class BuildResign extends EasCommand {
user: actor,
graphqlClient,
analytics,
env: buildProfile.env,
env,
easJsonCliConfig,
vcsClient,
});
@@ -181,7 +195,7 @@ export default class BuildResign extends EasCommand {
projectDir,
exp,
xcodeBuildContext,
env: buildProfile.env,
env,
vcsClient,
});
const credentialsResult = await ensureIosCredentialsForBuildResignAsync(
@@ -248,6 +262,7 @@ export default class BuildResign extends EasCommand {
targetProfile: flags['target-profile'],
maybeBuildId: flags.id,
wait: flags.wait,
environment: flags.environment,
};
}
@@ -3,8 +3,12 @@ import { EasJsonAccessor } from '@expo/eas-json';
import { Flags } from '@oclif/core';
import chalk from 'chalk';
import { evaluateConfigWithEnvVarsAsync } from '../../../build/evaluateConfigWithEnvVarsAsync';
import EasCommand from '../../../commandUtils/EasCommand';
import { EasNonInteractiveAndJsonFlags } from '../../../commandUtils/flags';
import {
EASEnvironmentFlagHidden,
EasNonInteractiveAndJsonFlags,
} from '../../../commandUtils/flags';
import { AppVersionQuery } from '../../../graphql/queries/AppVersionQuery';
import { toAppPlatform } from '../../../graphql/types/AppPlatform';
import Log from '../../../log';
@@ -31,6 +35,7 @@ export default class BuildVersionGetView extends EasCommand {
'Name of the build profile from eas.json. Defaults to "production" if defined in eas.json.',
helpValue: 'PROFILE_NAME',
}),
...EASEnvironmentFlagHidden,
...EasNonInteractiveAndJsonFlags,
};
@@ -74,8 +79,13 @@ export default class BuildVersionGetView extends EasCommand {
});
const results: { [key in Platform]?: string } = {};
for (const { profile, platform } of buildProfiles) {
const { exp, projectId } = await getDynamicPrivateProjectConfigAsync({
env: profile.env,
const { exp, projectId, env } = await evaluateConfigWithEnvVarsAsync({
flags,
buildProfile: profile,
buildProfileName: flags.profile ?? 'production',
graphqlClient,
getProjectConfig: getDynamicPrivateProjectConfigAsync,
opts: { env: profile.env },
});
validateAppConfigForRemoteVersionSource(exp, platform);
@@ -89,6 +99,7 @@ export default class BuildVersionGetView extends EasCommand {
platform,
vcsClient,
nonInteractive: flags['non-interactive'],
env,
});
const remoteVersions = await AppVersionQuery.latestVersionAsync(
graphqlClient,
@@ -4,7 +4,9 @@ import { EasJsonAccessor, EasJsonUtils } from '@expo/eas-json';
import { Flags } from '@oclif/core';
import chalk from 'chalk';
import { evaluateConfigWithEnvVarsAsync } from '../../../build/evaluateConfigWithEnvVarsAsync';
import EasCommand from '../../../commandUtils/EasCommand';
import { EASEnvironmentFlagHidden } from '../../../commandUtils/flags';
import { AppVersionMutation } from '../../../graphql/mutations/AppVersionMutation';
import { AppVersionQuery } from '../../../graphql/queries/AppVersionQuery';
import { toAppPlatform } from '../../../graphql/types/AppPlatform';
@@ -35,6 +37,7 @@ export default class BuildVersionSetView extends EasCommand {
'Name of the build profile from eas.json. Defaults to "production" if defined in eas.json.',
helpValue: 'PROFILE_NAME',
}),
...EASEnvironmentFlagHidden,
};
static override contextDefinition = {
@@ -64,7 +67,14 @@ export default class BuildVersionSetView extends EasCommand {
flags.profile ?? undefined
);
const { exp, projectId } = await getDynamicPrivateProjectConfigAsync({ env: profile.env });
const { exp, projectId, env } = await evaluateConfigWithEnvVarsAsync({
flags,
buildProfile: profile,
buildProfileName: flags.profile ?? 'production',
graphqlClient,
getProjectConfig: getDynamicPrivateProjectConfigAsync,
opts: { env: profile.env },
});
const displayName = await getDisplayNameForProjectIdAsync(graphqlClient, projectId);
validateAppConfigForRemoteVersionSource(exp, platform);
@@ -78,6 +88,7 @@ export default class BuildVersionSetView extends EasCommand {
platform,
vcsClient,
nonInteractive: false,
env,
});
const remoteVersions = await AppVersionQuery.latestVersionAsync(
graphqlClient,
@@ -5,8 +5,10 @@ import { Flags } from '@oclif/core';
import chalk from 'chalk';
import { updateNativeVersionsAsync as updateAndroidNativeVersionsAsync } from '../../../build/android/version';
import { evaluateConfigWithEnvVarsAsync } from '../../../build/evaluateConfigWithEnvVarsAsync';
import { updateNativeVersionsAsync as updateIosNativeVersionsAsync } from '../../../build/ios/version';
import EasCommand from '../../../commandUtils/EasCommand';
import { EASEnvironmentFlagHidden } from '../../../commandUtils/flags';
import { AppVersionQuery } from '../../../graphql/queries/AppVersionQuery';
import { toAppPlatform } from '../../../graphql/types/AppPlatform';
import Log from '../../../log';
@@ -54,6 +56,7 @@ export default class BuildVersionSyncView extends EasCommand {
'Name of the build profile from eas.json. Defaults to "production" if defined in eas.json.',
helpValue: 'PROFILE_NAME',
}),
...EASEnvironmentFlagHidden,
};
static override contextDefinition = {
@@ -87,8 +90,13 @@ export default class BuildVersionSyncView extends EasCommand {
projectDir,
});
for (const profileInfo of buildProfiles) {
const { exp, projectId } = await getDynamicPrivateProjectConfigAsync({
env: profileInfo.profile.env,
const { exp, projectId, env } = await evaluateConfigWithEnvVarsAsync({
flags,
buildProfile: profileInfo.profile,
buildProfileName: profileInfo.profileName,
graphqlClient,
getProjectConfig: getDynamicPrivateProjectConfigAsync,
opts: { env: profileInfo.profile.env },
});
validateAppConfigForRemoteVersionSource(exp, profileInfo.platform);
@@ -103,6 +111,7 @@ export default class BuildVersionSyncView extends EasCommand {
platform: profileInfo.platform,
vcsClient,
nonInteractive: false,
env,
});
const remoteVersions = await AppVersionQuery.latestVersionAsync(
graphqlClient,
+25 -7
View File
@@ -4,8 +4,10 @@ import { EasJsonAccessor, EasJsonUtils } from '@expo/eas-json';
import { Flags } from '@oclif/core';
import chalk from 'chalk';
import { evaluateConfigWithEnvVarsAsync } from '../build/evaluateConfigWithEnvVarsAsync';
import EasCommand from '../commandUtils/EasCommand';
import { EasNonInteractiveAndJsonFlags } from '../commandUtils/flags';
import { createGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
import { EASEnvironmentFlagHidden, EasNonInteractiveAndJsonFlags } from '../commandUtils/flags';
import { toAppPlatform } from '../graphql/types/AppPlatform';
import Log from '../log';
import { appPlatformEmojis } from '../platform';
@@ -27,12 +29,14 @@ export default class Config extends EasCommand {
'eas-json-only': Flags.boolean({
hidden: true,
}),
...EASEnvironmentFlagHidden,
...EasNonInteractiveAndJsonFlags,
};
static override contextDefinition = {
...this.ContextOptions.DynamicProjectConfig,
...this.ContextOptions.ProjectDir,
...this.ContextOptions.SessionManagment,
};
async runAsync(): Promise<void> {
@@ -40,10 +44,15 @@ export default class Config extends EasCommand {
if (flags.json) {
enableJsonOutput();
}
const { platform: maybePlatform, profile: maybeProfile } = flags;
const { getDynamicPublicProjectConfigAsync, projectDir } = await this.getContextAsync(Config, {
nonInteractive: false,
});
const {
platform: maybePlatform,
profile: maybeProfile,
'non-interactive': nonInteractive,
} = flags;
const { getDynamicPublicProjectConfigAsync, projectDir, sessionManager } =
await this.getContextAsync(Config, {
nonInteractive,
});
const accessor = EasJsonAccessor.fromProjectPath(projectDir);
const profileName =
@@ -80,8 +89,17 @@ export default class Config extends EasCommand {
Log.log(JSON.stringify(profile, null, 2));
}
} else {
const { exp: appConfig } = await getDynamicPublicProjectConfigAsync({
env: profile.env,
const { authenticationInfo } = await sessionManager.ensureLoggedInAsync({
nonInteractive,
});
const graphqlClient = createGraphqlClient(authenticationInfo);
const { exp: appConfig } = await evaluateConfigWithEnvVarsAsync({
flags,
buildProfile: profile,
buildProfileName: profileName,
graphqlClient,
getProjectConfig: getDynamicPublicProjectConfigAsync,
opts: { env: profile.env },
});
if (flags.json) {
+7 -6
View File
@@ -114,11 +114,10 @@ export default class EnvironmentVariableCreate extends EasCommand {
if (!environment) {
environment = await promptVariableEnvironmentAsync(nonInteractive);
}
const existingVariables = await EnvironmentVariablesQuery.byAppIdAsync(
graphqlClient,
projectId,
environment
);
const existingVariables = await EnvironmentVariablesQuery.byAppIdAsync(graphqlClient, {
appId: projectId,
environment,
});
const existingVariable = existingVariables.find(variable => variable.name === name);
if (existingVariable) {
@@ -191,7 +190,9 @@ export default class EnvironmentVariableCreate extends EasCommand {
`Created a new variable ${chalk.bold(name)} on project ${chalk.bold(projectDisplayName)}.`
);
} else if (scope === EnvironmentVariableScope.Shared) {
const sharedVariables = await EnvironmentVariablesQuery.sharedAsync(graphqlClient, projectId);
const sharedVariables = await EnvironmentVariablesQuery.sharedAsync(graphqlClient, {
appId: projectId,
});
const existingVariable = sharedVariables.find(variable => variable.name === name);
if (existingVariable) {
throw new Error(
+5 -2
View File
@@ -58,8 +58,11 @@ export default class EnvironmentVariableDelete extends EasCommand {
const variables =
scope === EnvironmentVariableScope.Project && environment
? await EnvironmentVariablesQuery.byAppIdAsync(graphqlClient, projectId, environment)
: await EnvironmentVariablesQuery.sharedAsync(graphqlClient, projectId);
? await EnvironmentVariablesQuery.byAppIdAsync(graphqlClient, {
appId: projectId,
environment,
})
: await EnvironmentVariablesQuery.sharedAsync(graphqlClient, { appId: projectId });
if (!name) {
({ name } = await promptAsync({
+15 -10
View File
@@ -72,7 +72,6 @@ export default class EnvironmentVariableGet extends EasCommand {
if (!environment && scope === EnvironmentVariableScope.Project) {
environment = await promptVariableEnvironmentAsync(nonInteractive);
}
const variable = await getVariableAsync(graphqlClient, scope, projectId, name, environment);
if (!variable) {
@@ -117,26 +116,32 @@ async function getVariableAsync(
graphqlClient: ExpoGraphqlClient,
scope: string,
projectId: string,
name: string,
name: string | undefined,
environment: string | undefined
): Promise<EnvironmentVariableFragment | null> {
if (!environment && scope === EnvironmentVariableScope.Project) {
throw new Error('Environment is required.');
}
if (!name) {
throw new Error("Variable name is required. Run the command with '--name VARIABLE_NAME' flag.");
}
if (environment && scope === EnvironmentVariableScope.Project) {
const appVariables = await EnvironmentVariablesQuery.byAppIdAsync(
graphqlClient,
projectId,
const appVariables = await EnvironmentVariablesQuery.byAppIdWithSensitiveAsync(graphqlClient, {
appId: projectId,
environment,
[name]
);
filterNames: [name],
});
return appVariables[0];
}
if (scope === EnvironmentVariableScope.Shared) {
const sharedVariables = await EnvironmentVariablesQuery.sharedAsync(graphqlClient, projectId, [
name,
]);
const sharedVariables = await EnvironmentVariablesQuery.sharedWithSensitiveAsync(
graphqlClient,
{
appId: projectId,
filterNames: [name],
}
);
return sharedVariables[0];
}
+3 -1
View File
@@ -40,7 +40,9 @@ export default class EnvironmentVariableLink extends EasCommand {
});
const projectDisplayName = await getDisplayNameForProjectIdAsync(graphqlClient, projectId);
const variables = await EnvironmentVariablesQuery.sharedAsync(graphqlClient, projectId);
const variables = await EnvironmentVariablesQuery.sharedAsync(graphqlClient, {
appId: projectId,
});
if (!name) {
name = await selectAsync(
+52 -6
View File
@@ -1,12 +1,18 @@
import { Flags } from '@oclif/core';
import chalk from 'chalk';
import EasCommand from '../../commandUtils/EasCommand';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
import {
EASEnvironmentFlag,
EASVariableFormatFlag,
EASVariableScopeFlag,
} from '../../commandUtils/flags';
import { EnvironmentVariableScope } from '../../graphql/generated';
import {
EnvironmentVariableEnvironment,
EnvironmentVariableFragment,
EnvironmentVariableScope,
} from '../../graphql/generated';
import { EnvironmentVariablesQuery } from '../../graphql/queries/EnvironmentVariablesQuery';
import Log from '../../log';
import { formatVariable } from '../../utils/formatVariable';
@@ -23,6 +29,10 @@ export default class EnvironmentValueList extends EasCommand {
};
static override flags = {
'include-sensitive': Flags.boolean({
description: 'Display sensitive values in the output',
default: false,
}),
...EASVariableFormatFlag,
...EASVariableScopeFlag,
...EASEnvironmentFlag,
@@ -30,7 +40,7 @@ export default class EnvironmentValueList extends EasCommand {
async runAsync(): Promise<void> {
let {
flags: { environment, format, scope },
flags: { environment, format, scope, 'include-sensitive': includeSensitive },
} = await this.parse(EnvironmentValueList);
const {
privateProjectConfig: { projectId },
@@ -43,10 +53,12 @@ export default class EnvironmentValueList extends EasCommand {
environment = await promptVariableEnvironmentAsync(false);
}
const variables =
scope === EnvironmentVariableScope.Project && environment
? await EnvironmentVariablesQuery.byAppIdAsync(graphqlClient, projectId, environment)
: await EnvironmentVariablesQuery.sharedAsync(graphqlClient, projectId);
const variables = await this.getVariablesForScopeAsync(graphqlClient, {
scope,
includingSensitive: includeSensitive,
environment,
projectId,
});
if (format === 'short') {
for (const variable of variables) {
@@ -69,4 +81,38 @@ export default class EnvironmentValueList extends EasCommand {
);
}
}
private async getVariablesForScopeAsync(
graphqlClient: ExpoGraphqlClient,
{
scope,
includingSensitive,
environment,
projectId,
}: {
scope: EnvironmentVariableScope;
includingSensitive: boolean;
environment?: EnvironmentVariableEnvironment;
projectId: string;
}
): Promise<EnvironmentVariableFragment[]> {
if (scope === EnvironmentVariableScope.Project && environment) {
if (includingSensitive) {
return await EnvironmentVariablesQuery.byAppIdWithSensitiveAsync(graphqlClient, {
appId: projectId,
environment,
});
}
return await EnvironmentVariablesQuery.byAppIdAsync(graphqlClient, {
appId: projectId,
environment,
});
}
return includingSensitive
? await EnvironmentVariablesQuery.sharedWithSensitiveAsync(graphqlClient, {
appId: projectId,
})
: await EnvironmentVariablesQuery.sharedAsync(graphqlClient, { appId: projectId });
}
}
+80
View File
@@ -0,0 +1,80 @@
import { Flags } from '@oclif/core';
import * as fs from 'fs-extra';
import EasCommand from '../../commandUtils/EasCommand';
import { EASEnvironmentFlag, EASNonInteractiveFlag } from '../../commandUtils/flags';
import { EnvironmentVariableFragment } from '../../graphql/generated';
import { EnvironmentVariablesQuery } from '../../graphql/queries/EnvironmentVariablesQuery';
import Log from '../../log';
import { confirmAsync } from '../../prompts';
import { promptVariableEnvironmentAsync } from '../../utils/prompts';
export default class EnvironmentValuePull extends EasCommand {
static override description = 'pull env file';
static override hidden = true;
static override contextDefinition = {
...this.ContextOptions.ProjectConfig,
...this.ContextOptions.LoggedIn,
};
static override flags = {
...EASEnvironmentFlag,
...EASNonInteractiveFlag,
path: Flags.string({
description: 'Path to the result `.env` file',
default: '.env.local',
}),
};
async runAsync(): Promise<void> {
let {
flags: { environment, path: targetPath, 'non-interactive': nonInteractive },
} = await this.parse(EnvironmentValuePull);
if (!environment) {
environment = await promptVariableEnvironmentAsync(nonInteractive);
}
const {
privateProjectConfig: { projectId },
loggedIn: { graphqlClient },
} = await this.getContextAsync(EnvironmentValuePull, {
nonInteractive,
});
targetPath = targetPath ?? '.env.local';
const environmentVariables = await EnvironmentVariablesQuery.byAppIdWithSensitiveAsync(
graphqlClient,
{
appId: projectId,
environment,
}
);
if (!nonInteractive && (await fs.exists(targetPath))) {
const result = await confirmAsync({
message: `File ${targetPath} already exists. Do you want to overwrite it?`,
});
if (!result) {
Log.log('Aborting...');
throw new Error(`File ${targetPath} already exists.`);
}
}
const filePrefix = `# Environment: ${environment}\n\n`;
const envFileContent = environmentVariables
.map((variable: EnvironmentVariableFragment) => {
if (variable.value === null) {
return `# ${variable.name}=***** (secret variables are not available for reading)`;
}
return `${variable.name}=${variable.value}`;
})
.join('\n');
await fs.writeFile(targetPath, filePrefix + envFileContent);
Log.log(`Pulled environment variables from ${environment} environment to ${targetPath}.`);
}
}
+210
View File
@@ -0,0 +1,210 @@
import { Flags } from '@oclif/core';
import dotenv from 'dotenv';
import fs from 'fs-extra';
import EasCommand from '../../commandUtils/EasCommand';
import { EASEnvironmentFlag } from '../../commandUtils/flags';
import {
EnvironmentVariableEnvironment,
EnvironmentVariableFragment,
EnvironmentVariableScope,
EnvironmentVariableVisibility,
} from '../../graphql/generated';
import {
EnvironmentVariableMutation,
EnvironmentVariablePushInput,
} from '../../graphql/mutations/EnvironmentVariableMutation';
import { EnvironmentVariablesQuery } from '../../graphql/queries/EnvironmentVariablesQuery';
import Log from '../../log';
import { confirmAsync, promptAsync } from '../../prompts';
type PushFlags = {
environment?: EnvironmentVariableEnvironment;
path: string;
};
export default class EnvironmentVariablePush extends EasCommand {
static override description = 'push env file';
static override hidden = true;
static override contextDefinition = {
...this.ContextOptions.ProjectConfig,
...this.ContextOptions.LoggedIn,
};
static override flags = {
...EASEnvironmentFlag,
path: Flags.string({
description: 'Path to the input `.env` file',
default: '.env.local',
}),
};
async runAsync(): Promise<void> {
const { flags } = await this.parse(EnvironmentVariablePush);
const { environment, path: envPath } = this.validateFlags(flags);
const {
privateProjectConfig: { projectId },
loggedIn: { graphqlClient },
} = await this.getContextAsync(EnvironmentVariablePush, {
nonInteractive: false,
});
const updateVariables: Record<string, EnvironmentVariablePushInput> =
await this.parseEnvFileAsync(envPath, environment);
const variableNames = Object.keys(updateVariables);
const existingVariables = await EnvironmentVariablesQuery.byAppIdAsync(graphqlClient, {
appId: projectId,
environment,
filterNames: variableNames,
});
const existingDifferentVariables: EnvironmentVariableFragment[] = [];
// Remove variables that are the same as the ones in the environment
existingVariables.forEach(variable => {
const existingVariableUpdate = updateVariables[variable.name];
if (existingVariableUpdate && existingVariableUpdate.value !== variable.value) {
existingDifferentVariables.push(variable);
} else {
delete updateVariables[variable.name];
}
});
const existingDifferentSharedVariables = existingDifferentVariables.filter(
variable => variable.scope === EnvironmentVariableScope.Shared
);
if (existingDifferentSharedVariables.length > 0) {
const existingDifferentSharedVariablesNames = existingDifferentSharedVariables.map(
variable => variable.name
);
Log.error('Shared variables cannot be overwritten by eas env:push command.');
Log.error('Remove them from the env file or unlink them from the project to continue:');
existingDifferentSharedVariablesNames.forEach(name => {
Log.error(`- ${name}`);
});
throw new Error('Shared variables cannot be overwritten by eas env:push command');
}
if (existingDifferentVariables.length > 0) {
Log.warn('Some variables already exist in the environment.');
const variableNames = existingDifferentVariables.map(variable => variable.name);
const confirmationMessage =
variableNames.length > 1
? `The ${variableNames.join(
', '
)} environment variables already exist in ${environment} environment. Do you want to override them all?`
: `The ${variableNames[0]} environment variable already exists in ${environment} environment. Do you want to override it?`;
const confirm = await confirmAsync({
message: confirmationMessage,
});
let variablesToOverwrite: string[] = [];
if (!confirm && existingDifferentVariables.length === 1) {
throw new Error('No new variables to push.');
}
if (confirm) {
variablesToOverwrite = existingDifferentVariables.map(variable => variable.name);
} else {
const promptResult = await promptAsync({
type: 'multiselect',
name: 'variablesToOverwrite',
message: 'Select variables to overwrite:',
// @ts-expect-error property missing from `@types/prompts`
optionsPerPage: 20,
choices: existingDifferentVariables.map(variable => ({
title: `${variable.name}: ${updateVariables[variable.name].value} (was ${
variable.value ?? '(secret)'
})`,
value: variable.name,
})),
});
variablesToOverwrite = promptResult.variablesToOverwrite;
}
for (const existingVariable of existingVariables) {
const name = existingVariable.name;
if (variablesToOverwrite.includes(name)) {
updateVariables[name]['overwrite'] = true;
} else {
delete updateVariables[name];
}
}
}
// Check if any of the sensitive variables already exist in the environment. Prompt the user to overwrite them.
const existingSensitiveVariables = existingVariables.filter(
variable => variable.value === null
);
if (existingSensitiveVariables.length > 0) {
const existingSensitiveVariablesNames = existingSensitiveVariables.map(
variable => `- ${variable.name}`
);
const confirm = await confirmAsync({
message: `You are about to overwrite sensitive variables.\n${existingSensitiveVariablesNames.join(
'\n'
)}\n Do you want to continue?`,
});
if (!confirm) {
throw new Error('Aborting...');
}
}
const variablesToPush = Object.values(updateVariables);
if (variablesToPush.length === 0) {
Log.log('No new variables to push.');
return;
}
await EnvironmentVariableMutation.createBulkEnvironmentVariablesForAppAsync(
graphqlClient,
variablesToPush,
projectId
);
Log.log(`Uploaded env file to ${environment} environment.`);
}
private async parseEnvFileAsync(
envPath: string,
environment: string
): Promise<Record<string, EnvironmentVariablePushInput>> {
if (!(await fs.exists(envPath))) {
throw new Error(`File ${envPath} does not exist.`);
}
const pushInput: Record<string, EnvironmentVariablePushInput> = {};
const variables: Record<string, string> = dotenv.parse(await fs.readFile(envPath, 'utf8'));
for (const [name, value] of Object.entries(variables)) {
pushInput[name] = {
name,
value,
environment,
visibility: name.startsWith('EXPO_SENSITIVE')
? EnvironmentVariableVisibility.Sensitive
: EnvironmentVariableVisibility.Public,
};
}
return pushInput;
}
private validateFlags(flags: PushFlags): Required<PushFlags> {
if (!flags.environment) {
throw new Error('Please provide an environment to push the env file to.');
}
return { ...flags, environment: flags.environment };
}
}
+4 -5
View File
@@ -46,11 +46,10 @@ export default class EnvironmentVariableUnlink extends EasCommand {
const projectDisplayName = await getDisplayNameForProjectIdAsync(graphqlClient, projectId);
const appVariables = await EnvironmentVariablesQuery.byAppIdAsync(
graphqlClient,
projectId,
environment
);
const appVariables = await EnvironmentVariablesQuery.byAppIdAsync(graphqlClient, {
appId: projectId,
environment,
});
const linkedVariables = appVariables.filter(
({ scope }) => scope === EnvironmentVariableScope.Shared
);
+7 -6
View File
@@ -80,11 +80,10 @@ export default class EnvironmentVariableUpdate extends EasCommand {
if (!environment) {
environment = await promptVariableEnvironmentAsync(nonInteractive);
}
const existingVariables = await EnvironmentVariablesQuery.byAppIdAsync(
graphqlClient,
projectId,
environment
);
const existingVariables = await EnvironmentVariablesQuery.byAppIdAsync(graphqlClient, {
appId: projectId,
environment,
});
if (!name) {
name = await selectAsync(
'Select variable',
@@ -134,7 +133,9 @@ export default class EnvironmentVariableUpdate extends EasCommand {
`Updated variable ${chalk.bold(name)} on project ${chalk.bold(projectDisplayName)}.`
);
} else if (scope === EnvironmentVariableScope.Shared) {
const sharedVariables = await EnvironmentVariablesQuery.sharedAsync(graphqlClient, projectId);
const sharedVariables = await EnvironmentVariablesQuery.sharedAsync(graphqlClient, {
appId: projectId,
});
if (!name) {
name = await selectAsync(
+54 -23
View File
@@ -8,6 +8,7 @@ import { getProjectDashboardUrl } from '../../build/utils/url';
import EasCommand from '../../commandUtils/EasCommand';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
import { saveProjectIdToAppConfigAsync } from '../../commandUtils/context/contextUtils/getProjectIdAsync';
import { EASNonInteractiveFlag } from '../../commandUtils/flags';
import { AppPrivacy, Role } from '../../graphql/generated';
import { AppMutation } from '../../graphql/mutations/AppMutation';
import { AppQuery } from '../../graphql/queries/AppQuery';
@@ -33,14 +34,10 @@ export default class ProjectInit extends EasCommand {
description: 'ID of the EAS project to link',
}),
force: Flags.boolean({
description: 'Whether to overwrite any existing project ID',
dependsOn: ['id'],
}),
// this is the same as EASNonInteractiveFlag but with the dependsOn
'non-interactive': Flags.boolean({
description: 'Run the command in non-interactive mode.',
dependsOn: ['id'],
description:
'Whether to create a new project/link an existing project without additional prompts or overwrite any existing project ID when running with --id flag',
}),
...EASNonInteractiveFlag,
};
static override contextDefinition = {
@@ -216,10 +213,11 @@ export default class ProjectInit extends EasCommand {
});
}
private static async initializeWithInteractiveSelectionAsync(
private static async initializeWithoutExplicitIDAsync(
graphqlClient: ExpoGraphqlClient,
actor: Actor,
projectDir: string
projectDir: string,
{ force, nonInteractive }: InitializeMethodOptions
): Promise<string> {
const exp = getPrivateExpoConfig(projectDir);
const existingProjectId = exp.extra?.eas?.projectId;
@@ -245,6 +243,20 @@ export default class ProjectInit extends EasCommand {
if (!accountName) {
if (allAccounts.length === 1) {
accountName = allAccounts[0].name;
} else if (nonInteractive) {
if (!force) {
throw new Error(
`There are multiple accounts that you have access to: ${allAccounts
.map(a => a.name)
.join(
', '
)}. Explicitly set the owner property in your app config or run this command with the --force flag to proceed with a default account: ${
allAccounts[0].name
}.`
);
}
accountName = allAccounts[0].name;
Log.log(`Using default account ${accountName} for non-interactive and force mode`);
} else {
const choices = ProjectInit.getAccountChoices(
actor,
@@ -274,13 +286,21 @@ export default class ProjectInit extends EasCommand {
projectName
);
if (existingProjectIdOnServer) {
const affirmedLink = await confirmAsync({
message: `Existing project found: ${projectFullName} (ID: ${existingProjectIdOnServer}). Link this project?`,
});
if (!affirmedLink) {
throw new Error(
`Project ID configuration canceled. Re-run the command to select a different account/project.`
);
if (!force) {
if (nonInteractive) {
throw new Error(
`Existing project found: ${projectFullName} (ID: ${existingProjectIdOnServer}). Use --force flag to continue with this project.`
);
}
const affirmedLink = await confirmAsync({
message: `Existing project found: ${projectFullName} (ID: ${existingProjectIdOnServer}). Link this project?`,
});
if (!affirmedLink) {
throw new Error(
`Project ID configuration canceled. Re-run the command to select a different account/project.`
);
}
}
await ProjectInit.saveProjectIdAndLogSuccessAsync(projectDir, existingProjectIdOnServer);
@@ -293,11 +313,18 @@ export default class ProjectInit extends EasCommand {
);
}
const affirmedCreate = await confirmAsync({
message: `Would you like to create a project for ${projectFullName}?`,
});
if (!affirmedCreate) {
throw new Error(`Project ID configuration canceled for ${projectFullName}.`);
if (!force) {
if (nonInteractive) {
throw new Error(
`Project does not exist: ${projectFullName}. Use --force flag to create this project.`
);
}
const affirmedCreate = await confirmAsync({
message: `Would you like to create a project for ${projectFullName}?`,
});
if (!affirmedCreate) {
throw new Error(`Project ID configuration canceled for ${projectFullName}.`);
}
}
const projectDashboardUrl = getProjectDashboardUrl(accountName, projectName);
@@ -405,10 +432,14 @@ export default class ProjectInit extends EasCommand {
});
idForConsistency = idArgument;
} else {
idForConsistency = await ProjectInit.initializeWithInteractiveSelectionAsync(
idForConsistency = await ProjectInit.initializeWithoutExplicitIDAsync(
graphqlClient,
actor,
projectDir
projectDir,
{
force,
nonInteractive,
}
);
}
@@ -1,6 +1,6 @@
import { ExpoConfig } from '@expo/config-types';
import { Platform } from '@expo/eas-build-job';
import { EasJson } from '@expo/eas-json';
import { AppVersionSource, EasJson } from '@expo/eas-json';
import chalk from 'chalk';
import fs from 'fs-extra';
import path from 'path';
@@ -411,6 +411,7 @@ async function configureProjectFromBareDefaultExpoTemplateAsync({
const easJson: EasJson = {
cli: {
version: `>= ${easCliVersion}`,
appVersionSource: AppVersionSource.REMOTE,
},
build: {
development: {
@@ -431,6 +432,7 @@ async function configureProjectFromBareDefaultExpoTemplateAsync({
},
production: {
channel: 'production',
autoIncrement: true,
...easBuildGitHubConfig,
},
},
@@ -138,7 +138,16 @@ describe(UpdatePublish.name, () => {
// Add configuration to the project that should not be included in the update
const { appJson } = mockTestProject({
expoConfig: {},
expoConfig: {
hooks: {
postPublish: [
{
file: 'custom-hook.js',
config: { some: 'config' },
},
],
},
},
});
const { platforms, runtimeVersion } = mockTestExport({ platforms: ['ios'] });
@@ -144,7 +144,16 @@ describe(UpdateRollBackToEmbedded.name, () => {
// Add configuration to the project that should not be included in the update
mockTestProject({
expoConfig: {},
expoConfig: {
hooks: {
postPublish: [
{
file: 'custom-hook.js',
config: { some: 'config' },
},
],
},
},
});
const platforms = ['ios'];
+66 -38
View File
@@ -4,6 +4,7 @@ import chalk from 'chalk';
import nullthrows from 'nullthrows';
import { ensureBranchExistsAsync } from '../../branch/queries';
import { transformFingerprintSource } from '../../build/graphql';
import { ensureRepoIsCleanAsync } from '../../build/utils/repository';
import { getUpdateGroupUrl } from '../../build/utils/url';
import EasCommand from '../../commandUtils/EasCommand';
@@ -21,6 +22,7 @@ import { PublishMutation } from '../../graphql/mutations/PublishMutation';
import Log, { learnMore, link } from '../../log';
import { ora } from '../../ora';
import { RequestedPlatform } from '../../platform';
import { maybeUploadFingerprintAsync } from '../../project/maybeUploadFingerprintAsync';
import { getOwnerAccountForProjectIdAsync } from '../../project/projectUtils';
import {
RawAsset,
@@ -32,9 +34,9 @@ import {
filterCollectedAssetsByRequestedPlatforms,
generateEasMetadataAsync,
getBranchNameForCommandAsync,
getRuntimeToPlatformMappingFromRuntimeVersions,
getRuntimeToPlatformsAndFingerprintInfoMappingFromRuntimeVersionInfoObjects,
getRuntimeToUpdateRolloutInfoGroupMappingAsync,
getRuntimeVersionObjectAsync,
getRuntimeVersionInfoObjectsAsync,
getUpdateMessageForCommandAsync,
isUploadedAssetCountAboveWarningThreshold,
platformDisplayNames,
@@ -374,7 +376,7 @@ export default class UpdatePublish extends EasCommand {
}
const workflows = await resolveWorkflowPerPlatformAsync(projectDir, vcsClient);
const runtimeVersions = await getRuntimeVersionObjectAsync({
const runtimeVersionInfoObjects = await getRuntimeVersionInfoObjectsAsync({
exp,
platforms: realizedPlatforms,
projectDir,
@@ -384,21 +386,40 @@ export default class UpdatePublish extends EasCommand {
},
env: undefined,
});
const runtimeToPlatformMapping =
getRuntimeToPlatformMappingFromRuntimeVersions(runtimeVersions);
const runtimeToPlatformsAndFingerprintInfoMapping =
getRuntimeToPlatformsAndFingerprintInfoMappingFromRuntimeVersionInfoObjects(
runtimeVersionInfoObjects
);
const { branchId } = await ensureBranchExistsAsync(graphqlClient, {
appId: projectId,
branchName,
});
const runtimeToPlatformsAndFingerprintInfoAndFingerprintSourceMapping = await Promise.all(
runtimeToPlatformsAndFingerprintInfoMapping.map(async info => {
return {
...info,
fingerprintSource: info.fingerprint
? (
await maybeUploadFingerprintAsync({
runtimeVersion: info.runtimeVersion,
fingerprint: info.fingerprint,
graphqlClient,
})
).fingerprintSource ?? null
: null,
};
})
);
const runtimeVersionToRolloutInfoGroup =
rolloutPercentage !== undefined
? await getRuntimeToUpdateRolloutInfoGroupMappingAsync(graphqlClient, {
appId: projectId,
branchName,
rolloutPercentage,
runtimeToPlatformMapping,
runtimeToPlatformsAndFingerprintInfoMapping,
})
: undefined;
@@ -406,39 +427,43 @@ export default class UpdatePublish extends EasCommand {
const isGitWorkingTreeDirty = await vcsClient.hasUncommittedChangesAsync();
// Sort the updates into different groups based on their platform specific runtime versions
const updateGroups: PublishUpdateGroupInput[] = runtimeToPlatformMapping.map(
({ runtimeVersion, platforms }) => {
const localUpdateInfoGroup = Object.fromEntries(
platforms.map(platform => [
platform,
unsortedUpdateInfoGroups[platform as keyof UpdateInfoGroup],
])
);
const updateGroups: PublishUpdateGroupInput[] =
runtimeToPlatformsAndFingerprintInfoAndFingerprintSourceMapping.map(
({ runtimeVersion, platforms, fingerprintSource }) => {
const localUpdateInfoGroup = Object.fromEntries(
platforms.map(platform => [
platform,
unsortedUpdateInfoGroups[platform as keyof UpdateInfoGroup],
])
);
const rolloutInfoGroupForRuntimeVersion = runtimeVersionToRolloutInfoGroup
? runtimeVersionToRolloutInfoGroup.get(runtimeVersion)
: null;
const localRolloutInfoGroup = rolloutInfoGroupForRuntimeVersion
? Object.fromEntries(
platforms.map(platform => [
platform,
rolloutInfoGroupForRuntimeVersion[platform as keyof UpdateRolloutInfoGroup],
])
)
: null;
const rolloutInfoGroupForRuntimeVersion = runtimeVersionToRolloutInfoGroup
? runtimeVersionToRolloutInfoGroup.get(runtimeVersion)
: null;
const localRolloutInfoGroup = rolloutInfoGroupForRuntimeVersion
? Object.fromEntries(
platforms.map(platform => [
platform,
rolloutInfoGroupForRuntimeVersion[platform as keyof UpdateRolloutInfoGroup],
])
)
: null;
return {
branchId,
updateInfoGroup: localUpdateInfoGroup,
rolloutInfoGroup: localRolloutInfoGroup,
runtimeVersion,
message: updateMessage,
gitCommitHash,
isGitWorkingTreeDirty,
awaitingCodeSigningInfo: !!codeSigningInfo,
};
}
);
return {
branchId,
updateInfoGroup: localUpdateInfoGroup,
rolloutInfoGroup: localRolloutInfoGroup,
runtimeFingerprintSource: fingerprintSource
? transformFingerprintSource(fingerprintSource)
: null,
runtimeVersion,
message: updateMessage,
gitCommitHash,
isGitWorkingTreeDirty,
awaitingCodeSigningInfo: !!codeSigningInfo,
};
}
);
let newUpdates: UpdatePublishMutation['updateBranch']['publishUpdateGroups'];
const publishSpinner = ora('Publishing...').start();
try {
@@ -513,7 +538,10 @@ export default class UpdatePublish extends EasCommand {
Log.addNewLineIfNone();
for (const runtime of uniqBy(runtimeVersions, version => version.runtimeVersion)) {
for (const runtime of uniqBy(
runtimeToPlatformsAndFingerprintInfoMapping,
version => version.runtimeVersion
)) {
const newUpdatesForRuntimeVersion = newUpdates.filter(
update => update.runtimeVersion === runtime.runtimeVersion
);
@@ -24,11 +24,12 @@ import {
getOwnerAccountForProjectIdAsync,
} from '../../project/projectUtils';
import {
RuntimeVersionInfo,
UpdatePublishPlatform,
defaultPublishPlatforms,
getBranchNameForCommandAsync,
getRuntimeToPlatformMappingFromRuntimeVersions,
getRuntimeVersionObjectAsync,
getRuntimeToPlatformsAndFingerprintInfoMappingFromRuntimeVersionInfoObjects,
getRuntimeVersionInfoObjectsAsync,
getUpdateMessageForCommandAsync,
} from '../../project/publish';
import { resolveWorkflowPerPlatformAsync } from '../../project/workflow';
@@ -193,7 +194,7 @@ export default class UpdateRollBackToEmbedded extends EasCommand {
const isGitWorkingTreeDirty = await vcsClient.hasUncommittedChangesAsync();
const workflows = await resolveWorkflowPerPlatformAsync(projectDir, vcsClient);
const runtimeVersions = await getRuntimeVersionObjectAsync({
const runtimeVersionInfoObjects = await getRuntimeVersionInfoObjectsAsync({
exp,
platforms: realizedPlatforms,
projectDir,
@@ -203,6 +204,10 @@ export default class UpdateRollBackToEmbedded extends EasCommand {
},
env: undefined,
});
const runtimeToPlatformsAndFingerprintInfoMapping =
getRuntimeToPlatformsAndFingerprintInfoMappingFromRuntimeVersionInfoObjects(
runtimeVersionInfoObjects
);
let newUpdates: UpdatePublishMutation['updateBranch']['publishUpdateGroups'];
const publishSpinner = ora('Publishing...').start();
@@ -214,7 +219,7 @@ export default class UpdateRollBackToEmbedded extends EasCommand {
updateMessage,
branchId,
codeSigningInfo,
runtimeVersions,
runtimeToPlatformsAndFingerprintInfoMapping,
realizedPlatforms,
});
publishSpinner.succeed('Published!');
@@ -235,7 +240,10 @@ export default class UpdateRollBackToEmbedded extends EasCommand {
Log.addNewLineIfNone();
for (const runtime of uniqBy(runtimeVersions, version => version.runtimeVersion)) {
for (const runtime of uniqBy(
runtimeToPlatformsAndFingerprintInfoMapping,
version => version.runtimeVersion
)) {
const newUpdatesForRuntimeVersion = newUpdates.filter(
update => update.runtimeVersion === runtime.runtimeVersion
);
@@ -290,7 +298,7 @@ export default class UpdateRollBackToEmbedded extends EasCommand {
updateMessage,
branchId,
codeSigningInfo,
runtimeVersions,
runtimeToPlatformsAndFingerprintInfoMapping,
realizedPlatforms,
}: {
graphqlClient: ExpoGraphqlClient;
@@ -299,17 +307,17 @@ export default class UpdateRollBackToEmbedded extends EasCommand {
updateMessage: string | undefined;
branchId: string;
codeSigningInfo: CodeSigningInfo | undefined;
runtimeVersions: { platform: UpdatePublishPlatform; runtimeVersion: string }[];
runtimeToPlatformsAndFingerprintInfoMapping: (RuntimeVersionInfo & {
platforms: UpdatePublishPlatform[];
})[];
realizedPlatforms: PublishPlatform[];
}): Promise<UpdatePublishMutation['updateBranch']['publishUpdateGroups']> {
const runtimeToPlatformMapping =
getRuntimeToPlatformMappingFromRuntimeVersions(runtimeVersions);
const rollbackInfoGroups = Object.fromEntries(
realizedPlatforms.map(platform => [platform, true])
);
// Sort the updates into different groups based on their platform specific runtime versions
const updateGroups: PublishUpdateGroupInput[] = runtimeToPlatformMapping.map(
const updateGroups: PublishUpdateGroupInput[] = runtimeToPlatformsAndFingerprintInfoMapping.map(
({ runtimeVersion, platforms }) => {
const localRollbackInfoGroup = Object.fromEntries(
platforms.map(platform => [platform, rollbackInfoGroups[platform]])
@@ -0,0 +1,212 @@
import chalk from 'chalk';
import fs from 'node:fs';
import * as path from 'node:path';
import EasCommand from '../../commandUtils/EasCommand';
import Log from '../../log';
import { ora } from '../../ora';
import { createProgressTracker } from '../../utils/progress';
import * as WorkerAssets from '../../worker/assets';
import { getSignedDeploymentUrlAsync } from '../../worker/deployment';
import { UploadParams, batchUploadAsync, uploadAsync } from '../../worker/upload';
const isDirectory = (directoryPath: string): Promise<boolean> =>
fs.promises
.stat(directoryPath)
.then(stat => stat.isDirectory())
.catch(() => false);
export default class WorkerDeploy extends EasCommand {
static override description = 'deploy an Expo web build';
static override aliases = ['deploy'];
// TODO(@kitten): Keep command hidden until worker deployments are live
static override hidden = true;
static override state = 'beta';
static override flags = {
// TODO(@kitten): Allow deployment identifier to be specified
};
static override contextDefinition = {
...this.ContextOptions.DynamicProjectConfig,
...this.ContextOptions.ProjectDir,
...this.ContextOptions.LoggedIn,
};
async runAsync(): Promise<void> {
Log.warn('EAS Worker Deployments are in beta and subject to breaking changes.');
const {
getDynamicPrivateProjectConfigAsync,
loggedIn: { graphqlClient },
} = await this.getContextAsync(WorkerDeploy, {
nonInteractive: true,
});
const { projectId, projectDir, exp } = await getDynamicPrivateProjectConfigAsync();
const distPath = path.resolve(projectDir, 'dist');
let distServerPath: string | null;
let distClientPath: string;
if (exp.web?.output === 'static') {
distClientPath = distPath;
distServerPath = null;
if (!(await isDirectory(distClientPath))) {
throw new Error(
`No "dist/" folder found. Prepare your project for deployment with "npx expo export"`
);
}
Log.log('Detected "static" worker deployment');
} else if (exp.web?.output === 'server') {
distClientPath = path.resolve(distPath, 'client');
distServerPath = path.resolve(distPath, 'server');
if (!(await isDirectory(distClientPath))) {
throw new Error(
`No "dist/client/" folder found. Prepare your project for deployment with "npx expo export"`
);
} else if (!(await isDirectory(distServerPath))) {
throw new Error(
`No "dist/server/" folder found. Prepare your project for deployment with "npx expo export"`
);
}
Log.log('Detected "server" worker deployment');
} else {
throw new Error(
`Single-page apps are not supported. Ensure that app.json key "expo.web.output" is set to "server" or "static".`
);
}
async function* emitWorkerTarballAsync(
assetMap: WorkerAssets.AssetMap
): AsyncGenerator<WorkerAssets.FileEntry> {
yield ['assets.json', JSON.stringify(assetMap)];
// TODO: Create manifest from user configuration
const manifest = { env: {} };
yield ['manifest.json', JSON.stringify(manifest)];
if (distServerPath) {
const workerFiles = WorkerAssets.listWorkerFilesAsync(distServerPath);
for await (const workerFile of workerFiles) {
yield [`server/${workerFile.normalizedPath}`, workerFile.data];
}
}
}
async function uploadTarballAsync(tarPath: string): Promise<any> {
const uploadUrl = await getSignedDeploymentUrlAsync(graphqlClient, exp, {
appId: projectId,
});
const { response } = await uploadAsync({
url: uploadUrl,
filePath: tarPath,
compress: false,
headers: {
accept: 'application/json',
},
});
if (response.status === 413) {
throw new Error(
'Upload failed! (Payload too large)\n' +
`The files in "dist/server/" (at: ${distServerPath}) exceed the maximum file size (10MB gzip).`
);
} else if (!response.ok) {
throw new Error(`Upload failed! (${response.statusText})`);
} else {
const json = await response.json();
if (!json.success || !json.result || typeof json.result !== 'object') {
throw new Error(json.message ? `Upload failed: ${json.message}` : 'Upload failed!');
}
return json.result;
}
}
async function uploadAssetsAsync(
assetMap: WorkerAssets.AssetMap,
uploads: Record<string, string>
): Promise<void> {
if (typeof uploads !== 'object' || !uploads) {
return;
}
// TODO(@kitten): Batch and upload multiple files in parallel
const uploadParams: UploadParams[] = [];
for await (const asset of WorkerAssets.listAssetMapFilesAsync(distClientPath, assetMap)) {
const uploadURL = uploads[asset.normalizedPath];
if (uploadURL) {
uploadParams.push({ url: uploadURL, filePath: asset.path });
}
}
const progress = {
total: uploadParams.length,
pending: 0,
percent: 0,
transferred: 0,
};
const updateProgress = createProgressTracker({
total: progress.total,
message(ratio) {
const percent = `${Math.floor(ratio * 100)}`;
const details = chalk.dim(
`(${progress.pending} Pending, ${progress.transferred} Completed, ${progress.total} Total)`
);
return `Uploading client assets: ${percent.padStart(3)}% ${details}`;
},
completedMessage: 'Uploaded assets for serverless deployment',
});
try {
for await (const signal of batchUploadAsync(uploadParams)) {
if ('response' in signal) {
progress.pending--;
progress.percent = ++progress.transferred / progress.total;
} else {
progress.pending++;
}
updateProgress({ progress });
}
} catch (error: any) {
updateProgress({ isComplete: true, error });
throw error;
}
updateProgress({ isComplete: true });
}
let progress = ora('Preparing worker upload');
let assetMap: WorkerAssets.AssetMap;
let tarPath: string;
try {
assetMap = await WorkerAssets.createAssetMapAsync(distClientPath);
tarPath = await WorkerAssets.packFilesIterableAsync(emitWorkerTarballAsync(assetMap));
} catch (error: any) {
progress.fail('Failed to prepare worker upload');
throw error;
}
progress.succeed('Prepared worker upload');
progress = ora('Creating worker deployment');
let deployResult: any;
try {
deployResult = await uploadTarballAsync(tarPath);
} catch (error: any) {
progress.fail('Failed to create worker deployment');
throw error;
}
progress.succeed('Created worker deployment');
await uploadAssetsAsync(assetMap, deployResult.uploads);
const baseDomain = process.env.EXPO_STAGING ? 'staging.expo' : 'expo';
const deploymentURL = `https://${deployResult.fullName}.${baseDomain}.app`;
const deploymentsUrl = `https://${baseDomain}.dev/accounts/${exp.owner}/projects/${deployResult.name}/serverless/deployments`;
Log.addNewLineIfNone();
Log.log(`🎉 Your worker deployment is ready: ${deploymentURL}`);
Log.addNewLineIfNone();
Log.log(`🔗 Manage on EAS: ${deploymentsUrl}`);
}
}
@@ -747,7 +747,47 @@ export const CapabilityMapping: CapabilityClassifier[] = [
validateOptions: validateBooleanOptions,
getOptions: getBooleanOptions,
},
{
entitlement: 'com.apple.developer.journal.allow',
name: 'Journaling Suggestions',
capability: CapabilityType.JOURNALING_SUGGESTIONS,
validateOptions: createValidateStringArrayOptions(['suggestions']),
getOptions: getDefinedOptions,
},
{
entitlement: 'com.apple.developer.managed-app-distribution.install-ui',
name: 'Managed App Installation UI',
capability: CapabilityType.MANAGED_APP_INSTALLATION_UI,
validateOptions: createValidateStringArrayOptions(['managed-app']),
getOptions: getDefinedOptions,
},
{
entitlement: 'com.apple.developer.networking.slicing.appcategory',
name: '5G Network Slicing',
capability: CapabilityType.NETWORK_SLICING,
validateOptions: createValidateStringArrayOptions([
'gaming-6014',
'communication-9000',
'streaming-9001',
]),
getOptions: getDefinedOptions,
},
{
entitlement: 'com.apple.developer.networking.slicing.trafficcategory',
name: '5G Network Slicing',
capability: CapabilityType.NETWORK_SLICING,
validateOptions: createValidateStringArrayOptions([
'defaultslice-1',
'video-2',
'background-3',
'voice-4',
'callsignaling-5',
'responsivedata-6',
'avstreaming-7',
'responsiveav-8',
]),
getOptions: getDefinedOptions,
},
// VMNET
// These don't appear to have entitlements, so it's unclear how we can automatically enable / disable them at this time.
+397 -61
View File
@@ -108,6 +108,8 @@ export type Account = {
apps: Array<App>;
/** Paginated list of apps associated with this account. By default sorted by name. Use filter to adjust the sorting order. */
appsPaginated: AccountAppsConnection;
/** Audit logs for account */
auditLogsPaginated: AuditLogConnection;
/** @deprecated Build packs are no longer supported */
availableBuilds?: Maybe<Scalars['Int']['output']>;
/** Billing information. Only visible to members with the ADMIN or OWNER role. */
@@ -324,6 +326,19 @@ export type AccountAppsPaginatedArgs = {
};
/**
* An account is a container owning projects, credentials, billing and other organization
* data and settings. Actors may own and be members of accounts.
*/
export type AccountAuditLogsPaginatedArgs = {
after?: InputMaybe<Scalars['String']['input']>;
before?: InputMaybe<Scalars['String']['input']>;
filter?: InputMaybe<AuditLogFilterInput>;
first?: InputMaybe<Scalars['Int']['input']>;
last?: InputMaybe<Scalars['Int']['input']>;
};
/**
* An account is a container owning projects, credentials, billing and other organization
* data and settings. Actors may own and be members of accounts.
@@ -1350,7 +1365,9 @@ export type App = Project & {
workerDeployment?: Maybe<WorkerDeployment>;
workerDeploymentAlias?: Maybe<WorkerDeploymentAlias>;
workerDeploymentAliases: WorkerDeploymentAliasesConnection;
workerDeploymentRequest: WorkerDeploymentRequestEdge;
workerDeployments: WorkerDeploymentsConnection;
workerDeploymentsCrash: WorkerDeploymentCrashEdge;
workerDeploymentsCrashes?: Maybe<WorkerDeploymentCrashes>;
workerDeploymentsMetrics?: Maybe<WorkerDeploymentMetrics>;
workerDeploymentsRequests?: Maybe<WorkerDeploymentRequests>;
@@ -1591,6 +1608,12 @@ export type AppWorkerDeploymentAliasesArgs = {
};
/** Represents an Exponent App (or Experience in legacy terms) */
export type AppWorkerDeploymentRequestArgs = {
requestId: Scalars['ID']['input'];
};
/** Represents an Exponent App (or Experience in legacy terms) */
export type AppWorkerDeploymentsArgs = {
after?: InputMaybe<Scalars['String']['input']>;
@@ -1600,6 +1623,13 @@ export type AppWorkerDeploymentsArgs = {
};
/** Represents an Exponent App (or Experience in legacy terms) */
export type AppWorkerDeploymentsCrashArgs = {
crashId: Scalars['ID']['input'];
sampleFor?: InputMaybe<CrashSampleFor>;
};
/** Represents an Exponent App (or Experience in legacy terms) */
export type AppWorkerDeploymentsCrashesArgs = {
limit?: Scalars['Int']['input'];
@@ -1609,12 +1639,14 @@ export type AppWorkerDeploymentsCrashesArgs = {
/** Represents an Exponent App (or Experience in legacy terms) */
export type AppWorkerDeploymentsMetricsArgs = {
filters?: InputMaybe<MetricsFilters>;
timespan: MetricsTimespan;
};
/** Represents an Exponent App (or Experience in legacy terms) */
export type AppWorkerDeploymentsRequestsArgs = {
filter?: InputMaybe<WorkerDeploymentRequestsFilter>;
limit?: Scalars['Int']['input'];
timespan: RequestsTimespan;
};
@@ -2456,6 +2488,18 @@ export type AuditLog = {
websiteMessage: Scalars['String']['output'];
};
export type AuditLogConnection = {
__typename?: 'AuditLogConnection';
edges: Array<AuditLogEdge>;
pageInfo: PageInfo;
};
export type AuditLogEdge = {
__typename?: 'AuditLogEdge';
cursor: Scalars['String']['output'];
node: AuditLog;
};
export type AuditLogExportInput = {
accountId: Scalars['ID']['input'];
createdAfter: Scalars['String']['input'];
@@ -2463,6 +2507,11 @@ export type AuditLogExportInput = {
format: AuditLogsExportFormat;
};
export type AuditLogFilterInput = {
entityTypes?: InputMaybe<Array<EntityTypeName>>;
mutationTypes?: InputMaybe<Array<TargetEntityMutationType>>;
};
export type AuditLogMutation = {
__typename?: 'AuditLogMutation';
/** Exports Audit Logs for an account. Returns the ID of the background job receipt. Use BackgroundJobReceiptQuery to get the status of the job. */
@@ -2569,6 +2618,17 @@ export type BranchFilterInput = {
searchTerm?: InputMaybe<Scalars['String']['input']>;
};
export type BranchQuery = {
__typename?: 'BranchQuery';
/** Query a Branch by ID */
byId: UpdateBranch;
};
export type BranchQueryByIdArgs = {
branchId: Scalars['ID']['input'];
};
/** Represents an EAS Build */
export type Build = ActivityTimelineProjectActivity & BuildOrBuildJob & {
__typename?: 'Build';
@@ -2589,6 +2649,7 @@ export type Build = ActivityTimelineProjectActivity & BuildOrBuildJob & {
createdAt: Scalars['DateTime']['output'];
customNodeVersion?: Maybe<Scalars['String']['output']>;
customWorkflowName?: Maybe<Scalars['String']['output']>;
deployment?: Maybe<Deployment>;
developmentClient?: Maybe<Scalars['Boolean']['output']>;
distribution?: Maybe<DistributionType>;
enqueuedAt?: Maybe<Scalars['DateTime']['output']>;
@@ -2637,6 +2698,8 @@ export type Build = ActivityTimelineProjectActivity & BuildOrBuildJob & {
resourceClassDisplayName: Scalars['String']['output'];
retryDisabledReason?: Maybe<BuildRetryDisabledReason>;
runFromCI?: Maybe<Scalars['Boolean']['output']>;
runtime?: Maybe<Runtime>;
/** @deprecated Use 'runtime' field . */
runtimeVersion?: Maybe<Scalars['String']['output']>;
sdkVersion?: Maybe<Scalars['String']['output']>;
selectedImage?: Maybe<Scalars['String']['output']>;
@@ -2734,6 +2797,7 @@ export type BuildArtifacts = {
applicationArchiveUrl?: Maybe<Scalars['String']['output']>;
buildArtifactsUrl?: Maybe<Scalars['String']['output']>;
buildUrl?: Maybe<Scalars['String']['output']>;
/** @deprecated Use 'runtime.fingerprintDebugInfoUrl' instead. */
fingerprintUrl?: Maybe<Scalars['String']['output']>;
xcodeBuildLogsUrl?: Maybe<Scalars['String']['output']>;
};
@@ -3125,6 +3189,17 @@ export type ChannelFilterInput = {
searchTerm?: InputMaybe<Scalars['String']['input']>;
};
export type ChannelQuery = {
__typename?: 'ChannelQuery';
/** Query a Channel by ID */
byId: UpdateChannel;
};
export type ChannelQueryByIdArgs = {
channelId: Scalars['ID']['input'];
};
export type Charge = {
__typename?: 'Charge';
amount: Scalars['Int']['output'];
@@ -3167,6 +3242,11 @@ export enum ContinentCode {
T1 = 'T1'
}
export enum CrashSampleFor {
Newest = 'NEWEST',
Oldest = 'OLDEST'
}
export type CrashesTimespan = {
end: Scalars['DateTime']['input'];
start?: InputMaybe<Scalars['DateTime']['input']>;
@@ -3228,6 +3308,8 @@ export type CreateGitHubBuildTriggerInput = {
appId: Scalars['ID']['input'];
autoSubmit: Scalars['Boolean']['input'];
buildProfile: Scalars['String']['input'];
environment?: InputMaybe<EnvironmentVariableEnvironment>;
executionBehavior: GitHubBuildTriggerExecutionBehavior;
isActive: Scalars['Boolean']['input'];
platform: AppPlatform;
/** A branch or tag name, or a wildcard pattern where the code change originates from. For example, `main` or `release/*`. */
@@ -3287,6 +3369,12 @@ export type CreateSubmissionResult = {
submission: Submission;
};
export type CumulativeMetricsOverTimeData = {
__typename?: 'CumulativeMetricsOverTimeData';
data: LineChartData;
metricsAtLastTimestamp: Array<LineDatapoint>;
};
export type CustomBuildConfigInput = {
path: Scalars['String']['input'];
};
@@ -3296,6 +3384,7 @@ export type CustomDomainDnsRecord = {
dnsContent: Scalars['String']['output'];
dnsName: Scalars['String']['output'];
dnsType: CustomDomainDnsRecordType;
isConfigured: Scalars['Boolean']['output'];
};
export enum CustomDomainDnsRecordType {
@@ -3303,13 +3392,6 @@ export enum CustomDomainDnsRecordType {
Txt = 'TXT'
}
export type CustomDomainMetadata = {
__typename?: 'CustomDomainMetadata';
ownershipVerification?: Maybe<CustomDomainDnsRecord>;
status: CustomDomainStatus;
verificationErrors?: Maybe<Array<Scalars['String']['output']>>;
};
export type CustomDomainMutation = {
__typename?: 'CustomDomainMutation';
deleteCustomDomain: DeleteCustomDomainResult;
@@ -3334,19 +3416,20 @@ export type CustomDomainMutationRegisterCustomDomainArgs = {
hostname: Scalars['String']['input'];
};
export type CustomDomainSetup = {
__typename?: 'CustomDomainSetup';
sslErrors?: Maybe<Array<Scalars['String']['output']>>;
sslStatus?: Maybe<CustomDomainStatus>;
status: CustomDomainStatus;
verificationErrors?: Maybe<Array<Scalars['String']['output']>>;
verificationStatus?: Maybe<CustomDomainStatus>;
};
export enum CustomDomainStatus {
Active = 'ACTIVE',
ActiveRedeploying = 'ACTIVE_REDEPLOYING',
Blocked = 'BLOCKED',
Deleted = 'DELETED',
Moved = 'MOVED',
Error = 'ERROR',
Pending = 'PENDING',
PendingBlocked = 'PENDING_BLOCKED',
PendingDeletion = 'PENDING_DELETION',
PendingMigration = 'PENDING_MIGRATION',
PendingProvisioned = 'PENDING_PROVISIONED',
Provisioned = 'PROVISIONED',
Unknown = 'UNKNOWN'
TimedOut = 'TIMED_OUT'
}
export type DeleteAccessTokenResult = {
@@ -3519,6 +3602,13 @@ export type DeploymentBuildsConnection = {
pageInfo: PageInfo;
};
export type DeploymentCumulativeMetricsOverTimeData = {
__typename?: 'DeploymentCumulativeMetricsOverTimeData';
data: LineChartData;
metricsAtLastTimestamp: Array<LineDatapoint>;
mostPopularUpdates: Array<Update>;
};
export type DeploymentEdge = {
__typename?: 'DeploymentEdge';
cursor: Scalars['String']['output'];
@@ -3532,6 +3622,7 @@ export type DeploymentFilterInput = {
export type DeploymentInsights = {
__typename?: 'DeploymentInsights';
cumulativeMetricsOverTime: DeploymentCumulativeMetricsOverTimeData;
embeddedUpdateTotalUniqueUsers: Scalars['Int']['output'];
embeddedUpdateUniqueUsersOverTime: UniqueUsersOverTimeData;
id: Scalars['ID']['output'];
@@ -3540,6 +3631,11 @@ export type DeploymentInsights = {
};
export type DeploymentInsightsCumulativeMetricsOverTimeArgs = {
timespan: InsightsTimespan;
};
export type DeploymentInsightsEmbeddedUpdateTotalUniqueUsersArgs = {
timespan: InsightsTimespan;
};
@@ -3559,6 +3655,17 @@ export type DeploymentInsightsUniqueUsersOverTimeArgs = {
timespan: InsightsTimespan;
};
export type DeploymentQuery = {
__typename?: 'DeploymentQuery';
/** Query a Deployment by ID */
byId: Deployment;
};
export type DeploymentQueryByIdArgs = {
deploymentId: Scalars['ID']['input'];
};
export type DeploymentSignedUrlResult = {
__typename?: 'DeploymentSignedUrlResult';
deploymentIdentifier: Scalars['ID']['output'];
@@ -3943,6 +4050,7 @@ export enum Feature {
export type FingerprintSourceInput = {
bucketKey?: InputMaybe<Scalars['String']['input']>;
isDebugFingerprint?: InputMaybe<Scalars['Boolean']['input']>;
type?: InputMaybe<FingerprintSourceType>;
};
@@ -4053,6 +4161,7 @@ export type GitHubBuildInput = {
autoSubmit?: InputMaybe<Scalars['Boolean']['input']>;
baseDirectory?: InputMaybe<Scalars['String']['input']>;
buildProfile: Scalars['String']['input'];
environment?: InputMaybe<EnvironmentVariableEnvironment>;
gitRef: Scalars['String']['input'];
platform: AppPlatform;
/** Repack the golden dev client build instead of running full build process. Used for onboarding. Do not use outside of onboarding flow, as for now it's only created with this specific use case in mind. */
@@ -4066,6 +4175,8 @@ export type GitHubBuildTrigger = {
autoSubmit: Scalars['Boolean']['output'];
buildProfile: Scalars['String']['output'];
createdAt: Scalars['DateTime']['output'];
environment?: Maybe<EnvironmentVariableEnvironment>;
executionBehavior: GitHubBuildTriggerExecutionBehavior;
id: Scalars['ID']['output'];
isActive: Scalars['Boolean']['output'];
lastRunAt?: Maybe<Scalars['DateTime']['output']>;
@@ -4081,6 +4192,11 @@ export type GitHubBuildTrigger = {
updatedAt: Scalars['DateTime']['output'];
};
export enum GitHubBuildTriggerExecutionBehavior {
Always = 'ALWAYS',
BaseDirectoryChanged = 'BASE_DIRECTORY_CHANGED'
}
export type GitHubBuildTriggerMutation = {
__typename?: 'GitHubBuildTriggerMutation';
/** Create GitHub build trigger for an App */
@@ -4712,6 +4828,7 @@ export type IosSubmissionConfigInput = {
export type JobRun = {
__typename?: 'JobRun';
app: App;
/** @deprecated No longer supported */
childJobRun?: Maybe<JobRun>;
createdAt: Scalars['DateTime']['output'];
displayName?: Maybe<Scalars['String']['output']>;
@@ -4735,8 +4852,6 @@ export type JobRunMutation = {
__typename?: 'JobRunMutation';
/** Cancel an EAS Job Run */
cancelJobRun: JobRun;
/** Retry an EAS Job Run */
retryJobRun: JobRun;
};
@@ -4744,11 +4859,6 @@ export type JobRunMutationCancelJobRunArgs = {
jobRunId: Scalars['ID']['input'];
};
export type JobRunMutationRetryJobRunArgs = {
jobRunId: Scalars['ID']['input'];
};
export enum JobRunPriority {
High = 'HIGH',
Normal = 'NORMAL'
@@ -4804,6 +4914,13 @@ export type LineChartData = {
labels: Array<Scalars['String']['output']>;
};
export type LineDatapoint = {
__typename?: 'LineDatapoint';
data: Scalars['Int']['output'];
id: Scalars['ID']['output'];
label: Scalars['String']['output'];
};
export type LineDataset = {
__typename?: 'LineDataset';
data: Array<Maybe<Scalars['Int']['output']>>;
@@ -4848,10 +4965,6 @@ export type MeMutation = {
certifySecondFactorDevice: SecondFactorBooleanResult;
/** Create a new Account and grant this User the owner Role */
createAccount: Account;
/** Delete an Account created via createAccount */
deleteAccount: DeleteAccountResult;
/** Delete a SSO user. Actor must be an owner on the SSO user's SSO account. */
deleteSSOUser: DeleteSsoUserResult;
/** Delete a second factor device */
deleteSecondFactorDevice: SecondFactorBooleanResult;
/** Delete a Snack that the current user owns */
@@ -4908,16 +5021,6 @@ export type MeMutationCreateAccountArgs = {
};
export type MeMutationDeleteAccountArgs = {
accountId: Scalars['ID']['input'];
};
export type MeMutationDeleteSsoUserArgs = {
ssoUserId: Scalars['ID']['input'];
};
export type MeMutationDeleteSecondFactorDeviceArgs = {
otp?: InputMaybe<Scalars['String']['input']>;
userSecondFactorDeviceId: Scalars['ID']['input'];
@@ -5001,6 +5104,42 @@ export type MeteredBillingStatus = {
EAS_UPDATE: Scalars['Boolean']['output'];
};
export enum MetricsCacheStatus {
Hit = 'HIT',
Miss = 'MISS',
Pass = 'PASS'
}
export type MetricsFilters = {
cacheStatus?: InputMaybe<Array<MetricsCacheStatus>>;
continent?: InputMaybe<Array<ContinentCode>>;
hasCustomDomainOrigin?: InputMaybe<Scalars['Boolean']['input']>;
isAsset?: InputMaybe<Scalars['Boolean']['input']>;
isCrash?: InputMaybe<Scalars['Boolean']['input']>;
isVerifiedBot?: InputMaybe<Scalars['Boolean']['input']>;
method?: InputMaybe<Array<MetricsRequestMethod>>;
os?: InputMaybe<Array<UserAgentOs>>;
pathname?: InputMaybe<Scalars['String']['input']>;
status?: InputMaybe<Array<Scalars['Int']['input']>>;
statusType?: InputMaybe<Array<MetricsStatusType>>;
};
export enum MetricsRequestMethod {
Delete = 'DELETE',
Get = 'GET',
Options = 'OPTIONS',
Post = 'POST',
Put = 'PUT'
}
export enum MetricsStatusType {
ClientError = 'CLIENT_ERROR',
None = 'NONE',
Redirect = 'REDIRECT',
ServerError = 'SERVER_ERROR',
Successful = 'SUCCESSFUL'
}
export type MetricsTimespan = {
end: Scalars['DateTime']['input'];
start: Scalars['DateTime']['input'];
@@ -5234,11 +5373,19 @@ export type PublishUpdateGroupInput = {
message?: InputMaybe<Scalars['String']['input']>;
rollBackToEmbeddedInfoGroup?: InputMaybe<UpdateRollBackToEmbeddedGroup>;
rolloutInfoGroup?: InputMaybe<UpdateRolloutInfoGroup>;
runtimeFingerprintSource?: InputMaybe<FingerprintSourceInput>;
runtimeVersion: Scalars['String']['input'];
turtleJobRunId?: InputMaybe<Scalars['String']['input']>;
updateInfoGroup?: InputMaybe<UpdateInfoGroup>;
};
export enum RequestStatusPattern {
Http_2Xx = 'HTTP_2XX',
Http_3Xx = 'HTTP_3XX',
Http_4Xx = 'HTTP_4XX',
Http_5Xx = 'HTTP_5XX'
}
export type RequestsTimespan = {
end: Scalars['DateTime']['input'];
start?: InputMaybe<Scalars['DateTime']['input']>;
@@ -5250,7 +5397,8 @@ export type RescindUserInvitationResult = {
};
export enum ResourceClassExperiment {
C3D = 'C3D'
C3D = 'C3D',
N2 = 'N2'
}
/** Represents a robot (not human) actor. */
@@ -5289,8 +5437,6 @@ export type RobotMutation = {
__typename?: 'RobotMutation';
/** Create a Robot and grant it Permissions on an Account */
createRobotForAccount: Robot;
/** Delete a Robot */
deleteRobot: DeleteRobotResult;
/** Schedule deletion of a Robot */
scheduleRobotDeletion: BackgroundJobReceipt;
/** Update a Robot */
@@ -5305,11 +5451,6 @@ export type RobotMutationCreateRobotForAccountArgs = {
};
export type RobotMutationDeleteRobotArgs = {
id: Scalars['String']['input'];
};
export type RobotMutationScheduleRobotDeletionArgs = {
id: Scalars['ID']['input'];
};
@@ -5486,11 +5627,17 @@ export type RootQuery = {
/** Top-level query object for querying Audit Logs. */
auditLogs: AuditLogQuery;
backgroundJobReceipt: BackgroundJobReceiptQuery;
/** Top-level query object for querying Branchs. */
branches: BranchQuery;
/** Top-level query object for querying annotations. */
buildAnnotations: BuildAnnotationsQuery;
/** Top-level query object for querying BuildPublicData publicly. */
buildPublicData: BuildPublicDataQuery;
builds: BuildQuery;
/** Top-level query object for querying Channels. */
channels: ChannelQuery;
/** Top-level query object for querying Deployments. */
deployments: DeploymentQuery;
/** Top-level query object for querying Experimentation configuration. */
experimentation: ExperimentationQuery;
/** Top-level query object for querying GitHub App information and resources it has access to. */
@@ -5515,6 +5662,8 @@ export type RootQuery = {
meUserActor?: Maybe<UserActor>;
/** @deprecated Snacks and apps should be queried separately */
project: ProjectQuery;
/** Top-level query object for querying Runtimes. */
runtimes: RuntimeQuery;
snack: SnackQuery;
/** Top-level query object for querying Expo status page services. */
statuspageService: StatuspageServiceQuery;
@@ -5582,6 +5731,7 @@ export type RootQueryUserByUsernameArgs = {
export type Runtime = {
__typename?: 'Runtime';
app: App;
fingerprintDebugInfoUrl?: Maybe<Scalars['String']['output']>;
firstBuildCreatedAt: Scalars['DateTime']['output'];
id: Scalars['ID']['output'];
version: Scalars['String']['output'];
@@ -5598,6 +5748,17 @@ export type RuntimeFilterInput = {
branchId?: InputMaybe<Scalars['String']['input']>;
};
export type RuntimeQuery = {
__typename?: 'RuntimeQuery';
/** Query a Runtime by ID */
byId: Runtime;
};
export type RuntimeQueryByIdArgs = {
runtimeId: Scalars['ID']['input'];
};
/** Represents the connection over the runtime edge of an App */
export type RuntimesConnection = {
__typename?: 'RuntimesConnection';
@@ -6304,6 +6465,8 @@ export type UpdateChannelMutationEditUpdateChannelArgs = {
export type UpdateGitHubBuildTriggerInput = {
autoSubmit: Scalars['Boolean']['input'];
buildProfile: Scalars['String']['input'];
environment?: InputMaybe<EnvironmentVariableEnvironment>;
executionBehavior: GitHubBuildTriggerExecutionBehavior;
isActive: Scalars['Boolean']['input'];
platform: AppPlatform;
sourcePattern: Scalars['String']['input'];
@@ -6330,11 +6493,17 @@ export type UpdateInfoGroup = {
export type UpdateInsights = {
__typename?: 'UpdateInsights';
cumulativeMetricsOverTime: CumulativeMetricsOverTimeData;
id: Scalars['ID']['output'];
totalUniqueUsers: Scalars['Int']['output'];
};
export type UpdateInsightsCumulativeMetricsOverTimeArgs = {
timespan: InsightsTimespan;
};
export type UpdateInsightsTotalUniqueUsersArgs = {
timespan: InsightsTimespan;
};
@@ -6718,6 +6887,34 @@ export type UserActorQueryByUsernameArgs = {
username: Scalars['String']['input'];
};
export enum UserAgentBrowser {
AndroidMobile = 'ANDROID_MOBILE',
Chrome = 'CHROME',
ChromeIos = 'CHROME_IOS',
Edge = 'EDGE',
FacebookMobile = 'FACEBOOK_MOBILE',
Firefox = 'FIREFOX',
FirefoxIos = 'FIREFOX_IOS',
InternetExplorer = 'INTERNET_EXPLORER',
Konqueror = 'KONQUEROR',
Mozilla = 'MOZILLA',
Opera = 'OPERA',
Safari = 'SAFARI',
SafariMobile = 'SAFARI_MOBILE',
SamsungInternet = 'SAMSUNG_INTERNET',
UcBrowser = 'UC_BROWSER'
}
export enum UserAgentOs {
Android = 'ANDROID',
ChromeOs = 'CHROME_OS',
Ios = 'IOS',
IpadOs = 'IPAD_OS',
Linux = 'LINUX',
MacOs = 'MAC_OS',
Windows = 'WINDOWS'
}
export type UserAppPinMutation = {
__typename?: 'UserAppPinMutation';
pinApp: Scalars['ID']['output'];
@@ -7029,12 +7226,14 @@ export type WorkerCustomDomain = {
__typename?: 'WorkerCustomDomain';
alias: WorkerDeploymentAlias;
createdAt: Scalars['DateTime']['output'];
dcvDelegationRecord?: Maybe<CustomDomainDnsRecord>;
devDomainName: Scalars['DevDomainName']['output'];
dnsRecord: CustomDomainDnsRecord;
hostname: Scalars['String']['output'];
id: Scalars['ID']['output'];
metadata?: Maybe<CustomDomainMetadata>;
setup?: Maybe<CustomDomainSetup>;
updatedAt: Scalars['DateTime']['output'];
verificationRecord?: Maybe<CustomDomainDnsRecord>;
};
export type WorkerDeployment = {
@@ -7059,6 +7258,7 @@ export type WorkerDeploymentLogsArgs = {
export type WorkerDeploymentMetricsArgs = {
filters?: InputMaybe<MetricsFilters>;
timespan: MetricsTimespan;
};
@@ -7087,18 +7287,30 @@ export type WorkerDeploymentAliasesConnection = {
pageInfo: PageInfo;
};
export type WorkerDeploymentCrashEdge = {
__typename?: 'WorkerDeploymentCrashEdge';
logs: Array<WorkerDeploymentLogNode>;
request: WorkerDeploymentRequestNode;
sample: WorkerDeploymentCrashSample;
};
export type WorkerDeploymentCrashNode = {
__typename?: 'WorkerDeploymentCrashNode';
id: Scalars['ID']['output'];
minOccurrences: Scalars['Int']['output'];
mostRecentlyOccurredAt: Scalars['DateTime']['output'];
sample?: Maybe<WorkerDeploymentCrashSample>;
sampleMessage?: Maybe<Scalars['String']['output']>;
oldestOccurredAt: Scalars['DateTime']['output'];
sample: WorkerDeploymentCrashSample;
};
export type WorkerDeploymentCrashSample = {
__typename?: 'WorkerDeploymentCrashSample';
firstStackLine?: Maybe<Scalars['String']['output']>;
message: Scalars['String']['output'];
requestTimestamp: Scalars['DateTime']['output'];
name: Scalars['String']['output'];
scriptName: Scalars['String']['output'];
stack?: Maybe<Array<Scalars['String']['output']>>;
timestamp: Scalars['DateTime']['output'];
};
export type WorkerDeploymentCrashes = {
@@ -7137,23 +7349,79 @@ export type WorkerDeploymentLogs = {
export type WorkerDeploymentMetrics = {
__typename?: 'WorkerDeploymentMetrics';
groups: Array<Maybe<WorkerDeploymentMetricsEdge>>;
id: Scalars['ID']['output'];
summary: WorkerDeploymentMetricsData;
byBrowser: Array<WorkerDeploymentMetricsBrowserEdge>;
byContinent: Array<WorkerDeploymentMetricsContinentEdge>;
byOS: Array<WorkerDeploymentMetricsOperatingSystemEdge>;
interval: Scalars['Int']['output'];
summary: WorkerDeploymentMetricsNode;
timeseries: Array<WorkerDeploymentMetricsTimeseriesEdge>;
};
export type WorkerDeploymentMetricsData = {
__typename?: 'WorkerDeploymentMetricsData';
export type WorkerDeploymentMetricsBrowserEdge = {
__typename?: 'WorkerDeploymentMetricsBrowserEdge';
browser?: Maybe<UserAgentBrowser>;
node: WorkerDeploymentMetricsNode;
};
export type WorkerDeploymentMetricsContinentEdge = {
__typename?: 'WorkerDeploymentMetricsContinentEdge';
continent: ContinentCode;
node: WorkerDeploymentMetricsNode;
};
export type WorkerDeploymentMetricsNode = {
__typename?: 'WorkerDeploymentMetricsNode';
assetsPerMs?: Maybe<Scalars['Float']['output']>;
assetsSum: Scalars['Int']['output'];
cacheHitRatio: Scalars['Float']['output'];
cacheHitRatioP50: Scalars['Float']['output'];
cacheHitRatioP90: Scalars['Float']['output'];
cacheHitRatioP99: Scalars['Float']['output'];
cacheHitsPerMs?: Maybe<Scalars['Float']['output']>;
cacheHitsSum: Scalars['Int']['output'];
cachePassRatio: Scalars['Float']['output'];
cachePassRatioP50: Scalars['Float']['output'];
cachePassRatioP90: Scalars['Float']['output'];
cachePassRatioP99: Scalars['Float']['output'];
clientErrorRatio: Scalars['Float']['output'];
clientErrorRatioP50: Scalars['Float']['output'];
clientErrorRatioP90: Scalars['Float']['output'];
clientErrorRatioP99: Scalars['Float']['output'];
crashRatio: Scalars['Float']['output'];
crashRatioP50: Scalars['Float']['output'];
crashRatioP90: Scalars['Float']['output'];
crashRatioP99: Scalars['Float']['output'];
crashesPerMs?: Maybe<Scalars['Float']['output']>;
crashesSum: Scalars['Int']['output'];
durationP50?: Maybe<Scalars['Float']['output']>;
durationP90?: Maybe<Scalars['Float']['output']>;
durationP99?: Maybe<Scalars['Float']['output']>;
duration: Scalars['Float']['output'];
durationP50: Scalars['Float']['output'];
durationP90: Scalars['Float']['output'];
durationP99: Scalars['Float']['output'];
requestsPerMs?: Maybe<Scalars['Float']['output']>;
requestsSum: Scalars['Int']['output'];
sampleRate: Scalars['Float']['output'];
serverErrorRatio: Scalars['Float']['output'];
serverErrorRatioP50: Scalars['Float']['output'];
serverErrorRatioP90: Scalars['Float']['output'];
serverErrorRatioP99: Scalars['Float']['output'];
staleIfErrorPerMs?: Maybe<Scalars['Float']['output']>;
staleIfErrorSum: Scalars['Int']['output'];
staleWhileRevalidatePerMs?: Maybe<Scalars['Float']['output']>;
staleWhileRevalidateSum: Scalars['Int']['output'];
};
export type WorkerDeploymentMetricsEdge = {
__typename?: 'WorkerDeploymentMetricsEdge';
node: WorkerDeploymentMetricsData;
export type WorkerDeploymentMetricsOperatingSystemEdge = {
__typename?: 'WorkerDeploymentMetricsOperatingSystemEdge';
node: WorkerDeploymentMetricsNode;
os?: Maybe<UserAgentOs>;
};
export type WorkerDeploymentMetricsTimeseriesEdge = {
__typename?: 'WorkerDeploymentMetricsTimeseriesEdge';
byBrowser: Array<WorkerDeploymentMetricsBrowserEdge>;
byContinent: Array<WorkerDeploymentMetricsContinentEdge>;
byOS: Array<WorkerDeploymentMetricsOperatingSystemEdge>;
node?: Maybe<WorkerDeploymentMetricsNode>;
timestamp: Scalars['DateTime']['output'];
};
@@ -7167,6 +7435,19 @@ export type WorkerDeploymentQueryByIdArgs = {
id: Scalars['ID']['input'];
};
export type WorkerDeploymentRequestEdge = {
__typename?: 'WorkerDeploymentRequestEdge';
crash?: Maybe<WorkerDeploymentCrashSample>;
logs: Array<WorkerDeploymentLogNode>;
node: WorkerDeploymentRequestNode;
};
export enum WorkerDeploymentRequestKind {
Asset = 'ASSET',
Crash = 'CRASH',
Rejected = 'REJECTED'
}
export type WorkerDeploymentRequestLocation = {
__typename?: 'WorkerDeploymentRequestLocation';
continent?: Maybe<ContinentCode>;
@@ -7176,12 +7457,21 @@ export type WorkerDeploymentRequestLocation = {
export type WorkerDeploymentRequestNode = {
__typename?: 'WorkerDeploymentRequestNode';
browser?: Maybe<UserAgentBrowser>;
browserVersion?: Maybe<Scalars['String']['output']>;
hasCustomDomainOrigin: Scalars['Boolean']['output'];
id: Scalars['ID']['output'];
isVerifiedBot: Scalars['Boolean']['output'];
kind?: Maybe<WorkerDeploymentRequestKind>;
location?: Maybe<WorkerDeploymentRequestLocation>;
method: Scalars['String']['output'];
os?: Maybe<UserAgentOs>;
pathname: Scalars['String']['output'];
scriptName: Scalars['String']['output'];
search?: Maybe<Scalars['String']['output']>;
status: Scalars['Int']['output'];
timestamp: Scalars['DateTime']['output'];
wallTime: Scalars['Int']['output'];
};
export type WorkerDeploymentRequests = {
@@ -7190,6 +7480,20 @@ export type WorkerDeploymentRequests = {
nodes: Array<WorkerDeploymentRequestNode>;
};
export type WorkerDeploymentRequestsFilter = {
include?: InputMaybe<WorkerDeploymentRequestsInclude>;
includeBotRequests?: InputMaybe<Scalars['Boolean']['input']>;
methods?: InputMaybe<Array<Scalars['String']['input']>>;
pathname?: InputMaybe<Scalars['String']['input']>;
statusCodes?: InputMaybe<Array<Scalars['Int']['input']>>;
statusPatterns?: InputMaybe<Array<RequestStatusPattern>>;
};
export enum WorkerDeploymentRequestsInclude {
Assets = 'ASSETS',
Routes = 'ROUTES'
}
export type WorkerDeploymentsConnection = {
__typename?: 'WorkerDeploymentsConnection';
edges: Array<WorkerDeploymentEdge>;
@@ -7832,6 +8136,14 @@ export type DeleteEnvironmentVariableMutationVariables = Exact<{
export type DeleteEnvironmentVariableMutation = { __typename?: 'RootMutation', environmentVariable: { __typename?: 'EnvironmentVariableMutation', deleteEnvironmentVariable: { __typename?: 'DeleteEnvironmentVariableResult', id: string } } };
export type CreateBulkEnvironmentVariablesForAppMutationVariables = Exact<{
input: Array<CreateEnvironmentVariableInput> | CreateEnvironmentVariableInput;
appId: Scalars['ID']['input'];
}>;
export type CreateBulkEnvironmentVariablesForAppMutation = { __typename?: 'RootMutation', environmentVariable: { __typename?: 'EnvironmentVariableMutation', createBulkEnvironmentVariablesForApp: Array<{ __typename?: 'EnvironmentVariable', id: string }> } };
export type CreateKeystoreGenerationUrlMutationVariables = Exact<{ [key: string]: never; }>;
@@ -8081,6 +8393,14 @@ export type EnvironmentVariablesSharedQueryVariables = Exact<{
export type EnvironmentVariablesSharedQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, ownerAccount: { __typename?: 'Account', id: string, environmentVariables: Array<{ __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environment?: EnvironmentVariableEnvironment | null, createdAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null }> } } } };
export type EnvironmentVariablesSharedWithSensitiveQueryVariables = Exact<{
appId: Scalars['String']['input'];
filterNames?: InputMaybe<Array<Scalars['String']['input']> | Scalars['String']['input']>;
}>;
export type EnvironmentVariablesSharedWithSensitiveQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, ownerAccount: { __typename?: 'Account', id: string, environmentVariablesIncludingSensitive: Array<{ __typename?: 'EnvironmentVariableWithSecret', id: string, name: string, value?: string | null }> } } } };
export type GetAssetMetadataQueryVariables = Exact<{
storageKeys: Array<Scalars['String']['input']> | Scalars['String']['input'];
}>;
@@ -8242,3 +8562,19 @@ export type IosAppBuildCredentialsFragment = { __typename?: 'IosAppBuildCredenti
export type CommonIosAppCredentialsWithoutBuildCredentialsFragment = { __typename?: 'IosAppCredentials', id: string, app: { __typename?: 'App', id: string, name: string, fullName: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string, ownerUserActor?: { __typename?: 'SSOUser', id: string, username: string } | { __typename?: 'User', id: string, username: string } | null, users: Array<{ __typename?: 'UserPermission', role: Role, actor: { __typename?: 'Robot', id: string } | { __typename?: 'SSOUser', id: string } | { __typename?: 'User', id: string } }> }, githubRepository?: { __typename?: 'GitHubRepository', id: string, metadata: { __typename?: 'GitHubRepositoryMetadata', githubRepoOwnerName: string, githubRepoName: string } } | null }, appleTeam?: { __typename?: 'AppleTeam', id: string, appleTeamIdentifier: string, appleTeamName?: string | null } | null, appleAppIdentifier: { __typename?: 'AppleAppIdentifier', id: string, bundleIdentifier: string }, pushKey?: { __typename?: 'ApplePushKey', id: string, keyIdentifier: string, updatedAt: any, appleTeam?: { __typename?: 'AppleTeam', id: string, appleTeamIdentifier: string, appleTeamName?: string | null } | null, iosAppCredentialsList: Array<{ __typename?: 'IosAppCredentials', id: string, app: { __typename?: 'App', id: string, name: string, fullName: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string, ownerUserActor?: { __typename?: 'SSOUser', id: string, username: string } | { __typename?: 'User', id: string, username: string } | null, users: Array<{ __typename?: 'UserPermission', role: Role, actor: { __typename?: 'Robot', id: string } | { __typename?: 'SSOUser', id: string } | { __typename?: 'User', id: string } }> }, githubRepository?: { __typename?: 'GitHubRepository', id: string, metadata: { __typename?: 'GitHubRepositoryMetadata', githubRepoOwnerName: string, githubRepoName: string } } | null }, appleAppIdentifier: { __typename?: 'AppleAppIdentifier', id: string, bundleIdentifier: string } }> } | null, appStoreConnectApiKeyForSubmissions?: { __typename?: 'AppStoreConnectApiKey', id: string, issuerIdentifier: string, keyIdentifier: string, name?: string | null, roles?: Array<AppStoreConnectUserRole> | null, createdAt: any, updatedAt: any, appleTeam?: { __typename?: 'AppleTeam', id: string, appleTeamIdentifier: string, appleTeamName?: string | null } | null } | null };
export type CommonIosAppCredentialsFragment = { __typename?: 'IosAppCredentials', id: string, iosAppBuildCredentialsList: Array<{ __typename?: 'IosAppBuildCredentials', id: string, iosDistributionType: IosDistributionType, distributionCertificate?: { __typename?: 'AppleDistributionCertificate', id: string, certificateP12?: string | null, certificatePassword?: string | null, serialNumber: string, developerPortalIdentifier?: string | null, validityNotBefore: any, validityNotAfter: any, updatedAt: any, appleTeam?: { __typename?: 'AppleTeam', id: string, appleTeamIdentifier: string, appleTeamName?: string | null } | null, iosAppBuildCredentialsList: Array<{ __typename?: 'IosAppBuildCredentials', id: string, iosAppCredentials: { __typename?: 'IosAppCredentials', id: string, app: { __typename?: 'App', id: string, name: string, fullName: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string, ownerUserActor?: { __typename?: 'SSOUser', id: string, username: string } | { __typename?: 'User', id: string, username: string } | null, users: Array<{ __typename?: 'UserPermission', role: Role, actor: { __typename?: 'Robot', id: string } | { __typename?: 'SSOUser', id: string } | { __typename?: 'User', id: string } }> }, githubRepository?: { __typename?: 'GitHubRepository', id: string, metadata: { __typename?: 'GitHubRepositoryMetadata', githubRepoOwnerName: string, githubRepoName: string } } | null }, appleAppIdentifier: { __typename?: 'AppleAppIdentifier', id: string, bundleIdentifier: string } }, provisioningProfile?: { __typename?: 'AppleProvisioningProfile', id: string, developerPortalIdentifier?: string | null } | null }> } | null, provisioningProfile?: { __typename?: 'AppleProvisioningProfile', id: string, expiration: any, developerPortalIdentifier?: string | null, provisioningProfile?: string | null, updatedAt: any, status: string, appleTeam?: { __typename?: 'AppleTeam', id: string, appleTeamIdentifier: string, appleTeamName?: string | null } | null, appleDevices: Array<{ __typename?: 'AppleDevice', id: string, identifier: string, name?: string | null, model?: string | null, deviceClass?: AppleDeviceClass | null, createdAt: any }> } | null }>, app: { __typename?: 'App', id: string, name: string, fullName: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string, ownerUserActor?: { __typename?: 'SSOUser', id: string, username: string } | { __typename?: 'User', id: string, username: string } | null, users: Array<{ __typename?: 'UserPermission', role: Role, actor: { __typename?: 'Robot', id: string } | { __typename?: 'SSOUser', id: string } | { __typename?: 'User', id: string } }> }, githubRepository?: { __typename?: 'GitHubRepository', id: string, metadata: { __typename?: 'GitHubRepositoryMetadata', githubRepoOwnerName: string, githubRepoName: string } } | null }, appleTeam?: { __typename?: 'AppleTeam', id: string, appleTeamIdentifier: string, appleTeamName?: string | null } | null, appleAppIdentifier: { __typename?: 'AppleAppIdentifier', id: string, bundleIdentifier: string }, pushKey?: { __typename?: 'ApplePushKey', id: string, keyIdentifier: string, updatedAt: any, appleTeam?: { __typename?: 'AppleTeam', id: string, appleTeamIdentifier: string, appleTeamName?: string | null } | null, iosAppCredentialsList: Array<{ __typename?: 'IosAppCredentials', id: string, app: { __typename?: 'App', id: string, name: string, fullName: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string, ownerUserActor?: { __typename?: 'SSOUser', id: string, username: string } | { __typename?: 'User', id: string, username: string } | null, users: Array<{ __typename?: 'UserPermission', role: Role, actor: { __typename?: 'Robot', id: string } | { __typename?: 'SSOUser', id: string } | { __typename?: 'User', id: string } }> }, githubRepository?: { __typename?: 'GitHubRepository', id: string, metadata: { __typename?: 'GitHubRepositoryMetadata', githubRepoOwnerName: string, githubRepoName: string } } | null }, appleAppIdentifier: { __typename?: 'AppleAppIdentifier', id: string, bundleIdentifier: string } }> } | null, appStoreConnectApiKeyForSubmissions?: { __typename?: 'AppStoreConnectApiKey', id: string, issuerIdentifier: string, keyIdentifier: string, name?: string | null, roles?: Array<AppStoreConnectUserRole> | null, createdAt: any, updatedAt: any, appleTeam?: { __typename?: 'AppleTeam', id: string, appleTeamIdentifier: string, appleTeamName?: string | null } | null } | null };
export type CreateDeploymentUrlMutationVariables = Exact<{
appId: Scalars['ID']['input'];
deploymentIdentifier?: InputMaybe<Scalars['ID']['input']>;
}>;
export type CreateDeploymentUrlMutation = { __typename?: 'RootMutation', deployments: { __typename?: 'DeploymentsMutation', createSignedDeploymentUrl: { __typename?: 'DeploymentSignedUrlResult', pendingWorkerDeploymentId: string, deploymentIdentifier: string, url: string } } };
export type AssignDevDomainNameMutationVariables = Exact<{
appId: Scalars['ID']['input'];
name: Scalars['DevDomainName']['input'];
}>;
export type AssignDevDomainNameMutation = { __typename?: 'RootMutation', devDomainName: { __typename?: 'AppDevDomainNameMutation', assignDevDomainName: { __typename?: 'AppDevDomainName', id: string, name: any } } };
@@ -4,6 +4,7 @@ import gql from 'graphql-tag';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
import { withErrorHandlingAsync } from '../client';
import {
CreateBulkEnvironmentVariablesForAppMutation,
CreateEnvironmentVariableForAccountMutation,
CreateEnvironmentVariableForAppMutation,
DeleteEnvironmentVariableMutation,
@@ -196,4 +197,34 @@ export const EnvironmentVariableMutation = {
return data.environmentVariable.deleteEnvironmentVariable;
},
async createBulkEnvironmentVariablesForAppAsync(
graphqlClient: ExpoGraphqlClient,
input: EnvironmentVariablePushInput[],
appId: string
): Promise<boolean> {
await withErrorHandlingAsync(
graphqlClient
.mutation<CreateBulkEnvironmentVariablesForAppMutation>(
gql`
mutation CreateBulkEnvironmentVariablesForApp(
$input: [CreateEnvironmentVariableInput!]!
$appId: ID!
) {
environmentVariable {
createBulkEnvironmentVariablesForApp(
environmentVariablesData: $input
appId: $appId
) {
id
}
}
}
`,
{ input, appId }
)
.toPromise()
);
return true;
},
};
@@ -4,7 +4,6 @@ import gql from 'graphql-tag';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
import { withErrorHandlingAsync } from '../client';
import {
EnvironmentVariableEnvironment,
EnvironmentVariableFragment,
EnvironmentVariablesByAppIdQuery,
EnvironmentVariablesSharedQuery,
@@ -21,12 +20,10 @@ export const EnvironmentVariablesQuery = {
filterNames,
}: {
appId: string;
environment: EnvironmentVariableEnvironment;
environment: string;
filterNames?: string[];
}
): Promise<{
appVariables: EnvironmentVariableFragment[];
}> {
): Promise<EnvironmentVariableFragment[]> {
const data = await withErrorHandlingAsync(
graphqlClient
.query(
@@ -52,20 +49,24 @@ export const EnvironmentVariablesQuery = {
}
`,
{ appId, filterNames, environment },
{ additionalTypenames: ['EnvironmentVariable'] }
{ additionalTypenames: ['EnvironmentVariableWithSecret'] }
)
.toPromise()
);
return {
appVariables: data.app?.byId.environmentVariablesIncludingSensitive ?? [],
};
return data.app?.byId.environmentVariablesIncludingSensitive ?? [];
},
async byAppIdAsync(
graphqlClient: ExpoGraphqlClient,
appId: string,
environment: string,
filterNames?: string[]
{
appId,
environment,
filterNames,
}: {
appId: string;
environment: string;
filterNames?: string[];
}
): Promise<EnvironmentVariableFragment[]> {
const data = await withErrorHandlingAsync(
graphqlClient
@@ -98,8 +99,7 @@ export const EnvironmentVariablesQuery = {
},
async sharedAsync(
graphqlClient: ExpoGraphqlClient,
appId: string,
filterNames?: string[]
{ appId, filterNames }: { appId: string; filterNames?: string[] }
): Promise<EnvironmentVariableFragment[]> {
const data = await withErrorHandlingAsync(
graphqlClient
@@ -129,4 +129,39 @@ export const EnvironmentVariablesQuery = {
return data.app?.byId.ownerAccount.environmentVariables ?? [];
},
async sharedWithSensitiveAsync(
graphqlClient: ExpoGraphqlClient,
{ appId, filterNames }: { appId: string; filterNames?: string[] }
): Promise<EnvironmentVariableFragment[]> {
const data = await withErrorHandlingAsync(
graphqlClient
.query(
gql`
query EnvironmentVariablesSharedWithSensitive(
$appId: String!
$filterNames: [String!]
) {
app {
byId(appId: $appId) {
id
ownerAccount {
id
environmentVariablesIncludingSensitive(filterNames: $filterNames) {
id
name
value
}
}
}
}
}
`,
{ appId, filterNames },
{ additionalTypenames: ['EnvironmentVariableWithSecret'] }
)
.toPromise()
);
return data.app?.byId.ownerAccount.environmentVariablesIncludingSensitive ?? [];
},
};
@@ -1,5 +1,5 @@
import { ExpoConfig } from '@expo/config';
import { Platform, Workflow } from '@expo/eas-build-job';
import { Env, Platform, Workflow } from '@expo/eas-build-job';
import { BuildProfile } from '@expo/eas-json';
import {
@@ -26,6 +26,7 @@ export async function getApplicationIdentifierAsync({
platform,
vcsClient,
nonInteractive,
env,
}: {
graphqlClient: ExpoGraphqlClient;
projectDir: string;
@@ -35,6 +36,7 @@ export async function getApplicationIdentifierAsync({
platform: Platform;
vcsClient: Client;
nonInteractive: boolean;
env: Env;
}): Promise<string> {
if (platform === Platform.ANDROID) {
const profile = buildProfile as BuildProfile<Platform.ANDROID>;
@@ -71,11 +73,12 @@ export async function getApplicationIdentifierAsync({
{ exp, projectDir, nonInteractive: false, vcsClient },
profile
);
const targets = await resolveTargetsAsync({
projectDir,
exp,
xcodeBuildContext,
env: profile.env,
env,
vcsClient,
});
const applicationTarget = findApplicationTarget(targets);
+1 -1
View File
@@ -189,7 +189,7 @@ async function resolveBareProjectDependenciesAsync({
}
);
const entitlements = await getNativeTargetEntitlementsAsync(projectDir, {
targetName: target.name,
targetName: dependency.name,
buildConfiguration,
});
result.push({
@@ -0,0 +1,79 @@
import { FingerprintSource, FingerprintSourceType } from '@expo/eas-build-job';
import fs from 'fs-extra';
import path from 'path';
import { v4 as uuidv4 } from 'uuid';
import { LocalBuildMode } from '../build/local';
import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
import { UploadSessionType } from '../graphql/generated';
import Log from '../log';
import { uploadFileAtPathToGCSAsync } from '../uploads';
import { getTmpDirectory } from '../utils/paths';
export async function maybeUploadFingerprintAsync({
runtimeVersion,
fingerprint,
graphqlClient,
localBuildMode,
}: {
runtimeVersion: string;
fingerprint: {
fingerprintSources: object[];
isDebugFingerprintSource: boolean;
};
graphqlClient: ExpoGraphqlClient;
localBuildMode?: LocalBuildMode;
}): Promise<{
runtimeVersion: string;
fingerprintSource?: FingerprintSource;
}> {
await fs.mkdirp(getTmpDirectory());
const fingerprintLocation = path.join(getTmpDirectory(), `${uuidv4()}-runtime-fingerprint.json`);
await fs.writeJSON(fingerprintLocation, {
hash: runtimeVersion,
sources: fingerprint.fingerprintSources,
});
if (localBuildMode === LocalBuildMode.LOCAL_BUILD_PLUGIN) {
return {
runtimeVersion,
fingerprintSource: {
type: FingerprintSourceType.PATH,
path: fingerprintLocation,
isDebugFingerprint: fingerprint.isDebugFingerprintSource,
},
};
}
let fingerprintGCSBucketKey = undefined;
try {
fingerprintGCSBucketKey = await uploadFileAtPathToGCSAsync(
graphqlClient,
UploadSessionType.EasUpdateFingerprint,
fingerprintLocation
);
} catch (err: any) {
let errMessage = 'Failed to upload fingerprint to EAS';
if (err.message) {
errMessage += `\n\nReason: ${err.message}`;
}
Log.warn(errMessage);
return {
runtimeVersion,
};
} finally {
await fs.remove(fingerprintLocation);
}
return {
runtimeVersion,
fingerprintSource: {
type: FingerprintSourceType.GCS,
bucketKey: fingerprintGCSBucketKey,
isDebugFingerprint: fingerprint.isDebugFingerprintSource,
},
};
}
+74 -47
View File
@@ -13,6 +13,7 @@ import path from 'path';
import promiseLimit from 'promise-limit';
import { isModernExpoUpdatesCLIWithRuntimeVersionCommandSupportedAsync } from './projectUtils';
import { resolveRuntimeVersionUsingCLIAsync } from './resolveRuntimeVersionAsync';
import { selectBranchOnAppAsync } from '../branch/queries';
import { getDefaultBranchNameAsync } from '../branch/utils';
import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
@@ -42,12 +43,10 @@ import {
shouldUseVersionedExpoCLI,
shouldUseVersionedExpoCLIWithExplicitPlatforms,
} from '../utils/expoCli';
import {
ExpoUpdatesCLIModuleNotFoundError,
expoUpdatesCommandAsync,
} from '../utils/expoUpdatesCli';
import { ExpoUpdatesCLIModuleNotFoundError } from '../utils/expoUpdatesCli';
import chunk from '../utils/expodash/chunk';
import { truthy } from '../utils/expodash/filter';
import groupBy from '../utils/expodash/groupBy';
import uniqBy from '../utils/expodash/uniqBy';
import { Client } from '../vcs/vcs';
@@ -698,7 +697,15 @@ export async function getUpdateMessageForCommandAsync(
export const defaultPublishPlatforms: UpdatePublishPlatform[] = ['android', 'ios'];
export async function getRuntimeVersionObjectAsync({
export type RuntimeVersionInfo = {
runtimeVersion: string;
fingerprint: {
fingerprintSources: object[];
isDebugFingerprintSource: boolean;
} | null;
};
export async function getRuntimeVersionInfoObjectsAsync({
exp,
platforms,
workflows,
@@ -710,12 +717,17 @@ export async function getRuntimeVersionObjectAsync({
workflows: Record<ExpoConfigPlatform, Workflow>;
projectDir: string;
env: Env | undefined;
}): Promise<{ platform: UpdatePublishPlatform; runtimeVersion: string }[]> {
}): Promise<
{
platform: UpdatePublishPlatform;
runtimeVersionInfo: RuntimeVersionInfo;
}[]
> {
return await Promise.all(
platforms.map(async platform => {
return {
platform,
runtimeVersion: await getRuntimeVersionForPlatformAsync({
runtimeVersionInfo: await getRuntimeVersionInfoForPlatformAsync({
exp,
platform,
workflow: workflows[platform],
@@ -727,7 +739,7 @@ export async function getRuntimeVersionObjectAsync({
);
}
async function getRuntimeVersionForPlatformAsync({
async function getRuntimeVersionInfoForPlatformAsync({
exp,
platform,
workflow,
@@ -739,29 +751,31 @@ async function getRuntimeVersionForPlatformAsync({
workflow: Workflow;
projectDir: string;
env: Env | undefined;
}): Promise<string> {
}): Promise<{
runtimeVersion: string;
fingerprint: {
fingerprintSources: object[];
isDebugFingerprintSource: boolean;
} | null;
}> {
if (await isModernExpoUpdatesCLIWithRuntimeVersionCommandSupportedAsync(projectDir)) {
try {
Log.debug('Using expo-updates runtimeversion:resolve CLI for runtime version resolution');
const extraArgs = Log.isDebug ? ['--debug'] : [];
const resolvedRuntimeVersionJSONResult = await expoUpdatesCommandAsync(
const runtimeVersionResult = await resolveRuntimeVersionUsingCLIAsync({
platform,
workflow,
projectDir,
['runtimeversion:resolve', '--platform', platform, '--workflow', workflow, ...extraArgs],
{ env }
);
const runtimeVersionResult = JSON.parse(resolvedRuntimeVersionJSONResult);
env,
});
Log.debug('runtimeversion:resolve output:');
Log.debug(resolvedRuntimeVersionJSONResult);
return nullthrows(
runtimeVersionResult.runtimeVersion,
`Unable to determine runtime version for ${
requestedPlatformDisplayNames[platform]
}. ${learnMore('https://docs.expo.dev/eas-update/runtime-versions/')}`
);
return {
...runtimeVersionResult,
runtimeVersion: nullthrows(
runtimeVersionResult.runtimeVersion,
`Unable to determine runtime version for ${
requestedPlatformDisplayNames[platform]
}. ${learnMore('https://docs.expo.dev/eas-update/runtime-versions/')}`
),
};
} catch (e: any) {
// if it's a known set of errors thrown by the CLI it means that we need to default back to the
// previous behavior, otherwise we throw the error since something is wrong
@@ -791,23 +805,37 @@ async function getRuntimeVersionForPlatformAsync({
);
}
return resolvedRuntimeVersion;
return {
runtimeVersion: resolvedRuntimeVersion,
fingerprint: null,
};
}
export function getRuntimeToPlatformMappingFromRuntimeVersions(
runtimeVersions: { platform: UpdatePublishPlatform; runtimeVersion: string }[]
): { runtimeVersion: string; platforms: UpdatePublishPlatform[] }[] {
const runtimeToPlatformMapping: { runtimeVersion: string; platforms: UpdatePublishPlatform[] }[] =
[];
for (const runtime of runtimeVersions) {
const platforms = runtimeVersions
.filter(({ runtimeVersion }) => runtimeVersion === runtime.runtimeVersion)
.map(({ platform }) => platform);
if (!runtimeToPlatformMapping.find(item => item.runtimeVersion === runtime.runtimeVersion)) {
runtimeToPlatformMapping.push({ runtimeVersion: runtime.runtimeVersion, platforms });
export function getRuntimeToPlatformsAndFingerprintInfoMappingFromRuntimeVersionInfoObjects(
runtimeVersionInfoObjects: {
platform: UpdatePublishPlatform;
runtimeVersionInfo: RuntimeVersionInfo;
}[]
): (RuntimeVersionInfo & { platforms: UpdatePublishPlatform[] })[] {
const groupedRuntimeVersionInfoObjects = groupBy(
runtimeVersionInfoObjects,
runtimeVersionInfoObject => runtimeVersionInfoObject.runtimeVersionInfo.runtimeVersion
);
return Object.entries(groupedRuntimeVersionInfoObjects).map(
([runtimeVersion, runtimeVersionInfoObjects]) => {
return {
runtimeVersion,
platforms: runtimeVersionInfoObjects.map(
runtimeVersionInfoObject => runtimeVersionInfoObject.platform
),
fingerprint:
runtimeVersionInfoObjects.map(
runtimeVersionInfoObject => runtimeVersionInfoObject.runtimeVersionInfo.fingerprint
)[0] ?? null,
};
}
}
return runtimeToPlatformMapping;
);
}
export const platformDisplayNames: Record<UpdatePublishPlatform, string> = {
@@ -841,19 +869,18 @@ export async function getRuntimeToUpdateRolloutInfoGroupMappingAsync(
appId,
branchName,
rolloutPercentage,
runtimeToPlatformMapping,
runtimeToPlatformsAndFingerprintInfoMapping,
}: {
appId: string;
branchName: string;
rolloutPercentage: number;
runtimeToPlatformMapping: { runtimeVersion: string; platforms: UpdatePublishPlatform[] }[];
runtimeToPlatformsAndFingerprintInfoMapping: (RuntimeVersionInfo & {
platforms: UpdatePublishPlatform[];
})[];
}
): Promise<Map<string, UpdateRolloutInfoGroup>> {
const runtimeToPlatformsMap = new Map(
runtimeToPlatformMapping.map<[string, UpdatePublishPlatform[]]>(r => [
r.runtimeVersion,
r.platforms,
])
runtimeToPlatformsAndFingerprintInfoMapping.map(r => [r.runtimeVersion, r.platforms])
);
return await mapMapAsync(runtimeToPlatformsMap, async (platforms, runtimeVersion) => {
return Object.fromEntries(
@@ -1,17 +1,32 @@
import { ExpoConfig } from '@expo/config';
import { Platform } from '@expo/eas-build-job';
import { AppVersionSource, EasJson, EasJsonAccessor, EasJsonUtils } from '@expo/eas-json';
import { Errors } from '@oclif/core';
import chalk from 'chalk';
import Log from '../log';
import { confirmAsync } from '../prompts';
import { BuildFlags } from '../build/types';
import Log, { learnMore } from '../log';
import { confirmAsync, selectAsync } from '../prompts';
import { ProfileData } from '../utils/profiles';
export enum AppVersionSourceUpdateOption {
SET_TO_REMOTE,
SET_TO_LOCAL,
ABORT,
}
export async function ensureVersionSourceIsRemoteAsync(
easJsonAccessor: EasJsonAccessor,
{ nonInteractive }: { nonInteractive: boolean }
): Promise<void> {
const easJsonCliConfig = await EasJsonUtils.getCliConfigAsync(easJsonAccessor);
let easJsonCliConfig = await EasJsonUtils.getCliConfigAsync(easJsonAccessor);
if (easJsonCliConfig?.appVersionSource === undefined) {
easJsonCliConfig = await ensureAppVersionSourceIsSetAsync(
easJsonAccessor,
easJsonCliConfig ?? undefined,
nonInteractive
);
}
if (easJsonCliConfig?.appVersionSource === AppVersionSource.REMOTE) {
return;
}
@@ -45,10 +60,31 @@ export async function ensureVersionSourceIsRemoteAsync(
Log.withTick('Updated eas.json');
}
export function validateBuildProfileVersionSettings(
export async function validateBuildProfileVersionSettingsAsync(
profileInfo: ProfileData<'build'>,
cliConfig: EasJson['cli']
): void {
cliConfig: EasJson['cli'],
projectDir: string,
flags: BuildFlags
): Promise<void> {
if (
cliConfig?.appVersionSource === undefined &&
profileInfo.profile.autoIncrement !== 'version'
) {
if (profileInfo.profile.autoIncrement !== true) {
Log.warn(
`The field "cli.appVersionSource" is not set, but it will be required in the future. ${learnMore(
'https://docs.expo.dev/build-reference/app-versions/'
)}`
);
} else {
const easJsonAccessor = EasJsonAccessor.fromProjectPath(projectDir);
cliConfig = await ensureAppVersionSourceIsSetAsync(
easJsonAccessor,
cliConfig,
flags.nonInteractive
);
}
}
if (cliConfig?.appVersionSource !== AppVersionSource.REMOTE) {
return;
}
@@ -98,3 +134,96 @@ export function getBuildVersionName(platform: Platform): string {
return 'buildNumber';
}
}
export async function ensureAppVersionSourceIsSetAsync(
easJsonAccessor: EasJsonAccessor,
easJsonCliConfig: EasJson['cli'] | undefined,
nonInteractive: boolean
): Promise<EasJson['cli'] | undefined> {
let selectOption, updateEasJson;
if (nonInteractive) {
Log.warn(
`The field "cli.appVersionSource" is not set, but it will be required in the future Proceeding with the default "local" value. ${learnMore(
'https://docs.expo.dev/build-reference/app-versions/'
)}`
);
selectOption = AppVersionSourceUpdateOption.SET_TO_LOCAL;
updateEasJson = false;
} else {
Log.log(
'Since EAS CLI version `12.0.0` explicitly specifying app version source is required. Please select your app version source:'
);
Log.log(
`\t1) With the "local" app version source and "autoIncrement" option enabled, the build number/version code is sourced from local project files and incremented automatically if possible, by editing local project files. ${learnMore(
'https://docs.expo.dev/build-reference/app-versions/#local-version-source'
)}`
);
Log.log(
`\t2) With the "remote" app version source and "autoIncrement" option enabled, the build number/version code is stored on EAS servers and updated every time you create a new build. Remote auto-incrementation won't edit the version in the local project files, but instead, the new version will be injected automatically during the build process. ${learnMore(
'https://docs.expo.dev/build-reference/app-versions/#remote-version-source'
)}`
);
Log.log(
`Until now, this project has been using the "local" version source (which was the previous default). App version source can now be set for you automatically, or you can configure it manually by setting the "appVersionSource" value in your eas.json.`
);
selectOption = await selectAsync(`What would you like to do?`, [
{
title: 'Update eas.json to use the default "remote" version source (recommended)',
value: AppVersionSourceUpdateOption.SET_TO_REMOTE,
},
{
title: 'Update eas.json to use "local" version source (old behavior)',
value: AppVersionSourceUpdateOption.SET_TO_LOCAL,
},
{
title: "Don't update eas.json, abort command and configure manually",
value: AppVersionSourceUpdateOption.ABORT,
},
]);
updateEasJson = true;
}
if (selectOption === AppVersionSourceUpdateOption.SET_TO_LOCAL) {
if (updateEasJson) {
await easJsonAccessor.readRawJsonAsync();
easJsonAccessor.patch(easJsonRawObject => {
easJsonRawObject.cli = {
...easJsonRawObject?.cli,
appVersionSource: AppVersionSource.LOCAL,
};
return easJsonRawObject;
});
await easJsonAccessor.writeAsync();
}
if (easJsonCliConfig) {
easJsonCliConfig.appVersionSource = AppVersionSource.LOCAL;
}
Log.withTick('Updated eas.json');
} else if (selectOption === AppVersionSourceUpdateOption.SET_TO_REMOTE) {
if (updateEasJson) {
await easJsonAccessor.readRawJsonAsync();
easJsonAccessor.patch(easJsonRawObject => {
easJsonRawObject.cli = {
...easJsonRawObject?.cli,
appVersionSource: AppVersionSource.REMOTE,
};
return easJsonRawObject;
});
await easJsonAccessor.writeAsync();
}
if (easJsonCliConfig) {
easJsonCliConfig.appVersionSource = AppVersionSource.REMOTE;
}
Log.withTick('Updated eas.json');
} else {
Log.warn(
`You'll need to configure ${chalk.bold('appVersionSource')} manually. ${learnMore(
'https://docs.expo.dev/build-reference/app-versions/'
)}`
);
Errors.error('Aborted.', { exit: 1 });
}
return easJsonCliConfig;
}
@@ -9,6 +9,52 @@ import {
expoUpdatesCommandAsync,
} from '../utils/expoUpdatesCli';
export async function resolveRuntimeVersionUsingCLIAsync({
platform,
workflow,
projectDir,
env,
cwd,
}: {
platform: 'ios' | 'android';
workflow: Workflow;
projectDir: string;
env: Env | undefined;
cwd?: string;
}): Promise<{
runtimeVersion: string | null;
fingerprint: {
fingerprintSources: object[];
isDebugFingerprintSource: boolean;
} | null;
}> {
Log.debug('Using expo-updates runtimeversion:resolve CLI for runtime version resolution');
const useDebugFingerprintSource = Log.isDebug;
const extraArgs = useDebugFingerprintSource ? ['--debug'] : [];
const resolvedRuntimeVersionJSONResult = await expoUpdatesCommandAsync(
projectDir,
['runtimeversion:resolve', '--platform', platform, '--workflow', workflow, ...extraArgs],
{ env, cwd }
);
const runtimeVersionResult = JSON.parse(resolvedRuntimeVersionJSONResult);
Log.debug('runtimeversion:resolve output:');
Log.debug(resolvedRuntimeVersionJSONResult);
return {
runtimeVersion: runtimeVersionResult.runtimeVersion ?? null,
fingerprint: runtimeVersionResult.fingerprintSources
? {
fingerprintSources: runtimeVersionResult.fingerprintSources,
isDebugFingerprintSource: useDebugFingerprintSource,
}
: null,
};
}
export async function resolveRuntimeVersionAsync({
exp,
platform,
@@ -40,31 +86,7 @@ export async function resolveRuntimeVersionAsync({
}
try {
Log.debug('Using expo-updates runtimeversion:resolve CLI for runtime version resolution');
const useDebugFingerprintSource = Log.isDebug;
const extraArgs = useDebugFingerprintSource ? ['--debug'] : [];
const resolvedRuntimeVersionJSONResult = await expoUpdatesCommandAsync(
projectDir,
['runtimeversion:resolve', '--platform', platform, '--workflow', workflow, ...extraArgs],
{ env, cwd }
);
const runtimeVersionResult = JSON.parse(resolvedRuntimeVersionJSONResult);
Log.debug('runtimeversion:resolve output:');
Log.debug(resolvedRuntimeVersionJSONResult);
return {
runtimeVersion: runtimeVersionResult.runtimeVersion ?? null,
fingerprint: runtimeVersionResult.fingerprintSources
? {
fingerprintSources: runtimeVersionResult.fingerprintSources,
isDebugFingerprintSource: useDebugFingerprintSource,
}
: null,
};
return await resolveRuntimeVersionUsingCLIAsync({ platform, workflow, projectDir, env, cwd });
} catch (e: any) {
// if expo-updates is not installed, there's no need for a runtime version in the build
if (e instanceof ExpoUpdatesCLIModuleNotFoundError) {
+149
View File
@@ -0,0 +1,149 @@
import { Gzip, GzipOptions } from 'minizlib';
import { HashOptions, createHash, randomBytes } from 'node:crypto';
import fs, { createWriteStream } from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { pipeline } from 'node:stream/promises';
import { pack } from 'tar-stream';
/** Returns whether a file or folder is ignored */
function isIgnoredName(name: string): boolean {
switch (name) {
// macOS system files
case '.DS_Store':
case '.AppleDouble':
case '.Trashes':
case '__MACOSX':
case '.LSOverride':
return true;
default:
// Backup file name convention
return name.endsWith('~');
}
}
/** Creates a temporary file write path */
async function createTempWritePathAsync(): Promise<string> {
const basename = path.basename(__filename, path.extname(__filename));
const tmpdir = await fs.promises.realpath(os.tmpdir());
const random = randomBytes(4).toString('hex');
return path.resolve(tmpdir, `tmp-${basename}-${process.pid}-${random}`);
}
/** Computes a SHA512 hash for a file */
async function computeSha512HashAsync(
filePath: fs.PathLike,
options?: HashOptions
): Promise<string> {
const hash = createHash('sha512', { encoding: 'hex', ...options });
await pipeline(fs.createReadStream(filePath), hash);
return `${hash.read()}`;
}
/** A file entry with a gzip-safe (normalized) path and a filesystem path */
interface RecursiveFileEntry {
normalizedPath: string;
path: string;
}
/** Lists plain files in base path recursively and outputs normalized paths */
function listFilesRecursively(basePath: string): AsyncGenerator<RecursiveFileEntry> {
async function* recurseAsync(parentPath?: string): AsyncGenerator<RecursiveFileEntry> {
const target = parentPath ? path.resolve(basePath, parentPath) : basePath;
const entries = await fs.promises.readdir(target, { withFileTypes: true });
for (const dirent of entries) {
const normalizedPath = parentPath ? `${parentPath}/${dirent.name}` : dirent.name;
if (isIgnoredName(dirent.name)) {
continue;
} else if (dirent.isFile()) {
yield {
normalizedPath,
path: path.resolve(target, dirent.name),
};
} else if (dirent.isDirectory()) {
yield* recurseAsync(normalizedPath);
}
}
}
return recurseAsync();
}
interface AssetMapOptions {
hashOptions?: HashOptions;
}
/** Mapping of normalized file paths to a SHA512 hash */
export type AssetMap = Record<string, string>;
/** Creates an asset map of a given target path */
async function createAssetMapAsync(
assetPath: string,
options?: AssetMapOptions
): Promise<AssetMap> {
const map: AssetMap = Object.create(null);
for await (const file of listFilesRecursively(assetPath)) {
map[file.normalizedPath] = await computeSha512HashAsync(file.path, options?.hashOptions);
}
return map;
}
interface WorkerFileEntry {
normalizedPath: string;
path: string;
data: Buffer | string;
}
/** Reads worker files while normalizing sourcemaps and providing normalized paths */
async function* listWorkerFilesAsync(workerPath: string): AsyncGenerator<WorkerFileEntry> {
for await (const file of listFilesRecursively(workerPath)) {
yield {
normalizedPath: file.normalizedPath,
path: file.path,
data: await fs.promises.readFile(file.path),
};
}
}
/** Reads files of an asset maps and enumerates normalized paths and data */
async function* listAssetMapFilesAsync(
assetPath: string,
assetMap: AssetMap
): AsyncGenerator<WorkerFileEntry> {
for (const normalizedPath in assetMap) {
const filePath = path.resolve(assetPath, normalizedPath.split('/').join(path.sep));
const data = await fs.promises.readFile(filePath);
yield {
normalizedPath,
path: filePath,
data,
};
}
}
/** Entry of a normalized (gzip-safe) path and file data */
export type FileEntry = readonly [normalizedPath: string, data: Buffer | string];
/** Packs file entries into a tar.gz file (path to tgz returned) */
async function packFilesIterableAsync(
iterable: Iterable<FileEntry> | AsyncIterable<FileEntry>,
options?: GzipOptions
): Promise<string> {
const writePath = `${await createTempWritePathAsync()}.tar.gz`;
const write = createWriteStream(writePath);
const gzip = new Gzip({ portable: true, ...options });
const tar = pack();
const writeTask$ = pipeline(tar, gzip, write);
for await (const file of iterable) {
tar.entry({ name: file[0], type: 'file' }, file[1]);
}
tar.finalize();
await writeTask$;
return writePath;
}
export {
createAssetMapAsync,
listWorkerFilesAsync,
listAssetMapFilesAsync,
packFilesIterableAsync,
};
+89
View File
@@ -0,0 +1,89 @@
import { ExpoConfig } from '@expo/config-types';
import { CombinedError as GraphqlError } from '@urql/core';
import { DeploymentsMutation } from './mutations';
import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
import Log from '../log';
import { promptAsync } from '../prompts';
export async function getSignedDeploymentUrlAsync(
graphqlClient: ExpoGraphqlClient,
exp: ExpoConfig,
deploymentVariables: {
appId: string;
deploymentIdentifier?: string | null;
}
): Promise<string> {
try {
return await DeploymentsMutation.createSignedDeploymentUrlAsync(
graphqlClient,
deploymentVariables
);
} catch (error: any) {
const isMissingDevDomain = (error as GraphqlError)?.graphQLErrors?.some(e =>
['APP_NO_DEV_DOMAIN_NAME'].includes(e?.extensions?.errorCode as string)
);
if (!isMissingDevDomain) {
throw error;
}
await chooseDevDomainNameAsync({
graphqlClient,
appId: deploymentVariables.appId,
slug: exp.slug,
});
return await DeploymentsMutation.createSignedDeploymentUrlAsync(
graphqlClient,
deploymentVariables
);
}
}
async function chooseDevDomainNameAsync({
graphqlClient,
appId,
slug,
}: {
graphqlClient: ExpoGraphqlClient;
appId: string;
slug: string;
}): Promise<void> {
const validationMessage = 'The project does not have a dev domain name.';
const { name } = await promptAsync({
type: 'text',
name: 'name',
message: 'Choose a dev domain name for your project:',
validate: value => (value && value.length > 3 ? true : validationMessage),
initial: slug,
});
if (!name) {
throw new Error('Prompt failed');
}
try {
const success = await DeploymentsMutation.assignDevDomainNameAsync(graphqlClient, {
appId,
name,
});
if (!success) {
throw new Error('Failed to assign dev domain name');
}
} catch (error: any) {
const isChosenNameTaken = (error as GraphqlError)?.graphQLErrors?.some(e =>
['DEV_DOMAIN_NAME_TAKEN'].includes(e?.extensions?.errorCode as string)
);
if (isChosenNameTaken) {
Log.error(`The entered dev domain name "${name}" is taken. Choose a different name.`);
await chooseDevDomainNameAsync({ graphqlClient, appId, slug });
}
if (!isChosenNameTaken) {
throw error;
}
}
}
+71
View File
@@ -0,0 +1,71 @@
import assert from 'assert';
import gql from 'graphql-tag';
import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
import { withErrorHandlingAsync } from '../graphql/client';
import {
AssignDevDomainNameMutation,
AssignDevDomainNameMutationVariables,
CreateDeploymentUrlMutation,
CreateDeploymentUrlMutationVariables,
} from '../graphql/generated';
export const DeploymentsMutation = {
async createSignedDeploymentUrlAsync(
graphqlClient: ExpoGraphqlClient,
deploymentVariables: {
appId: string;
deploymentIdentifier?: string | null;
}
): Promise<string> {
const data = await withErrorHandlingAsync(
graphqlClient
.mutation<CreateDeploymentUrlMutation, CreateDeploymentUrlMutationVariables>(
gql`
mutation createDeploymentUrlMutation($appId: ID!, $deploymentIdentifier: ID) {
deployments {
createSignedDeploymentUrl(
appId: $appId
deploymentIdentifier: $deploymentIdentifier
) {
pendingWorkerDeploymentId
deploymentIdentifier
url
}
}
}
`,
deploymentVariables
)
.toPromise()
);
const url = data.deployments?.createSignedDeploymentUrl.url;
assert(url, 'Deployment URL must be defined');
return url;
},
async assignDevDomainNameAsync(
graphqlClient: ExpoGraphqlClient,
devDomainNameVariables: { appId: string; name: string }
): Promise<boolean> {
const data = await withErrorHandlingAsync(
graphqlClient
.mutation<AssignDevDomainNameMutation, AssignDevDomainNameMutationVariables>(
gql`
mutation AssignDevDomainName($appId: ID!, $name: DevDomainName!) {
devDomainName {
assignDevDomainName(appId: $appId, name: $name) {
id
name
}
}
}
`,
devDomainNameVariables
)
.toPromise()
);
return data.devDomainName.assignDevDomainName.name === devDomainNameVariables.name;
},
};
+177
View File
@@ -0,0 +1,177 @@
import * as https from 'https';
import createHttpsProxyAgent from 'https-proxy-agent';
import mime from 'mime';
import { Gzip } from 'minizlib';
import fetch, { Headers, HeadersInit, RequestInit, Response } from 'node-fetch';
import fs, { createReadStream } from 'node:fs';
import path from 'node:path';
import promiseRetry from 'promise-retry';
const MAX_RETRIES = 4;
const MAX_CONCURRENCY = 10;
const MIN_RETRY_TIMEOUT = 100;
const MAX_UPLOAD_SIZE = 5e8; // 5MB
const MIN_COMPRESSION_SIZE = 5e4; // 50kB
const isCompressible = (contentType: string | null, size: number): boolean => {
if (size < MIN_COMPRESSION_SIZE) {
// Don't compress small files
return false;
} else if (contentType && /^(?:audio|video|image)\//i.test(contentType)) {
// Never compress images, audio, or videos as they're presumably precompressed
return false;
} else if (contentType && /^application\//i.test(contentType)) {
// Only compress `application/` files if they're marked as XML/JSON/JS
return /(?:xml|json5?|javascript)$/i.test(contentType);
} else {
return true;
}
};
export interface UploadParams extends Omit<RequestInit, 'signal' | 'body'> {
filePath: string;
compress?: boolean;
url: string;
method?: string;
headers?: HeadersInit;
body?: undefined;
signal?: AbortSignal;
}
export interface UploadResult {
params: UploadParams;
response: Response;
}
let sharedAgent: https.Agent | undefined;
const getAgent = (): https.Agent => {
if (sharedAgent) {
return sharedAgent;
} else if (process.env.https_proxy) {
return (sharedAgent = createHttpsProxyAgent(process.env.https_proxy));
} else {
return (sharedAgent = new https.Agent({
keepAlive: true,
maxSockets: MAX_CONCURRENCY,
maxTotalSockets: MAX_CONCURRENCY,
scheduling: 'lifo',
timeout: 4_000,
}));
}
};
export async function uploadAsync(params: UploadParams): Promise<UploadResult> {
const {
filePath,
signal,
compress,
method = 'POST',
url,
headers: headersInit,
...requestInit
} = params;
const stat = await fs.promises.stat(params.filePath);
if (stat.size > MAX_UPLOAD_SIZE) {
throw new Error(
`Upload of "${params.filePath}" aborted: File size is greater than the upload limit (>500MB)`
);
}
const contentType = mime.getType(path.basename(params.filePath));
return await promiseRetry(
async retry => {
const headers = new Headers(headersInit);
if (contentType) {
headers.set('content-type', contentType);
}
let bodyStream: NodeJS.ReadableStream = createReadStream(filePath);
if (compress && isCompressible(contentType, stat.size)) {
const gzip = new Gzip({ portable: true });
bodyStream.on('error', error => gzip.emit('error', error));
// @ts-expect-error: Gzip implements a Readable-like interface
bodyStream = bodyStream.pipe(gzip) as NodeJS.ReadableStream;
headers.set('content-encoding', 'gzip');
}
let response: Response;
try {
response = await fetch(params.url, {
...requestInit,
method,
body: bodyStream,
headers,
agent: getAgent(),
// @ts-expect-error: Internal types don't match
signal,
});
} catch (error) {
return retry(error);
}
if (
response.status === 408 ||
response.status === 409 ||
response.status === 429 ||
(response.status >= 500 && response.status <= 599)
) {
const message = `Upload of "${filePath}" failed: ${response.statusText}`;
const text = await response.text().catch(() => null);
return retry(new Error(text ? `${message}\n${text}` : message));
} else if (response.status === 413) {
const message = `Upload of "${filePath}" failed: File size exceeded the upload limit`;
throw new Error(message);
} else if (!response.ok) {
throw new Error(`Upload of "${filePath}" failed: ${response.statusText}`);
}
return {
params,
response,
};
},
{
retries: MAX_RETRIES,
minTimeout: MIN_RETRY_TIMEOUT,
randomize: true,
factor: 2,
}
);
}
export interface UploadPending {
params: UploadParams;
}
export type BatchUploadSignal = UploadResult | UploadPending;
export async function* batchUploadAsync(
uploads: readonly UploadParams[]
): AsyncGenerator<BatchUploadSignal> {
const controller = new AbortController();
const queue = new Set<Promise<UploadResult>>();
try {
let index = 0;
while (index < uploads.length || queue.size > 0) {
while (queue.size < MAX_CONCURRENCY && index < uploads.length) {
const uploadParams = uploads[index++];
let uploadPromise: Promise<UploadResult>;
queue.add(
(uploadPromise = uploadAsync({ ...uploadParams, signal: controller.signal }).finally(() =>
queue.delete(uploadPromise)
))
);
yield { params: uploadParams };
}
yield await Promise.race(queue);
}
} catch (error: any) {
if (typeof error !== 'object' || error.name !== 'AbortError') {
throw error;
}
} finally {
if (queue.size > 0) {
controller.abort();
}
}
}
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "@expo/eas-json",
"description": "A library for interacting with eas.json",
"version": "11.0.0",
"version": "12.0.0",
"author": "Expo <[email protected]>",
"bugs": "https://github.com/expo/eas-cli/issues",
"dependencies": {
"@babel/code-frame": "7.23.5",
"@expo/eas-build-job": "1.0.130",
"@expo/eas-build-job": "1.0.133",
"chalk": "4.1.2",
"env-string": "1.0.1",
"fs-extra": "11.2.0",
Generated
+269 -145
View File
@@ -1359,10 +1359,10 @@
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.56.0.tgz#ef20350fec605a7f7035a01764731b2de0f3782b"
integrity sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==
"@expo/apple-utils@1.7.1":
version "1.7.1"
resolved "https://registry.yarnpkg.com/@expo/apple-utils/-/apple-utils-1.7.1.tgz#b072cc95ace4fed734d088740eff9945e8f4d22e"
integrity sha512-oKHKRMfpPsVIlMSwHsartqrFhxKR1PnwGzaM3i+d4/g9XE9A+bKMu5YIUT4IXX561E0YYoaeaRHuxiIzcmEmRw==
"@expo/apple-utils@1.8.0":
version "1.8.0"
resolved "https://registry.yarnpkg.com/@expo/apple-utils/-/apple-utils-1.8.0.tgz#8a359cefbad000be66caa18235ecd4c03406a15d"
integrity sha512-JKGfPCCGko7GtLcvCj9VeyrSJGimgWsBJnR4G10kGY9sUQo3ykEgVrUBUaG2HJrCLzbeDUExmsbuZRWqJha77g==
"@expo/bunyan@^4.0.0":
version "4.0.0"
@@ -1382,58 +1382,90 @@
node-forge "^1.2.1"
nullthrows "^1.1.1"
"@expo/config-plugins@8.0.8", "@expo/config-plugins@~8.0.8":
version "8.0.8"
resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-8.0.8.tgz#294a71905a498ea02c8b79bea950b5e37ab5d748"
integrity sha512-Fvu6IO13EUw0R9WeqxUO37FkM62YJBNcZb9DyJAOgMz7Ez/vaKQGEjKt9cwT+Q6uirtCATMgaq6VWAW7YW8xXw==
"@expo/config-plugins@7.8.4":
version "7.8.4"
resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-7.8.4.tgz#533b5d536c1dc8b5544d64878b51bda28f2e1a1f"
integrity sha512-hv03HYxb/5kX8Gxv/BTI8TLc9L06WzqAfHRRXdbar4zkLcP2oTzvsLEF4/L/TIpD3rsnYa0KU42d0gWRxzPCJg==
dependencies:
"@expo/config-types" "^51.0.0-unreleased"
"@expo/config-types" "^50.0.0-alpha.1"
"@expo/fingerprint" "^0.6.0"
"@expo/json-file" "~8.3.0"
"@expo/plist" "^0.1.0"
"@expo/sdk-runtime-versions" "^1.0.0"
"@react-native/normalize-color" "^2.0.0"
chalk "^4.1.2"
debug "^4.3.1"
find-up "~5.0.0"
getenv "^1.0.0"
glob "7.1.6"
resolve-from "^5.0.0"
semver "^7.5.4"
semver "^7.5.3"
slash "^3.0.0"
slugify "^1.6.6"
xcode "^3.0.1"
xml2js "0.6.0"
"@expo/config-[email protected]", "@expo/config-types@^51.0.0-unreleased":
version "51.0.2"
resolved "https://registry.yarnpkg.com/@expo/config-types/-/config-types-51.0.2.tgz#7385451b180d34d8f2a4eeb5feabe1fe3c5d4f32"
integrity sha512-IglkIoiDwJMY01lYkF/ZSBoe/5cR+O3+Gx6fpLFjLfgZGBTdyPkKa1g8NWoWQCk+D3cKL2MDbszT2DyRRB0YqQ==
"@expo/config-plugins@~7.8.0", "@expo/config-plugins@~7.8.2":
version "7.8.2"
resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-7.8.2.tgz#c00ce93c4d6c2cb9e345ed9cd56ceeea05ab8ddb"
integrity sha512-XM2eXA5EvcpmXFCui48+bVy8GTskYSjPf2yC+LliYv8PDcedu7+pdgmbnvH4eZCyHfTMO8/UiF+w8e5WgOEj5A==
dependencies:
"@expo/config-types" "^50.0.0-alpha.1"
"@expo/fingerprint" "^0.6.0"
"@expo/json-file" "~8.3.0"
"@expo/plist" "^0.1.0"
"@expo/sdk-runtime-versions" "^1.0.0"
"@react-native/normalize-color" "^2.0.0"
chalk "^4.1.2"
debug "^4.3.1"
find-up "~5.0.0"
getenv "^1.0.0"
glob "7.1.6"
resolve-from "^5.0.0"
semver "^7.5.3"
slash "^3.0.0"
slugify "^1.6.6"
xcode "^3.0.1"
xml2js "0.6.0"
"@expo/config@9.0.3", "@expo/config@~9.0.0-beta.0":
version "9.0.3"
resolved "https://registry.yarnpkg.com/@expo/config/-/config-9.0.3.tgz#4bc2ec654145e6242f4b1964db2962ee0fee1270"
integrity sha512-eOTNM8eOC8gZNHgenySRlc/lwmYY1NOgvjwA8LHuvPT7/eUwD93zrxu3lPD1Cc/P6C/2BcVdfH4hf0tLmDxnsg==
"@expo/config-types@50.0.0", "@expo/config-types@^50.0.0", "@expo/config-types@^50.0.0-alpha.1":
version "50.0.0"
resolved "https://registry.yarnpkg.com/@expo/config-types/-/config-types-50.0.0.tgz#b534d3ec997ec60f8af24f6ad56244c8afc71a0b"
integrity sha512-0kkhIwXRT6EdFDwn+zTg9R2MZIAEYGn1MVkyRohAd+C9cXOb5RA8WLQi7vuxKF9m1SMtNAUrf0pO+ENK0+/KSw==
"@expo/[email protected]":
version "8.5.4"
resolved "https://registry.yarnpkg.com/@expo/config/-/config-8.5.4.tgz#bb5eb06caa36e4e35dc8c7647fae63e147b830ca"
integrity sha512-ggOLJPHGzJSJHVBC1LzwXwR6qUn8Mw7hkc5zEKRIdhFRuIQ6s2FE4eOvP87LrNfDF7eZGa6tJQYsiHSmZKG+8Q==
dependencies:
"@babel/code-frame" "~7.10.4"
"@expo/config-plugins" "~8.0.8"
"@expo/config-types" "^51.0.0-unreleased"
"@expo/json-file" "^8.3.0"
"@expo/config-plugins" "~7.8.2"
"@expo/config-types" "^50.0.0"
"@expo/json-file" "^8.2.37"
getenv "^1.0.0"
glob "7.1.6"
require-from-string "^2.0.2"
resolve-from "^5.0.0"
semver "^7.6.0"
semver "7.5.3"
slugify "^1.3.4"
sucrase "3.34.0"
"@expo/[email protected]0":
version "1.0.130"
resolved "https://registry.yarnpkg.com/@expo/eas-build-job/-/eas-build-job-1.0.130.tgz#698de0139d14cd339f9d0f37ad40a86f1e9acbc8"
integrity sha512-3amSYB9QC24ZqMjNAl/s2EHbF4Y3btKnSAafp5sp5t2g8GvU1sBZ/+rXQPKH/Ga+PcbqNT+pduGIGg4uUC7gnw==
"@expo/config@~8.5.0":
version "8.5.2"
resolved "https://registry.yarnpkg.com/@expo/config/-/config-8.5.2.tgz#4a0de82279337a37b5f1f0958711fe56e8ea31c2"
integrity sha512-UYy9kWxjQAEDwlX7gwLk0+8IxGPcHJMLnYRYtR5C5xGIV+ML7tCA+qFz1p4gHZRPkJD+k7iZyqBtyqt8xm+zXw==
dependencies:
"@expo/logger" "1.0.117"
joi "^17.13.1"
semver "^7.6.2"
zod "^3.23.8"
"@babel/code-frame" "~7.10.4"
"@expo/config-plugins" "~7.8.2"
"@expo/config-types" "^50.0.0"
"@expo/json-file" "^8.2.37"
getenv "^1.0.0"
glob "7.1.6"
require-from-string "^2.0.2"
resolve-from "^5.0.0"
semver "7.5.3"
slugify "^1.3.4"
sucrase "^3.20.0"
"@expo/[email protected]":
version "1.0.133"
@@ -1445,12 +1477,25 @@
semver "^7.6.2"
zod "^3.23.8"
"@expo/image-utils@^0.5.0":
version "0.5.1"
resolved "https://registry.yarnpkg.com/@expo/image-utils/-/image-utils-0.5.1.tgz#06fade141facebcd8431355923d30f3839309942"
integrity sha512-U/GsFfFox88lXULmFJ9Shfl2aQGcwoKPF7fawSCLixIKtMCpsI+1r0h+5i0nQnmt9tHuzXZDL8+Dg1z6OhkI9A==
"@expo/fingerprint@^0.6.0":
version "0.6.0"
resolved "https://registry.yarnpkg.com/@expo/fingerprint/-/fingerprint-0.6.0.tgz#77366934673d4ecea37284109b4dd67f9e6a7487"
integrity sha512-KfpoVRTMwMNJ/Cf5o+Ou8M/Y0EGSTqK+rbi70M2Y0K2qgWNfMJ1gm6sYO9uc8lcTr7YSYM1Rme3dk7QXhpScNA==
dependencies:
"@expo/spawn-async" "^1.7.2"
"@expo/spawn-async" "^1.5.0"
chalk "^4.1.2"
debug "^4.3.4"
find-up "^5.0.0"
minimatch "^3.0.4"
p-limit "^3.1.0"
resolve-from "^5.0.0"
"@expo/image-utils@^0.4.0":
version "0.4.1"
resolved "https://registry.yarnpkg.com/@expo/image-utils/-/image-utils-0.4.1.tgz#78c54b8aaa974d0ac37fee5285683b54ff161b2c"
integrity sha512-EZb+VHSmw+a5s2hS9qksTcWylY0FDaIAVufcxoaRS9tHIXLjW5zcKW7Rhj9dSEbZbRVy9yXXdHKa3GQdUQIOFw==
dependencies:
"@expo/spawn-async" "1.5.0"
chalk "^4.0.0"
fs-extra "9.0.0"
getenv "^1.0.0"
@@ -1458,13 +1503,13 @@
node-fetch "^2.6.0"
parse-png "^2.1.0"
resolve-from "^5.0.0"
semver "^7.6.0"
semver "7.3.2"
tempy "0.3.0"
"@expo/json-file@8.3.3", "@expo/json-file@^8.3.0":
version "8.3.3"
resolved "https://registry.yarnpkg.com/@expo/json-file/-/json-file-8.3.3.tgz#7926e3592f76030ce63d6b1308ac8f5d4d9341f4"
integrity sha512-eZ5dld9AD0PrVRiIWpRkm5aIoWBw3kAyd8VkuWEy92sEthBKDDDHAnK2a0dw0Eil6j7rK7lS/Qaq/Zzngv2h5A==
"@expo/json-file@8.2.37", "@expo/json-file@^8.2.37":
version "8.2.37"
resolved "https://registry.yarnpkg.com/@expo/json-file/-/json-file-8.2.37.tgz#9c02d3b42134907c69cc0a027b18671b69344049"
integrity sha512-YaH6rVg11JoTS2P6LsW7ybS2CULjf40AbnAHw2F1eDPuheprNjARZMnyHFPkKv7GuxCy+B9GPcbOKgc4cgA80Q==
dependencies:
"@babel/code-frame" "~7.10.4"
json5 "^2.2.2"
@@ -1496,21 +1541,21 @@
nullthrows "^1.1.1"
structured-headers "^0.4.1"
"@expo/osascript@2.1.3":
version "2.1.3"
resolved "https://registry.yarnpkg.com/@expo/osascript/-/osascript-2.1.3.tgz#912b74825cb83f3b958cad81034df9e19f1f2808"
integrity sha512-aOEkhPzDsaAfolSswObGiYW0Pf0ROfR9J2NBRLQACdQ6uJlyAMiPF45DVEVknAU9juKh0y8ZyvC9LXqLEJYohA==
"@expo/osascript@2.0.33":
version "2.0.33"
resolved "https://registry.yarnpkg.com/@expo/osascript/-/osascript-2.0.33.tgz#e9dcc8da54466c11939074aa71a006024ea884b1"
integrity sha512-FQinlwHrTlJbntp8a7NAlCKedVXe06Va/0DSLXRO8lZVtgbEMrYYSUZWQNcOlNtc58c2elNph6z9dMOYwSo3JQ==
dependencies:
"@expo/spawn-async" "^1.7.2"
"@expo/spawn-async" "^1.5.0"
exec-async "^2.2.0"
"@expo/package-manager@1.5.2":
version "1.5.2"
resolved "https://registry.yarnpkg.com/@expo/package-manager/-/package-manager-1.5.2.tgz#6015963669977a188bbbac930aa0dc103162ee73"
integrity sha512-IuA9XtGBilce0q8cyxtWINqbzMB1Fia0Yrug/O53HNuRSwQguV/iqjV68bsa4z8mYerePhcFgtvISWLAlNEbUA==
"@expo/package-manager@1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@expo/package-manager/-/package-manager-1.1.2.tgz#e58c9bed4cbb829ebf2cbb80b8542600a6609bd1"
integrity sha512-JI9XzrxB0QVXysyuJ996FPCJGDCYRkbUvgG4QmMTTMFA1T+mv8YzazC3T9C1pHQUAAveVCre1+Pqv0nZXN24Xg==
dependencies:
"@expo/json-file" "^8.3.0"
"@expo/spawn-async" "^1.7.2"
"@expo/json-file" "^8.2.37"
"@expo/spawn-async" "^1.5.0"
ansi-regex "^5.0.0"
chalk "^4.0.0"
find-up "^5.0.0"
@@ -1518,21 +1563,20 @@
js-yaml "^3.13.1"
micromatch "^4.0.2"
npm-package-arg "^7.0.0"
ora "^3.4.0"
split "^1.0.1"
sudo-prompt "9.1.1"
"@expo/pkcs12@0.1.2":
version "0.1.2"
resolved "https://registry.yarnpkg.com/@expo/pkcs12/-/pkcs12-0.1.2.tgz#9d88ed0d980e211690a9580fed425d9e3cc4c5b7"
integrity sha512-CLoOKm35mcIJHV11bR7DunfAtw0HcQ2ir7fWWCw9gwvhrhi75cer2xlLqeHPhmvXDad437Mh8L1Bz+B1EIKdMA==
"@expo/pkcs12@0.0.8":
version "0.0.8"
resolved "https://registry.yarnpkg.com/@expo/pkcs12/-/pkcs12-0.0.8.tgz#40ddde3007d90d4fd58779670f1aabfa82ce2950"
integrity sha512-VNZnmsu3PgdvZRqYLB0Ja8dNjKrgKpcqMvtUPINI4fJbF/ihDNI0A/LkHvnR2/21WRMHk2tm4QgMIkOQTfZ5kg==
dependencies:
node-forge "^1.2.1"
"@expo/plist@0.1.3":
version "0.1.3"
resolved "https://registry.yarnpkg.com/@expo/plist/-/plist-0.1.3.tgz#b4fbee2c4f7a88512a4853d85319f4d95713c529"
integrity sha512-GW/7hVlAylYg1tUrEASclw1MMk9FP4ZwyFAY/SUTJIhPDQHtfOlXREyWV3hhrHdX/K+pS73GNgdfT6E/e+kBbg==
"@expo/plist@0.0.20":
version "0.0.20"
resolved "https://registry.yarnpkg.com/@expo/plist/-/plist-0.0.20.tgz#a6b3124438031c02b762bad5a47b70584d3c0072"
integrity sha512-UXQ4LXCfTZ580LDHGJ5q62jSTwJFFJ1GqBu8duQMThiHKWbMJ+gajJh6rsB6EJ3aLUr9wcauxneL5LVRFxwBEA==
dependencies:
"@xmldom/xmldom" "~0.7.7"
base64-js "^1.2.3"
@@ -1568,21 +1612,20 @@
semver "^7.3.7"
tslib "^2.4.0"
"@expo/prebuild-config@7.0.8":
version "7.0.8"
resolved "https://registry.yarnpkg.com/@expo/prebuild-config/-/prebuild-config-7.0.8.tgz#8af72b19c92f05f1ab6c6c70d31f33159dacac39"
integrity sha512-wH9NVg6HiwF5y9x0TxiMEeBF+ITPGDXy5/i6OUheSrKpPgb0lF1Mwzl/f2fLPXBEpl+ZXOQ8LlLW32b7K9lrNg==
"@expo/prebuild-config@6.7.3":
version "6.7.3"
resolved "https://registry.yarnpkg.com/@expo/prebuild-config/-/prebuild-config-6.7.3.tgz#8444c1630bd92931c2d1a510791535b7282d8fa6"
integrity sha512-jZIHzlnvdg4Gnln06XR9tvirL3hSp/Jh48COhLKs51vb3THCWumUytZBS4DSMdvGwf8btnaB01Zg00xQhSDBsA==
dependencies:
"@expo/config" "~9.0.0-beta.0"
"@expo/config-plugins" "~8.0.8"
"@expo/config-types" "^51.0.0-unreleased"
"@expo/image-utils" "^0.5.0"
"@expo/json-file" "^8.3.0"
"@react-native/normalize-colors" "0.74.85"
"@expo/config" "~8.5.0"
"@expo/config-plugins" "~7.8.0"
"@expo/config-types" "^50.0.0-alpha.1"
"@expo/image-utils" "^0.4.0"
"@expo/json-file" "^8.2.37"
debug "^4.3.1"
fs-extra "^9.0.0"
resolve-from "^5.0.0"
semver "^7.6.0"
semver "7.5.3"
xml2js "0.6.0"
"@expo/[email protected]":
@@ -1608,19 +1651,33 @@
resolved "https://registry.yarnpkg.com/@expo/sdk-runtime-versions/-/sdk-runtime-versions-1.0.0.tgz#d7ebd21b19f1c6b0395e50d78da4416941c57f7c"
integrity sha512-Doz2bfiPndXYFPMRwPyGa1k5QaKDVpY806UJj570epIiMzWaYyCtobasyfC++qfIXVb5Ocy7r3tP9d62hAQ7IQ==
"@expo/spawn-async@1.7.2", "@expo/spawn-async@^1.7.2":
"@expo/spawn-async@1.5.0":
version "1.5.0"
resolved "https://registry.yarnpkg.com/@expo/spawn-async/-/spawn-async-1.5.0.tgz#799827edd8c10ef07eb1a2ff9dcfe081d596a395"
integrity sha512-LB7jWkqrHo+5fJHNrLAFdimuSXQ2MQ4lA7SQW5bf/HbsXuV2VrT/jN/M8f/KoWt0uJMGN4k/j7Opx4AvOOxSew==
dependencies:
cross-spawn "^6.0.5"
"@expo/[email protected]", "@expo/spawn-async@^1.5.0":
version "1.7.0"
resolved "https://registry.yarnpkg.com/@expo/spawn-async/-/spawn-async-1.7.0.tgz#3ab6082b24318cccc4e73b13464da91325555500"
integrity sha512-sqPAjOEFTrjaTybrh9SnPFLInDXcoMC06psEFmH68jLTmoipSQCq8GCEfIoHhxRDALWB+DsiwXJSbXlE/iVIIQ==
dependencies:
cross-spawn "^7.0.3"
"@expo/spawn-async@^1.7.2":
version "1.7.2"
resolved "https://registry.yarnpkg.com/@expo/spawn-async/-/spawn-async-1.7.2.tgz#fcfe66c3e387245e72154b1a7eae8cada6a47f58"
integrity sha512-QdWi16+CHB9JYP7gma19OVVg0BFkvU8zNj9GjWorYI8Iv8FUxjOCcYRuAmX4s/h91e4e7BPsskc8cSrZYho9Ew==
dependencies:
cross-spawn "^7.0.3"
"@expo/[email protected]0":
version "1.0.130"
resolved "https://registry.yarnpkg.com/@expo/steps/-/steps-1.0.130.tgz#91e05e7387f674d7c27cc610fa558e6cc2fb7ac1"
integrity sha512-ZWjrPGj8rzPVDSwxhWi2i2FWIkKUZmJCNfs0p9DSPqdUOADg7XIFSqxefxBeygZ0R2dJMEjRQA8Gz0mqjFIkiQ==
"@expo/[email protected]4":
version "1.0.134"
resolved "https://registry.yarnpkg.com/@expo/steps/-/steps-1.0.134.tgz#c7765a3fb2c0fdec458f168365b1c80cc59632cf"
integrity sha512-9WZUhq1Jggipy+cTcN/pi92I911jaOS4VoEWjuKbhp5G5HU/oHBSfR3ZapEopA9N9xzBv9I/GYzRbPiMHPXaxw==
dependencies:
"@expo/eas-build-job" "1.0.130"
"@expo/eas-build-job" "1.0.133"
"@expo/logger" "1.0.117"
"@expo/spawn-async" "^1.7.2"
arg "^5.0.2"
@@ -3405,10 +3462,10 @@
resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.0.tgz#7d8dacb7fdef0e4387caf7396cbd77f179867d06"
integrity sha512-Zwq5OCzuwJC2jwqmpEQt7Ds1DTi6BWSwoGkbb1n9pO3hzb35BoJELx7c0T23iDkBGkh2e7tvOtjF3tr3OaQHDQ==
"@react-native/normalize-color[email protected]":
version "0.74.85"
resolved "https://registry.yarnpkg.com/@react-native/normalize-colors/-/normalize-colors-0.74.85.tgz#62bcb9ab1b10b822ca0278fdfdf23d3b18e125da"
integrity sha512-pcE4i0X7y3hsAE0SpIl7t6dUc0B0NZLd1yv7ssm4FrLhWG+CGyIq4eFDXpmPU1XHmL5PPySxTAjEMiwv6tAmOw==
"@react-native/normalize-color@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@react-native/normalize-color/-/normalize-color-2.0.0.tgz#da955909432474a9a0fe1cbffc66576a0447f567"
integrity sha512-Wip/xsc5lw8vsBlmY2MO/gFLp3MvuZ2baBZjDeTjjndMgM0h5sxz7AZR62RDPGgstp8Np7JzjvVqVT7tpFZqsw==
"@repeaterjs/repeater@^3.0.4":
version "3.0.5"
@@ -3880,6 +3937,13 @@
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c"
integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==
"@types/[email protected]":
version "3.1.3"
resolved "https://registry.yarnpkg.com/@types/tar-stream/-/tar-stream-3.1.3.tgz#f61427229691eda1b7d5719f34acdc4fc8a558ce"
integrity sha512-Zbnx4wpkWBMBSu5CytMbrT5ZpMiF55qgM+EpHzR4yIDu7mv52cej8hTkOc6K+LzpkOAbxwn/m7j3iO+/l42YkQ==
dependencies:
"@types/node" "*"
"@types/[email protected]":
version "6.1.10"
resolved "https://registry.yarnpkg.com/@types/tar/-/tar-6.1.10.tgz#10b0e12129f4af5909af82a055837116ab06f860"
@@ -4266,11 +4330,6 @@ ansi-escapes@^6.0.0:
dependencies:
type-fest "^3.0.0"
ansi-regex@^4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed"
integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==
ansi-regex@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
@@ -4644,6 +4703,11 @@ axios@^1.0.0:
form-data "^4.0.0"
proxy-from-env "^1.1.0"
b4a@^1.6.4:
version "1.6.6"
resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.6.tgz#a4cc349a3851987c3c4ac2d7785c18744f6da9ba"
integrity sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==
babel-jest@^29.7.0:
version "29.7.0"
resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5"
@@ -4759,6 +4823,11 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
bare-events@^2.2.0:
version "2.4.2"
resolved "https://registry.yarnpkg.com/bare-events/-/bare-events-2.4.2.tgz#3140cca7a0e11d49b3edc5041ab560659fd8e1f8"
integrity sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==
base64-js@^1.0.2, base64-js@^1.2.3, base64-js@^1.3.1, base64-js@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
@@ -5196,7 +5265,7 @@ [email protected], chalk@^4, chalk@^4.0.2, chalk@^4.1.1, chalk@^4.1.2:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
chalk@^2.0.0, chalk@^2.0.1, chalk@^2.4.2:
chalk@^2.0.0, chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
@@ -5303,13 +5372,6 @@ [email protected], cli-cursor@^3.1.0:
dependencies:
restore-cursor "^3.1.0"
cli-cursor@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5"
integrity sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==
dependencies:
restore-cursor "^2.0.0"
[email protected], cli-progress@^3.10.0, cli-progress@^3.12.0:
version "3.12.0"
resolved "https://registry.yarnpkg.com/cli-progress/-/cli-progress-3.12.0.tgz#807ee14b66bcc086258e444ad0f19e7d42577942"
@@ -5322,11 +5384,6 @@ [email protected], cli-spinners@^2.5.0:
resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d"
integrity sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==
cli-spinners@^2.0.0:
version "2.9.2"
resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.2.tgz#1773a8f4b9c4d6ac31563df53b3fc1d79462fe41"
integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==
cli-spinners@^2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.4.0.tgz#c6256db216b878cfba4720e719cec7cf72685d7f"
@@ -7011,6 +7068,11 @@ fast-diff@^1.1.2:
resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==
fast-fifo@^1.2.0, fast-fifo@^1.3.2:
version "1.3.2"
resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c"
integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==
[email protected]:
version "3.3.2"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
@@ -7674,6 +7736,18 @@ glob@^10.2.2:
minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
path-scurry "^1.10.1"
glob@^10.3.7:
version "10.4.2"
resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.2.tgz#bed6b95dade5c1f80b4434daced233aee76160e5"
integrity sha512-GwMlUF6PkPo3Gk21UxkCohOv0PLcIXVtKyLlpEI28R/cO/4eNOdmLk3CMW1wROV/WR/EsZOWAfBbBOqYvs88/w==
dependencies:
foreground-child "^3.1.0"
jackspeak "^3.1.2"
minimatch "^9.0.4"
minipass "^7.1.2"
package-json-from-dist "^1.0.0"
path-scurry "^1.11.1"
glob@^6.0.1:
version "6.0.4"
resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22"
@@ -9013,6 +9087,15 @@ jackspeak@^2.3.5:
optionalDependencies:
"@pkgjs/parseargs" "^0.11.0"
jackspeak@^3.1.2:
version "3.4.0"
resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.0.tgz#a75763ff36ad778ede6a156d8ee8b124de445b4a"
integrity sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==
dependencies:
"@isaacs/cliui" "^8.0.2"
optionalDependencies:
"@pkgjs/parseargs" "^0.11.0"
jake@^10.8.5:
version "10.8.5"
resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.5.tgz#f2183d2c59382cb274226034543b9c03b8164c46"
@@ -9994,13 +10077,6 @@ [email protected], log-symbols@^4.1.0:
chalk "^4.1.0"
is-unicode-supported "^0.1.0"
log-symbols@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a"
integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==
dependencies:
chalk "^2.0.1"
log-symbols@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.0.0.tgz#69b3cc46d20f448eccdb75ea1fa733d9e821c920"
@@ -10051,6 +10127,11 @@ lowercase-keys@^2.0.0:
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
lru-cache@^10.2.0:
version "10.3.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.3.0.tgz#4a4aaf10c84658ab70f79a85a9a3f1e1fb11196b"
integrity sha512-CQl19J/g+Hbjbv4Y3mFNNXFEL/5t/KCg8POCuUqd4rMKjGG+j1ybER83hxV58zL+dFI1PTkt3GNFSHRt+d8qEQ==
lru-cache@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
@@ -10336,11 +10417,6 @@ [email protected]:
resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7"
integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==
mimic-fn@^1.0.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
mimic-fn@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
@@ -10536,6 +10612,19 @@ minipass@^5.0.0:
resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c"
integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==
minipass@^7.0.4, minipass@^7.1.2:
version "7.1.2"
resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707"
integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==
[email protected]:
version "3.0.1"
resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-3.0.1.tgz#46d5329d1eb3c83924eff1d3b858ca0a31581012"
integrity sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==
dependencies:
minipass "^7.0.4"
rimraf "^5.0.5"
minizlib@^2.0.0, minizlib@^2.1.1, minizlib@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931"
@@ -11269,13 +11358,6 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0:
dependencies:
wrappy "1"
onetime@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4"
integrity sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==
dependencies:
mimic-fn "^1.0.0"
onetime@^5.1.0, onetime@^5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
@@ -11318,18 +11400,6 @@ [email protected]:
strip-ansi "^6.0.0"
wcwidth "^1.0.1"
ora@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/ora/-/ora-3.4.0.tgz#bf0752491059a3ef3ed4c85097531de9fdbcd318"
integrity sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==
dependencies:
chalk "^2.4.2"
cli-cursor "^2.1.0"
cli-spinners "^2.0.0"
log-symbols "^2.2.0"
strip-ansi "^5.2.0"
wcwidth "^1.0.1"
ora@^5.4.1:
version "5.4.1"
resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18"
@@ -11484,6 +11554,11 @@ [email protected]:
dependencies:
p-reduce "^2.0.0"
package-json-from-dist@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00"
integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==
pacote@^12.0.0, pacote@^12.0.2:
version "12.0.2"
resolved "https://registry.yarnpkg.com/pacote/-/pacote-12.0.2.tgz#14ae30a81fe62ec4fc18c071150e6763e932527c"
@@ -11702,6 +11777,14 @@ path-scurry@^1.10.1, path-scurry@^1.6.1:
lru-cache "^9.1.1 || ^10.0.0"
minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
path-scurry@^1.11.1:
version "1.11.1"
resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2"
integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==
dependencies:
lru-cache "^10.2.0"
minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
[email protected]:
version "0.1.7"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
@@ -12018,6 +12101,11 @@ [email protected]:
resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=
queue-tick@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/queue-tick/-/queue-tick-1.0.1.tgz#f6f07ac82c1fd60f82e098b417a80e52f1f4c142"
integrity sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==
quick-lru@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f"
@@ -12368,14 +12456,6 @@ responselike@^2.0.0:
dependencies:
lowercase-keys "^2.0.0"
restore-cursor@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
integrity sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==
dependencies:
onetime "^2.0.0"
signal-exit "^3.0.2"
restore-cursor@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
@@ -12418,6 +12498,13 @@ rimraf@^4.4.1:
dependencies:
glob "^9.2.0"
rimraf@^5.0.5:
version "5.0.7"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-5.0.7.tgz#27bddf202e7d89cb2e0381656380d1734a854a74"
integrity sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==
dependencies:
glob "^10.3.7"
rimraf@~2.4.0:
version "2.4.5"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.4.5.tgz#ee710ce5d93a8fdb856fb5ea8ff0e2d75934b2da"
@@ -12539,6 +12626,11 @@ scuid@^1.1.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
[email protected]:
version "7.3.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938"
integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==
[email protected]:
version "7.5.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.2.tgz#5b851e66d1be07c1cdaf37dfc856f543325a2beb"
@@ -13008,6 +13100,17 @@ streamsearch@^1.1.0:
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764"
integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==
streamx@^2.15.0:
version "2.18.0"
resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.18.0.tgz#5bc1a51eb412a667ebfdcd4e6cf6a6fc65721ac7"
integrity sha512-LLUC1TWdjVdn1weXGcSxyTR3T4+acB6tVGXT95y0nGbca4t4o/ng1wKAGTljm9VicuCVLvRlqFYXYy5GwgM7sQ==
dependencies:
fast-fifo "^1.3.2"
queue-tick "^1.0.1"
text-decoder "^1.1.0"
optionalDependencies:
bare-events "^2.2.0"
[email protected], string-env-interpolation@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/string-env-interpolation/-/string-env-interpolation-1.0.1.tgz#ad4397ae4ac53fe6c91d1402ad6f6a52862c7152"
@@ -13201,13 +13304,6 @@ string_decoder@~1.1.1:
dependencies:
ansi-regex "^5.0.1"
strip-ansi@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
dependencies:
ansi-regex "^4.1.0"
strip-ansi@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532"
@@ -13316,6 +13412,18 @@ [email protected]:
pirates "^4.0.1"
ts-interface-checker "^0.1.9"
sucrase@^3.20.0:
version "3.20.1"
resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.20.1.tgz#1c055e97d0fab2f9857f02461364075b3a4ab226"
integrity sha512-BIG59HaJOxNct9Va6KvT5yzBA/rcMGetzvZyTx0ZdCcspIbpJTPS64zuAfYlJuOj+3WaI5JOdA+F0bJQQi8ZiQ==
dependencies:
commander "^4.0.0"
glob "7.1.6"
lines-and-columns "^1.1.6"
mz "^2.7.0"
pirates "^4.0.1"
ts-interface-checker "^0.1.9"
[email protected]:
version "9.1.1"
resolved "https://registry.yarnpkg.com/sudo-prompt/-/sudo-prompt-9.1.1.tgz#73853d729770392caec029e2470db9c221754db0"
@@ -13391,6 +13499,15 @@ synckit@^0.9.1:
"@pkgr/core" "^0.1.0"
tslib "^2.6.2"
[email protected]:
version "3.1.7"
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-3.1.7.tgz#24b3fb5eabada19fe7338ed6d26e5f7c482e792b"
integrity sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==
dependencies:
b4a "^1.6.4"
fast-fifo "^1.2.0"
streamx "^2.15.0"
tar-stream@~2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287"
@@ -13457,6 +13574,13 @@ test-exclude@^6.0.0:
glob "^7.1.4"
minimatch "^3.0.4"
text-decoder@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/text-decoder/-/text-decoder-1.1.0.tgz#3379e728fcf4d3893ec1aea35e8c2cac215ef190"
integrity sha512-TmLJNj6UgX8xcUZo4UDStGQtDiTzF7BzWlzn9g7UWrjkpHr5uJTK1ld16wZ3LXb2vb6jH8qU89dW5whuMdXYdw==
dependencies:
b4a "^1.6.4"
text-extensions@^1.0.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26"