Compare commits

..
14 Commits
Author SHA1 Message Date
Szymon Dziedzic 4fbc6aa3ff v12.3.0 2024-09-09 17:36:14 +02:00
Szymon Dziedzic 83bf6de727 [eas-cli] warn people if pulling secret env vars in env:pull command (#2538)
<!-- 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/C06FK950085/p1725586296781109

# How

warn people if pulling secret env vars in env:pull command

# Test Plan

![Screenshot 2024-09-06 at 15.36.44.png](https://graphite-user-uploaded-assets-prod.s3.amazonaws.com/9YRXgAETSTRMfjZ0IP35/d1ecf95a-a9f4-4d01-b24e-5b2e9ea5e31c.png)
2024-09-09 17:30:58 +02:00
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
30 changed files with 5042 additions and 6892 deletions

No files matched your search

+25 -4
View File
@@ -6,16 +6,37 @@ This is the log of notable changes to EAS CLI and related packages.
### 🛠 Breaking changes
### 🎉 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))
### 🐛 Bug fixes
### 🧹 Chores
## [11.0.3](https://github.com/expo/eas-cli/releases/tag/v11.0.3) - 2024-08-31
### 🐛 Bug fixes
+1 -1
View File
@@ -1,5 +1,5 @@
{
"npmClient": "yarn",
"version": "12.0.0",
"version": "12.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/packages/eas-cli/src/commands/analytics.ts)_
_See code: [packages/eas-cli/src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v12.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/packages/eas-cli/src/commands/config.ts)_
_See code: [packages/eas-cli/src/commands/config.ts](https://github.com/expo/eas-cli/blob/v12.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/packages/eas-cli/src/commands/diagnostics.ts)_
_See code: [packages/eas-cli/src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v12.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/packages/eas-cli/src/commands/open.ts)_
_See code: [packages/eas-cli/src/commands/open.ts](https://github.com/expo/eas-cli/blob/v12.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/packages/eas-cli/src/commands/submit.ts)_
_See code: [packages/eas-cli/src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v12.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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/v12.0.0/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.3.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:
+2490 -281
View File
File diff suppressed because it is too large. Load diff
+4 -1
View File
@@ -1,7 +1,7 @@
{
"name": "eas-cli",
"description": "EAS command line tool",
"version": "12.0.0",
"version": "12.3.0",
"author": "Expo <[email protected]>",
"bin": {
"eas": "./bin/run"
@@ -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",
+10 -55
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';
@@ -669,7 +667,7 @@ async function createAndMaybeUploadFingerprintAsync<T extends Platform>(
ctx: BuildContext<T>
): Promise<{
runtimeVersion?: string;
fingerprintSource?: Metadata['fingerprintSource'];
fingerprintSource?: FingerprintSource;
}> {
const resolvedRuntimeVersion = await resolveRuntimeVersionAsync({
exp: ctx.exp,
@@ -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,
},
};
}
@@ -4,23 +4,25 @@ 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 from '../log';
import Log, { learnMore } from '../log';
function isEnvironment(env: string): env is EnvironmentVariableEnvironment {
return Object.values(EnvironmentVariableEnvironment).includes(
env.toUpperCase() as EnvironmentVariableEnvironment
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>;
@@ -31,7 +33,13 @@ export async function evaluateConfigWithEnvVarsAsync<Config extends { projectId:
return { env: buildProfile.env ?? {}, ...config };
}
const { projectId } = await getProjectConfig({ env: buildProfile.env, ...opts });
const env = await resolveEnvVarsAsync({ flags, buildProfile, graphqlClient, projectId });
const env = await resolveEnvVarsAsync({
flags,
buildProfile,
buildProfileName,
graphqlClient,
projectId,
});
const config = await getProjectConfig({ ...opts, env });
return { env, ...config };
@@ -40,18 +48,29 @@ export async function evaluateConfigWithEnvVarsAsync<Config extends { projectId:
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 ?? process.env.EAS_CURRENT_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 };
}
@@ -63,15 +82,31 @@ async function resolveEnvVarsAsync({
environment,
}
);
const envVars = Object.fromEntries(
const serverEnvVars = Object.fromEntries(
environmentVariables
.filter(({ name, value }) => name && value)
.map(({ name, value }) => [name, value])
) as Record<string, string>;
return { ...envVars, ...buildProfile.env };
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(`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'
+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 {
@@ -197,17 +197,12 @@ export async function runBuildAndSubmitAsync(
const { env } = await evaluateConfigWithEnvVarsAsync({
flags,
buildProfile: buildProfile.profile,
buildProfileName: buildProfile.profileName,
graphqlClient,
getProjectConfig: getDynamicPrivateProjectConfigAsync,
opts: { env: buildProfile.profile.env },
});
Log.log(
`Loaded "env" configuration for the "${buildProfile.profileName}" profile: ${
env ? Object.keys(env).join(', ') : 'no environment variables specified'
}. ${learnMore('https://docs.expo.dev/build-reference/variables/')}`
);
const { build: maybeBuild, buildCtx } = await prepareAndStartBuildAsync({
projectDir,
flags,
@@ -149,6 +149,7 @@ export default class BuildResign extends EasCommand {
const { exp, projectId, env } = await evaluateConfigWithEnvVarsAsync({
flags,
buildProfile,
buildProfileName: flags.targetProfile ?? 'production',
graphqlClient,
getProjectConfig: getDynamicPrivateProjectConfigAsync,
opts: { env: buildProfile.env },
@@ -82,6 +82,7 @@ export default class BuildVersionGetView extends EasCommand {
const { exp, projectId, env } = await evaluateConfigWithEnvVarsAsync({
flags,
buildProfile: profile,
buildProfileName: flags.profile ?? 'production',
graphqlClient,
getProjectConfig: getDynamicPrivateProjectConfigAsync,
opts: { env: profile.env },
@@ -70,6 +70,7 @@ export default class BuildVersionSetView extends EasCommand {
const { exp, projectId, env } = await evaluateConfigWithEnvVarsAsync({
flags,
buildProfile: profile,
buildProfileName: flags.profile ?? 'production',
graphqlClient,
getProjectConfig: getDynamicPrivateProjectConfigAsync,
opts: { env: profile.env },
@@ -93,6 +93,7 @@ export default class BuildVersionSyncView extends EasCommand {
const { exp, projectId, env } = await evaluateConfigWithEnvVarsAsync({
flags,
buildProfile: profileInfo.profile,
buildProfileName: profileInfo.profileName,
graphqlClient,
getProjectConfig: getDynamicPrivateProjectConfigAsync,
opts: { env: profileInfo.profile.env },
+1
View File
@@ -96,6 +96,7 @@ export default class Config extends EasCommand {
const { exp: appConfig } = await evaluateConfigWithEnvVarsAsync({
flags,
buildProfile: profile,
buildProfileName: profileName,
graphqlClient,
getProjectConfig: getDynamicPublicProjectConfigAsync,
opts: { env: profile.env },
+18 -4
View File
@@ -9,7 +9,7 @@ import Log from '../../log';
import { confirmAsync } from '../../prompts';
import { promptVariableEnvironmentAsync } from '../../utils/prompts';
export default class EnvironmentValuePull extends EasCommand {
export default class EnvironmentVariablePull extends EasCommand {
static override description = 'pull env file';
static override hidden = true;
@@ -31,7 +31,7 @@ export default class EnvironmentValuePull extends EasCommand {
async runAsync(): Promise<void> {
let {
flags: { environment, path: targetPath, 'non-interactive': nonInteractive },
} = await this.parse(EnvironmentValuePull);
} = await this.parse(EnvironmentVariablePull);
if (!environment) {
environment = await promptVariableEnvironmentAsync(nonInteractive);
@@ -39,7 +39,7 @@ export default class EnvironmentValuePull extends EasCommand {
const {
privateProjectConfig: { projectId },
loggedIn: { graphqlClient },
} = await this.getContextAsync(EnvironmentValuePull, {
} = await this.getContextAsync(EnvironmentVariablePull, {
nonInteractive,
});
@@ -75,6 +75,20 @@ export default class EnvironmentValuePull extends EasCommand {
.join('\n');
await fs.writeFile(targetPath, filePrefix + envFileContent);
Log.log(`Pulled environment variables from ${environment} environment to ${targetPath}.`);
const secretEnvVariables = environmentVariables.filter(
(variable: EnvironmentVariableFragment) => variable.value === null
);
if (secretEnvVariables.length > 0) {
Log.warn(
`The eas env:pull command tried to pull environment variables with "secret" visibility. The variables with "secret" visibility are not available for reading, therefore thet were marked as "*****" in the generated .env file. Provide values for these manually in ${targetPath} if needed. Skipped variables: ${secretEnvVariables
.map(v => v.name)
.join('\n')}`
);
Log.warn();
}
Log.log(
`Pulled environment variables from ${environment.toLowerCase()} environment to ${targetPath}.`
);
}
}
+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,
}
);
}
+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}`);
}
}
+1210 -6324
View File
File diff suppressed because it is too large. Load diff
+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(
@@ -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();
}
}
}
Generated
+113
View File
@@ -3937,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"
@@ -4696,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"
@@ -4811,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"
@@ -7051,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"
@@ -7714,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"
@@ -9053,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"
@@ -10084,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"
@@ -10564,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"
@@ -11493,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"
@@ -11711,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"
@@ -12027,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"
@@ -12419,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"
@@ -13014,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"
@@ -13402,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"
@@ -13468,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"