Compare commits

...
11 Commits
Author SHA1 Message Date
Stanisław Chmiela a5d3ea8aba v13.1.1 2024-11-08 12:17:00 +01:00
Stanisław Chmiela 37f53e0976 [eas-cli] Honor EAS_NO_VCS in build:internal (#2677)
<!-- 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 need to use `build:internal` to resolve build configuration in GCS workflow jobs which have no Git repository.

# How

I'm going to be adding `EAS_NO_VCS=1` to GCS workflow jobs. This should prevent `build:internal` from requiring Git repository.

# Test Plan

I have verified `EAS_BUILD_ID=d7fb9f5c-dce0-40e2-b459-cbc05ba1ed77 EAS_NO_VCS=1 easd build:internal -p android` prints the JSON output on my computer.
2024-11-08 12:15:34 +01:00
Expo CI 97a26dce40 update CHANGELOG.md 2024-11-07 21:35:43 +00:00
Stanisław Chmiela b0b14788dd v13.1.0 2024-11-07 22:29:56 +01:00
Stanisław ChmielaandSzymon Dziedzic b81c60e8a4 [eas-cli] Add workflow:run (#2669)
<!-- If this PR requires a changelog entry, add it by commenting the PR with the command `/changelog-entry [breaking-change|new-feature|bug-fix|chore] [message]`. -->
<!-- You can skip the changelog check by labeling the PR with "no changelog". -->

# Why

We want to allow users to start workflows manually.

# How

I added a `createRunMutation` to GraphQL and used it here. We upload project archive, `eas.json` and use to start a new workflow run.

# Test Plan

```
Workflows are in beta and subject to breaking changes.

Compressing project files and uploading to EAS. Learn more: https://expo.fyi/eas-build-archive
✔ Uploaded eas.json to EAS 
✔ Uploaded project archive to EAS 1s

✔ Workflow started successfully. https://staging.expo.dev/accounts/sjchmiela/projects/staging-app/workflows/019301f1-b1b4-700d-9e3b-82dc97d76a32
```

Co-authored-by: Szymon Dziedzic <[email protected]>
2024-11-07 22:26:52 +01:00
Jon Samp d47b80a125 Adds workflow:validate command (#2650)
* adds validate command

* use yaml

* incorp feedback
2024-11-07 08:53:51 -06:00
Quinlan Jung 3f2dcc7e09 [eas-cli] compute fingerprint on each build (#2663)
* Temporary Commit at 11/4/2024, 4:33:33 PM

* Temporary Commit at 11/5/2024, 4:17:31 PM

* Temporary Commit at 11/5/2024, 4:22:18 PM
2024-11-05 19:20:44 -08:00
Expo CI b039da04e2 update CHANGELOG.md 2024-11-05 22:20:04 +00:00
Cedric van Putten 9e55fcbe7c v13.0.1 2024-11-05 23:02:06 +01:00
Cedric van Putten 281ae7bad6 fix(eas-cli): update EAS Metadata with new props for App Store 3.6.0 (#2671)
* refactor(eas-cli): upgrade eas metadata to support app store 3.6.0 advisory props

* chore(eas-cli): bump `@expo/apple-utils` to `2.1.0`

* fix(eas-cli): update eas metadata json schema

* docs(eas-cli): add changelog entry

* fix(eas-cli): fix typo in config version

* fix(eas-cli): resolve outdated fixtures

* chore(eas-cli): resolve linting issues
2024-11-05 23:01:14 +01:00
Expo CI 433c47b221 update CHANGELOG.md 2024-11-05 18:52:32 +00:00
29 changed files with 3317 additions and 323 deletions

No files matched your search

+20 -2
View File
@@ -6,14 +6,32 @@ This is the log of notable changes to EAS CLI and related packages.
### 🛠 Breaking changes
- Resolve versioned expo config using `npx expo config` command instead of using fixed `@expo/config` version shipped with EAS CLI, if available. ([#2529](https://github.com/expo/eas-cli/pull/2529) by [@szdziedzic](https://github.com/szdziedzic))
### 🎉 New features
### 🐛 Bug fixes
### 🧹 Chores
## [13.1.0](https://github.com/expo/eas-cli/releases/tag/v13.1.0) - 2024-11-07
### 🎉 New features
- Compute fingerprint for builds with SDK 52 and higher ([#2663](https://github.com/expo/eas-cli/pull/2663) by [@quinlanj](https://github.com/quinlanj))
## [13.0.1](https://github.com/expo/eas-cli/releases/tag/v13.0.1) - 2024-11-05
### 🧹 Chores
- Upgrade EAS Metadata with new properties from App Store. ([#2671](https://github.com/expo/eas-cli/pull/2671) by [@byCedric](https://github.com/byCedric))
## [13.0.0](https://github.com/expo/eas-cli/releases/tag/v13.0.0) - 2024-11-05
### 🛠 Breaking changes
- Resolve versioned expo config using `npx expo config` command instead of using fixed `@expo/config` version shipped with EAS CLI, if available. ([#2529](https://github.com/expo/eas-cli/pull/2529) by [@szdziedzic](https://github.com/szdziedzic))
### 🧹 Chores
- Add `macos-sonoma-14.6-xcode-16.1` image and `sdk-52` image tag to `eas.schema.json`. ([#2666](https://github.com/expo/eas-cli/pull/2666) by [@szdziedzic](https://github.com/szdziedzic))
- Update `@expo` packages versions. ([#2530](https://github.com/expo/eas-cli/pull/2530) by [@szdziedzic](https://github.com/szdziedzic))
+1 -1
View File
@@ -1,5 +1,5 @@
{
"npmClient": "yarn",
"version": "13.0.0",
"version": "13.1.1",
"$schema": "node_modules/lerna/schemas/lerna-schema.json"
}
+63 -63
View File
@@ -146,7 +146,7 @@ ALIASES
$ eas login
```
_See code: [packages/eas-cli/src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/account/login.ts)_
## `eas account:logout`
@@ -163,7 +163,7 @@ ALIASES
$ eas logout
```
_See code: [packages/eas-cli/src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/account/logout.ts)_
## `eas account:view`
@@ -180,7 +180,7 @@ ALIASES
$ eas whoami
```
_See code: [packages/eas-cli/src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/account/view.ts)_
## `eas analytics [STATUS]`
@@ -194,7 +194,7 @@ DESCRIPTION
display or change analytics settings
```
_See code: [packages/eas-cli/src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/analytics.ts)_
## `eas autocomplete [SHELL]`
@@ -246,7 +246,7 @@ DESCRIPTION
create a branch
```
_See code: [packages/eas-cli/src/commands/branch/create.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/branch/create.ts)_
## `eas branch:delete [NAME]`
@@ -267,7 +267,7 @@ DESCRIPTION
delete a branch
```
_See code: [packages/eas-cli/src/commands/branch/delete.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/branch/delete.ts)_
## `eas branch:list`
@@ -287,7 +287,7 @@ DESCRIPTION
list all branches
```
_See code: [packages/eas-cli/src/commands/branch/list.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/branch/list.ts)_
## `eas branch:rename`
@@ -307,7 +307,7 @@ DESCRIPTION
rename a branch
```
_See code: [packages/eas-cli/src/commands/branch/rename.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/branch/rename.ts)_
## `eas branch:view [NAME]`
@@ -330,7 +330,7 @@ DESCRIPTION
view a branch
```
_See code: [packages/eas-cli/src/commands/branch/view.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/branch/view.ts)_
## `eas build`
@@ -367,7 +367,7 @@ DESCRIPTION
start a build
```
_See code: [packages/eas-cli/src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/build/index.ts)_
## `eas build:cancel [BUILD_ID]`
@@ -386,7 +386,7 @@ DESCRIPTION
cancel a build
```
_See code: [packages/eas-cli/src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/build/cancel.ts)_
## `eas build:configure`
@@ -403,7 +403,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/v13.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/v13.1.1/packages/eas-cli/src/commands/build/configure.ts)_
## `eas build:delete [BUILD_ID]`
@@ -422,7 +422,7 @@ DESCRIPTION
delete a build
```
_See code: [packages/eas-cli/src/commands/build/delete.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/build/delete.ts)_
## `eas build:inspect`
@@ -457,7 +457,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/v13.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/v13.1.1/packages/eas-cli/src/commands/build/inspect.ts)_
## `eas build:list`
@@ -507,7 +507,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/v13.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/v13.1.1/packages/eas-cli/src/commands/build/list.ts)_
## `eas build:resign`
@@ -536,7 +536,7 @@ DESCRIPTION
re-sign a build archive
```
_See code: [packages/eas-cli/src/commands/build/resign.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/build/resign.ts)_
## `eas build:run`
@@ -562,7 +562,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/v13.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/v13.1.1/packages/eas-cli/src/commands/build/run.ts)_
## `eas build:submit`
@@ -612,7 +612,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/v13.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/v13.1.1/packages/eas-cli/src/commands/build/version/get.ts)_
## `eas build:version:set`
@@ -631,7 +631,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/v13.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/v13.1.1/packages/eas-cli/src/commands/build/version/set.ts)_
## `eas build:version:sync`
@@ -650,7 +650,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/v13.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/v13.1.1/packages/eas-cli/src/commands/build/version/sync.ts)_
## `eas build:view [BUILD_ID]`
@@ -667,7 +667,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/v13.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/v13.1.1/packages/eas-cli/src/commands/build/view.ts)_
## `eas channel:create [NAME]`
@@ -688,7 +688,7 @@ DESCRIPTION
create a channel
```
_See code: [packages/eas-cli/src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/channel/create.ts)_
## `eas channel:edit [NAME]`
@@ -710,7 +710,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/v13.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/v13.1.1/packages/eas-cli/src/commands/channel/edit.ts)_
## `eas channel:list`
@@ -730,7 +730,7 @@ DESCRIPTION
list all channels
```
_See code: [packages/eas-cli/src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/channel/list.ts)_
## `eas channel:pause [NAME]`
@@ -752,7 +752,7 @@ DESCRIPTION
pause a channel to stop it from sending updates
```
_See code: [packages/eas-cli/src/commands/channel/pause.ts](https://github.com/expo/eas-cli/blob/v13.0.0/packages/eas-cli/src/commands/channel/pause.ts)_
_See code: [packages/eas-cli/src/commands/channel/pause.ts](https://github.com/expo/eas-cli/blob/v13.1.1/packages/eas-cli/src/commands/channel/pause.ts)_
## `eas channel:resume [NAME]`
@@ -774,7 +774,7 @@ DESCRIPTION
resume a channel to start sending updates
```
_See code: [packages/eas-cli/src/commands/channel/resume.ts](https://github.com/expo/eas-cli/blob/v13.0.0/packages/eas-cli/src/commands/channel/resume.ts)_
_See code: [packages/eas-cli/src/commands/channel/resume.ts](https://github.com/expo/eas-cli/blob/v13.1.1/packages/eas-cli/src/commands/channel/resume.ts)_
## `eas channel:rollout [CHANNEL]`
@@ -807,7 +807,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/v13.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/v13.1.1/packages/eas-cli/src/commands/channel/rollout.ts)_
## `eas channel:view [NAME]`
@@ -830,7 +830,7 @@ DESCRIPTION
view a channel
```
_See code: [packages/eas-cli/src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/channel/view.ts)_
## `eas config`
@@ -851,7 +851,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/v13.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/v13.1.1/packages/eas-cli/src/commands/config.ts)_
## `eas credentials`
@@ -868,7 +868,7 @@ DESCRIPTION
manage credentials
```
_See code: [packages/eas-cli/src/commands/credentials/index.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/credentials/index.ts)_
## `eas credentials:configure-build`
@@ -886,7 +886,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/v13.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/v13.1.1/packages/eas-cli/src/commands/credentials/configure-build.ts)_
## `eas device:create`
@@ -900,7 +900,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/v13.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/v13.1.1/packages/eas-cli/src/commands/device/create.ts)_
## `eas device:delete`
@@ -920,7 +920,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/v13.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/v13.1.1/packages/eas-cli/src/commands/device/delete.ts)_
## `eas device:list`
@@ -941,7 +941,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/v13.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/v13.1.1/packages/eas-cli/src/commands/device/list.ts)_
## `eas device:rename`
@@ -962,7 +962,7 @@ DESCRIPTION
rename a registered device
```
_See code: [packages/eas-cli/src/commands/device/rename.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/device/rename.ts)_
## `eas device:view [UDID]`
@@ -976,7 +976,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/v13.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/v13.1.1/packages/eas-cli/src/commands/device/view.ts)_
## `eas diagnostics`
@@ -990,7 +990,7 @@ DESCRIPTION
display environment info
```
_See code: [packages/eas-cli/src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/diagnostics.ts)_
## `eas help [COMMAND]`
@@ -1098,7 +1098,7 @@ DESCRIPTION
validate the local store configuration
```
_See code: [packages/eas-cli/src/commands/metadata/lint.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/metadata/lint.ts)_
## `eas metadata:pull`
@@ -1115,7 +1115,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/v13.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/v13.1.1/packages/eas-cli/src/commands/metadata/pull.ts)_
## `eas metadata:push`
@@ -1132,7 +1132,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/v13.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/v13.1.1/packages/eas-cli/src/commands/metadata/push.ts)_
## `eas onboarding [TARGET_PROJECT_DIRECTORY]`
@@ -1162,7 +1162,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/v13.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/v13.1.1/packages/eas-cli/src/commands/open.ts)_
## `eas project:info`
@@ -1176,7 +1176,7 @@ DESCRIPTION
information about the current project
```
_See code: [packages/eas-cli/src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/project/info.ts)_
## `eas project:init`
@@ -1199,7 +1199,7 @@ ALIASES
$ eas init
```
_See code: [packages/eas-cli/src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/project/init.ts)_
## `eas project:onboarding [TARGET_PROJECT_DIRECTORY]`
@@ -1217,7 +1217,7 @@ ALIASES
$ eas onboarding
```
_See code: [packages/eas-cli/src/commands/project/onboarding.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/project/onboarding.ts)_
## `eas secret:create`
@@ -1240,7 +1240,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/v13.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/v13.1.1/packages/eas-cli/src/commands/secret/create.ts)_
## `eas secret:delete`
@@ -1258,7 +1258,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/v13.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/v13.1.1/packages/eas-cli/src/commands/secret/delete.ts)_
## `eas secret:list`
@@ -1272,7 +1272,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/v13.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/v13.1.1/packages/eas-cli/src/commands/secret/list.ts)_
## `eas secret:push`
@@ -1292,7 +1292,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/v13.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/v13.1.1/packages/eas-cli/src/commands/secret/push.ts)_
## `eas submit`
@@ -1323,7 +1323,7 @@ ALIASES
$ eas build:submit
```
_See code: [packages/eas-cli/src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/submit.ts)_
## `eas update`
@@ -1361,7 +1361,7 @@ DESCRIPTION
publish an update group
```
_See code: [packages/eas-cli/src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/update/index.ts)_
## `eas update:configure`
@@ -1379,7 +1379,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/v13.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/v13.1.1/packages/eas-cli/src/commands/update/configure.ts)_
## `eas update:delete GROUPID`
@@ -1400,7 +1400,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/v13.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/v13.1.1/packages/eas-cli/src/commands/update/delete.ts)_
## `eas update:edit [GROUPID]`
@@ -1424,7 +1424,7 @@ DESCRIPTION
edit all the updates in an update group
```
_See code: [packages/eas-cli/src/commands/update/edit.ts](https://github.com/expo/eas-cli/blob/v13.0.0/packages/eas-cli/src/commands/update/edit.ts)_
_See code: [packages/eas-cli/src/commands/update/edit.ts](https://github.com/expo/eas-cli/blob/v13.1.1/packages/eas-cli/src/commands/update/edit.ts)_
## `eas update:list`
@@ -1446,7 +1446,7 @@ DESCRIPTION
view the recent updates
```
_See code: [packages/eas-cli/src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/update/list.ts)_
## `eas update:republish`
@@ -1478,7 +1478,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/v13.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/v13.1.1/packages/eas-cli/src/commands/update/republish.ts)_
## `eas update:roll-back-to-embedded`
@@ -1506,7 +1506,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/v13.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/v13.1.1/packages/eas-cli/src/commands/update/roll-back-to-embedded.ts)_
## `eas update:rollback`
@@ -1526,7 +1526,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/v13.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/v13.1.1/packages/eas-cli/src/commands/update/rollback.ts)_
## `eas update:view GROUPID`
@@ -1546,7 +1546,7 @@ DESCRIPTION
update group details
```
_See code: [packages/eas-cli/src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/update/view.ts)_
## `eas webhook:create`
@@ -1567,7 +1567,7 @@ DESCRIPTION
create a webhook
```
_See code: [packages/eas-cli/src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/webhook/create.ts)_
## `eas webhook:delete [ID]`
@@ -1587,7 +1587,7 @@ DESCRIPTION
delete a webhook
```
_See code: [packages/eas-cli/src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/webhook/delete.ts)_
## `eas webhook:list`
@@ -1605,7 +1605,7 @@ DESCRIPTION
list webhooks
```
_See code: [packages/eas-cli/src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/webhook/list.ts)_
## `eas webhook:update`
@@ -1627,7 +1627,7 @@ DESCRIPTION
update a webhook
```
_See code: [packages/eas-cli/src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/webhook/update.ts)_
## `eas webhook:view ID`
@@ -1644,7 +1644,7 @@ DESCRIPTION
view a webhook
```
_See code: [packages/eas-cli/src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v13.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/v13.1.1/packages/eas-cli/src/commands/webhook/view.ts)_
## `eas whoami`
+2096 -137
View File
File diff suppressed because it is too large. Load diff
+3 -2
View File
@@ -1,14 +1,14 @@
{
"name": "eas-cli",
"description": "EAS command line tool",
"version": "13.0.0",
"version": "13.1.1",
"author": "Expo <[email protected]>",
"bin": {
"eas": "./bin/run"
},
"bugs": "https://github.com/expo/eas-cli/issues",
"dependencies": {
"@expo/apple-utils": "2.0.3",
"@expo/apple-utils": "2.1.0",
"@expo/code-signing-certificates": "0.0.5",
"@expo/config": "9.0.4",
"@expo/config-plugins": "8.0.10",
@@ -86,6 +86,7 @@
"untildify": "4.0.0",
"uuid": "9.0.1",
"wrap-ansi": "7.0.0",
"yaml": "2.6.0",
"zod": "^3.23.8"
},
"devDependencies": {
+53 -18
View File
@@ -1,6 +1,20 @@
{
"$schema": "http://json-schema.org/draft-06/schema",
"type": "object",
"properties": {
"configVersion": {
"enum": [0],
"description": "The EAS metadata store configuration version"
},
"apple": {
"$ref": "#/definitions/AppleConfig"
}
},
"additionalProperties": false,
"required": [
"configVersion",
"apple"
],
"definitions": {
"apple": {
"AppleKidsAge": {
@@ -323,7 +337,8 @@
"gambling",
"unrestrictedWebAccess",
"kidsAgeBand",
"seventeenPlus"
"ageRatingOverride",
"koreaAgeRatingOverride"
],
"defaultSnippets": [
{
@@ -345,7 +360,9 @@
"gambling": false,
"unrestrictedWebAccess": false,
"kidsAgeBand": null,
"seventeenPlus": false
"ageRatingOverride": "NONE",
"koreaAgeRatingOverride": "NONE",
"lootBox": false
}
},
{
@@ -367,7 +384,9 @@
"unrestrictedWebAccess": false,
"gambling": false,
"kidsAgeBand": null,
"seventeenPlus": false
"ageRatingOverride": "${13|NONE,SEVENTEEN_PLUS,UNRATED|}",
"koreaAgeRatingOverride": "${14|NONE,FIFTEEN_PLUS,NINETEEN_PLUS|}",
"lootBox": false
}
}
],
@@ -442,8 +461,24 @@
},
"seventeenPlus": {
"type": "boolean",
"deprecated": true,
"deprecationMessage": "This property is deprecated, use `ageRatingOverride` instead.",
"description": "If your app rates 12+ or lower, and you believe its content may not be suitable for children under 17, you can manually set the age rating to 17+.\n@see https://help.apple.com/app-store-connect/#/dev599d50efb",
"markdownDescription": "If your app rates 12+ or lower, and you believe its content may not be suitable for children under 17, you can manually set the age rating to 17+.\n\n[Learn more](https://help.apple.com/app-store-connect/#/dev599d50efb)"
},
"ageRatingOverride": {
"$ref": "#/definitions/apple/AppleAgeRatingOverride",
"description": "If your app rates 12+ or lower, and you believe its content may not be suitable for children under 17, you can manually set the age rating to 17+.\n\nIf your app will be distributed through alternative app marketplaces or websites in the European Union and you believe your app is [Unrated](https://developer.apple.com/help/app-store-connect/reference/age-ratings), set this to `UNRATED`.\n\n@see https://help.apple.com/app-store-connect/#/dev599d50efb",
"markdownDescription": "If your app rates 12+ or lower, and you believe its content may not be suitable for children under 17, you can manually set the age rating to 17+.\n\nIf your app will be distributed through alternative app marketplaces or websites in the European Union and you believe your app is [Unrated](https://developer.apple.com/help/app-store-connect/reference/age-ratings), set this to `UNRATED`.\n\n[Learn more](https://help.apple.com/app-store-connect/#/dev599d50efb)"
},
"koreaAgeRatingOverride": {
"$ref": "#/definitions/apple/AppleKoreaAgeRatingOverride",
"description": "If your app rates 12+ or lower, and you believe its content may not be suitable for children under 15 or 19, you can manually set the age rating to 15+ or 19+.\n\nIf your app will be distributed through alternative app marketplaces or websites in the European Union and you believe your app is [Unrated](https://developer.apple.com/help/app-store-connect/reference/age-ratings), set this to `UNRATED`.\n\n@see https://help.apple.com/app-store-connect/#/dev599d50efb",
"markdownDescription": "If your app rates 12+ or lower, and you believe its content may not be suitable for children under 15 or 19, you can manually set the age rating to 15+ or 19+.\n\nIf your app will be distributed through alternative app marketplaces or websites in the European Union and you believe your app is [Unrated](https://developer.apple.com/help/app-store-connect/reference/age-ratings), set this to `UNRATED`.\n\n[Learn more](https://help.apple.com/app-store-connect/#/dev599d50efb)"
},
"lootBox": {
"type": "boolean",
"description": "Does your app contain purchasable loot boxes? These virtual containers provide players with in-game items, including functional cards or cosmetic modifications, based on random chance."
}
}
},
@@ -565,6 +600,20 @@
"maxLength": 4000
}
}
},
"AppleAgeRatingOverride": {
"enum": [
"NONE",
"SEVENTEEN_PLUS",
"UNRATED"
]
},
"AppleKoreaAgeRatingOverride": {
"enum": [
"NONE",
"FIFTEEN_PLUS",
"NINETEEN_PLUS"
]
}
},
"AppleConfig": {
@@ -775,19 +824,5 @@
}
}
}
},
"properties": {
"configVersion": {
"enum": [0],
"description": "The EAS metadata store configuration version"
},
"apple": {
"$ref": "#/definitions/AppleConfig"
}
},
"additionalProperties": false,
"required": [
"configVersion",
"apple"
]
}
}
+69 -5
View File
@@ -66,6 +66,7 @@ import { maybeUploadFingerprintAsync } from '../project/maybeUploadFingerprintAs
import { resolveRuntimeVersionAsync } from '../project/resolveRuntimeVersionAsync';
import { uploadFileAtPathToGCSAsync } from '../uploads';
import { formatBytes } from '../utils/files';
import { createFingerprintAsync } from '../utils/fingerprintCli';
import { printJsonOnlyOutput } from '../utils/json';
import { createProgressTracker } from '../utils/progress';
import { sleepAsync } from '../utils/promise';
@@ -174,8 +175,9 @@ export async function prepareBuildRequestForPlatformAsync<
}
assert(projectArchive);
const runtimeMetadata = await createAndMaybeUploadFingerprintAsync(ctx);
const metadata = await collectMetadataAsync(ctx, runtimeMetadata);
const runtimeAndFingerprintMetadata =
await computeAndMaybeUploadRuntimeAndFingerprintMetadataAsync(ctx);
const metadata = await collectMetadataAsync(ctx, runtimeAndFingerprintMetadata);
const buildParams = resolveBuildParamsInput(ctx, metadata);
const job = await builder.prepareJobAsync(ctx, {
projectArchive,
@@ -660,11 +662,38 @@ function formatAccountBillingUrl(accountName: string): string {
return new URL(`/accounts/${accountName}/settings/billing`, getExpoWebsiteBaseUrl()).toString();
}
async function createAndMaybeUploadFingerprintAsync<T extends Platform>(
async function computeAndMaybeUploadRuntimeAndFingerprintMetadataAsync<T extends Platform>(
ctx: BuildContext<T>
): Promise<{
runtimeVersion?: string | undefined;
fingerprintHash?: string | undefined;
fingerprintSource?: FingerprintSource | undefined;
}> {
const runtimeAndFingerprintMetadata =
await computeAndMaybeUploadFingerprintFromExpoUpdatesAsync(ctx);
if (!runtimeAndFingerprintMetadata?.fingerprint) {
const fingerprint = await computeAndMaybeUploadFingerprintWithoutExpoUpdatesAsync(ctx);
return {
...runtimeAndFingerprintMetadata,
...fingerprint,
};
} else {
return {
...runtimeAndFingerprintMetadata,
fingerprintHash: runtimeAndFingerprintMetadata.runtimeVersion,
};
}
}
async function computeAndMaybeUploadFingerprintFromExpoUpdatesAsync<T extends Platform>(
ctx: BuildContext<T>
): Promise<{
runtimeVersion?: string;
fingerprintSource?: FingerprintSource;
fingerprint?: {
fingerprintSources: object[];
isDebugFingerprintSource: boolean;
};
}> {
const resolvedRuntimeVersion = await resolveRuntimeVersionAsync({
exp: ctx.exp,
@@ -689,10 +718,45 @@ async function createAndMaybeUploadFingerprintAsync<T extends Platform>(
};
}
return await maybeUploadFingerprintAsync({
runtimeVersion: resolvedRuntimeVersion.runtimeVersion,
const uploadedFingerprint = await maybeUploadFingerprintAsync({
hash: resolvedRuntimeVersion.runtimeVersion,
fingerprint: resolvedRuntimeVersion.fingerprint,
graphqlClient: ctx.graphqlClient,
localBuildMode: ctx.localBuildOptions.localBuildMode,
});
return {
runtimeVersion: uploadedFingerprint.hash,
fingerprintSource: uploadedFingerprint.fingerprintSource,
fingerprint: resolvedRuntimeVersion.fingerprint,
};
}
async function computeAndMaybeUploadFingerprintWithoutExpoUpdatesAsync<T extends Platform>(
ctx: BuildContext<T>,
{ debug }: { debug?: boolean } = {}
): Promise<{
fingerprintHash?: string;
fingerprintSource?: FingerprintSource;
}> {
const fingerprint = await createFingerprintAsync(ctx.projectDir, {
workflow: ctx.workflow,
platform: ctx.platform,
env: ctx.env,
});
if (!fingerprint) {
return {};
}
const uploadedFingerprint = await maybeUploadFingerprintAsync({
hash: fingerprint.hash,
fingerprint: {
fingerprintSources: fingerprint.sources,
isDebugFingerprintSource: debug ?? false,
},
graphqlClient: ctx.graphqlClient,
localBuildMode: ctx.localBuildOptions.localBuildMode,
});
return {
fingerprintHash: uploadedFingerprint.hash,
fingerprintSource: uploadedFingerprint.fingerprintSource,
};
}
+5 -3
View File
@@ -16,8 +16,9 @@ import { easCliVersion } from '../utils/easCli';
export async function collectMetadataAsync<T extends Platform>(
ctx: BuildContext<T>,
runtimeMetadata: {
runtimeAndFingerprintMetadata: {
runtimeVersion?: string | undefined;
fingerprintHash?: string | undefined;
fingerprintSource?: FingerprintSource | undefined;
}
): Promise<Metadata> {
@@ -30,8 +31,9 @@ export async function collectMetadataAsync<T extends Platform>(
workflow: ctx.workflow,
credentialsSource: ctx.buildProfile.credentialsSource,
sdkVersion: ctx.exp.sdkVersion,
runtimeVersion: runtimeMetadata?.runtimeVersion,
fingerprintSource: runtimeMetadata?.fingerprintSource,
runtimeVersion: runtimeAndFingerprintMetadata?.runtimeVersion,
fingerprintHash: runtimeAndFingerprintMetadata?.fingerprintHash,
fingerprintSource: runtimeAndFingerprintMetadata?.fingerprintSource,
reactNativeVersion: await getReactNativeVersionAsync(ctx.projectDir),
...channelObject,
distribution,
+13
View File
@@ -50,3 +50,16 @@ export function getUpdateGroupUrl(
getExpoWebsiteBaseUrl()
).toString();
}
export function getWorkflowRunUrl(
accountName: string,
projectName: string,
workflowRunId: string
): string {
return new URL(
`/accounts/${encodeURIComponent(accountName)}/projects/${encodeURIComponent(
projectName
)}/workflows/${workflowRunId}`,
getExpoWebsiteBaseUrl()
).toString();
}
@@ -7,6 +7,7 @@ import EasCommand from '../../commandUtils/EasCommand';
import { RequestedPlatform } from '../../platform';
import { enableJsonOutput } from '../../utils/json';
import GitNoCommitClient from '../../vcs/clients/gitNoCommit';
import NoVcsClient from '../../vcs/clients/noVcs';
/**
* This command will be run on the EAS Build workers, when building
@@ -63,7 +64,7 @@ export default class BuildInternal extends EasCommand {
vcsClient,
} = await this.getContextAsync(BuildInternal, {
nonInteractive: true,
vcsClientOverride: new GitNoCommitClient(),
vcsClientOverride: process.env.EAS_NO_VCS ? new NoVcsClient() : new GitNoCommitClient(),
withServerSideEnvironment: null,
});
@@ -413,7 +413,7 @@ export default class UpdatePublish extends EasCommand {
fingerprintSource: info.fingerprint
? (
await maybeUploadFingerprintAsync({
runtimeVersion: info.runtimeVersion,
hash: info.runtimeVersion,
fingerprint: info.fingerprint,
graphqlClient,
})
@@ -0,0 +1,115 @@
import fs from 'node:fs';
import * as path from 'node:path';
import { getWorkflowRunUrl } from '../../build/utils/url';
import EasCommand from '../../commandUtils/EasCommand';
import { EASNonInteractiveFlag } from '../../commandUtils/flags';
import { WorkflowProjectSourceType } from '../../graphql/generated';
import { WorkflowRunMutation } from '../../graphql/mutations/WorkflowRunMutation';
import Log, { link } from '../../log';
import { getOwnerAccountForProjectIdAsync } from '../../project/projectUtils';
import { uploadAccountScopedEasJsonAsync } from '../../project/uploadAccountScopedEasJsonAsync';
import { uploadAccountScopedProjectSourceAsync } from '../../project/uploadAccountScopedProjectSourceAsync';
export default class WorkflowRun extends EasCommand {
static override description = 'Run an EAS workflow';
// TODO(@sjchmiela): Keep command hidden until workflows are live
static override hidden = true;
static override state = 'beta';
static override args = [{ name: 'file', description: 'Path to the workflow file to run' }];
static override flags = {
...EASNonInteractiveFlag,
};
static override contextDefinition = {
...this.ContextOptions.DynamicProjectConfig,
...this.ContextOptions.ProjectDir,
...this.ContextOptions.Vcs,
...this.ContextOptions.LoggedIn,
};
async runAsync(): Promise<void> {
const { flags, args } = await this.parse(WorkflowRun);
Log.warn('Workflows are in beta and subject to breaking changes.');
const {
getDynamicPrivateProjectConfigAsync,
loggedIn: { graphqlClient },
vcsClient,
projectDir,
} = await this.getContextAsync(WorkflowRun, {
nonInteractive: flags['non-interactive'],
withServerSideEnvironment: null,
});
let yamlConfig: string;
try {
yamlConfig = await fs.promises.readFile(path.join(projectDir, args.file), 'utf8');
} catch (err) {
Log.error('Failed to read workflow file.');
throw err;
}
const {
projectId,
exp: { slug: projectName },
} = await getDynamicPrivateProjectConfigAsync();
const account = await getOwnerAccountForProjectIdAsync(graphqlClient, projectId);
let projectArchiveBucketKey: string;
let easJsonBucketKey: string;
try {
({ projectArchiveBucketKey } = await uploadAccountScopedProjectSourceAsync({
graphqlClient,
vcsClient,
accountId: account.id,
}));
({ easJsonBucketKey } = await uploadAccountScopedEasJsonAsync({
graphqlClient,
accountId: account.id,
projectDir,
}));
} catch (err) {
Log.error('Failed to upload project sources.');
throw err;
}
try {
const { id: workflowRunId } = await WorkflowRunMutation.createWorkflowRunAsync(
graphqlClient,
{
appId: projectId,
workflowRevisionInput: {
fileName: path.basename(args.file),
yamlConfig,
},
workflowRunInput: {
projectSource: {
type: WorkflowProjectSourceType.Gcs,
projectArchiveBucketKey,
easJsonBucketKey,
},
},
}
);
Log.newLine();
Log.succeed(
`Workflow started successfully. ${link(
getWorkflowRunUrl(account.name, projectName, workflowRunId)
)}`
);
} catch (err) {
Log.error('Failed to start the workflow with the API.');
throw err;
}
}
}
@@ -0,0 +1,98 @@
import fs from 'fs/promises';
import path from 'path';
import * as YAML from 'yaml';
import EasCommand from '../../commandUtils/EasCommand';
import Log from '../../log';
import { ora } from '../../ora';
export class WorkflowValidate extends EasCommand {
static override description = 'validate a workflow configuration yaml file';
static override hidden = true;
static override args = [
{
name: 'path',
description: 'Path to the workflow configuration YAML file (must end with .yml or .yaml)',
required: true,
},
];
async runAsync(): Promise<void> {
const {
args: { path: filePath },
} = await this.parse(WorkflowValidate);
const spinner = ora().start('Validating the workflow YAML file…');
try {
await validateYAMLAsync(filePath);
spinner.succeed('Workflow configuration YAML is valid.');
} catch (error) {
spinner.fail('Workflow configuration YAML is not valid.');
if (error instanceof YAML.YAMLParseError) {
Log.error(`YAML syntax error: ${error.message}`);
} else if (error instanceof Error) {
Log.error(error.message);
} else {
Log.error(`Unexpected error: ${String(error)}`);
}
process.exit(1);
}
}
}
async function checkIfFileExistsAsync(filePath: string): Promise<void> {
try {
await fs.access(filePath);
} catch {
throw new Error(`File does not exist: ${filePath}`);
}
}
function checkIfValidYAMLFileExtension(filePath: string): void {
const fileExtension = path.extname(filePath).toLowerCase();
if (fileExtension !== '.yml' && fileExtension !== '.yaml') {
throw new Error('File must have a .yml or .yaml extension');
}
}
async function validateYAMLAsync(filePath: string): Promise<void> {
await checkIfFileExistsAsync(filePath);
checkIfValidYAMLFileExtension(filePath);
try {
const fileContents = await fs.readFile(filePath, 'utf8');
// First check if the file is empty or only contains whitespace
if (!fileContents.trim()) {
throw new Error('YAML file is empty or contains only comments.');
}
const parsedYaml = YAML.parse(fileContents);
// Check if the parsed result is empty or null
if (
parsedYaml === null ||
parsedYaml === undefined ||
(typeof parsedYaml === 'object' && Object.keys(parsedYaml).length === 0)
) {
throw new Error('YAML file is empty or contains only comments.');
}
} catch (error) {
if (
error instanceof Error &&
error.message === 'YAML file is empty or contains only comments.'
) {
throw error;
}
if (error instanceof YAML.YAMLParseError || error instanceof Error) {
throw new Error(`YAML parsing error: ${error.message}`);
} else {
throw new Error(`YAML parsing error: ${String(error)}`);
}
}
}
+308 -46
View File
@@ -710,6 +710,10 @@ export type AccountSsoConfigurationPublicDataQueryPublicDataByAccountNameArgs =
accountName: Scalars['String']['input'];
};
export enum AccountUploadSessionType {
WorkflowsProjectSources = 'WORKFLOWS_PROJECT_SOURCES'
}
export type AccountUsageEasBuildMetadata = {
__typename?: 'AccountUsageEASBuildMetadata';
billingResourceClass?: Maybe<EasBuildBillingResourceClass>;
@@ -1374,6 +1378,7 @@ export type App = Project & {
workerDeploymentsCrashes?: Maybe<WorkerDeploymentCrashes>;
workerDeploymentsRequest: WorkerDeploymentRequestEdge;
workerDeploymentsRequests?: Maybe<WorkerDeploymentRequests>;
workflowRunsPaginated: AppWorkflowRunsConnection;
workflows: Array<Workflow>;
};
@@ -1383,7 +1388,6 @@ export type AppActivityTimelineProjectActivitiesArgs = {
createdBefore?: InputMaybe<Scalars['DateTime']['input']>;
filterChannels?: InputMaybe<Array<Scalars['String']['input']>>;
filterPlatforms?: InputMaybe<Array<AppPlatform>>;
filterReleaseChannels?: InputMaybe<Array<Scalars['String']['input']>>;
filterTypes?: InputMaybe<Array<ActivityTimelineProjectActivityType>>;
limit: Scalars['Int']['input'];
};
@@ -1647,6 +1651,15 @@ export type AppWorkerDeploymentsRequestsArgs = {
timespan: DatasetTimespan;
};
/** Represents an Exponent App (or Experience in legacy terms) */
export type AppWorkflowRunsPaginatedArgs = {
after?: InputMaybe<Scalars['String']['input']>;
before?: InputMaybe<Scalars['String']['input']>;
first?: InputMaybe<Scalars['Int']['input']>;
last?: InputMaybe<Scalars['Int']['input']>;
};
export type AppBranchEdge = {
__typename?: 'AppBranchEdge';
cursor: Scalars['String']['output'];
@@ -2088,6 +2101,18 @@ export type AppWithGithubRepositoryInput = {
projectName: Scalars['String']['input'];
};
export type AppWorkflowRunEdge = {
__typename?: 'AppWorkflowRunEdge';
cursor: Scalars['String']['output'];
node: WorkflowRun;
};
export type AppWorkflowRunsConnection = {
__typename?: 'AppWorkflowRunsConnection';
edges: Array<AppWorkflowRunEdge>;
pageInfo: PageInfo;
};
export type AppleAppIdentifier = {
__typename?: 'AppleAppIdentifier';
account: Account;
@@ -2490,7 +2515,8 @@ export type AuditLog = {
metadata?: Maybe<Scalars['JSONObject']['output']>;
targetEntityId: Scalars['ID']['output'];
targetEntityMutationType: TargetEntityMutationType;
targetEntityTypeName: Scalars['String']['output'];
targetEntityTypeName: EntityTypeName;
targetEntityTypePublicName: Scalars['String']['output'];
websiteMessage: Scalars['String']['output'];
};
@@ -2535,6 +2561,7 @@ export type AuditLogQuery = {
__typename?: 'AuditLogQuery';
/** Audit logs for account */
byId: AuditLog;
typeNamesMap: Array<LogNameTypeMapping>;
};
@@ -2884,6 +2911,7 @@ export type BuildMetadataInput = {
developmentClient?: InputMaybe<Scalars['Boolean']['input']>;
distribution?: InputMaybe<DistributionType>;
environment?: InputMaybe<Scalars['String']['input']>;
fingerprintHash?: InputMaybe<Scalars['String']['input']>;
fingerprintSource?: InputMaybe<FingerprintSourceInput>;
gitCommitHash?: InputMaybe<Scalars['String']['input']>;
gitCommitMessage?: InputMaybe<Scalars['String']['input']>;
@@ -3147,7 +3175,9 @@ export enum BuildResourceClass {
IosMedium = 'IOS_MEDIUM',
IosMLarge = 'IOS_M_LARGE',
IosMMedium = 'IOS_M_MEDIUM',
Legacy = 'LEGACY'
Legacy = 'LEGACY',
LinuxLarge = 'LINUX_LARGE',
LinuxMedium = 'LINUX_MEDIUM'
}
export enum BuildRetryDisabledReason {
@@ -3298,8 +3328,8 @@ export type CreateEnvironmentSecretInput = {
};
export type CreateEnvironmentVariableInput = {
environment?: InputMaybe<EnvironmentVariableEnvironment>;
environments?: InputMaybe<Array<EnvironmentVariableEnvironment>>;
fileName?: InputMaybe<Scalars['String']['input']>;
name: Scalars['String']['input'];
overwrite?: InputMaybe<Scalars['Boolean']['input']>;
type?: InputMaybe<EnvironmentSecretType>;
@@ -3366,6 +3396,8 @@ export type CreateServerlessFunctionUploadUrlResult = {
export type CreateSharedEnvironmentVariableInput = {
environments?: InputMaybe<Array<EnvironmentVariableEnvironment>>;
fileName?: InputMaybe<Scalars['String']['input']>;
isGlobal?: InputMaybe<Scalars['Boolean']['input']>;
name: Scalars['String']['input'];
overwrite?: InputMaybe<Scalars['Boolean']['input']>;
type?: InputMaybe<EnvironmentSecretType>;
@@ -3381,8 +3413,8 @@ export type CreateSubmissionResult = {
export type CumulativeMetrics = {
__typename?: 'CumulativeMetrics';
/** Totals from the beginning of time till now */
totals: CumulativeMetricsTotals;
data: UpdatesMetricsData;
metricsAtLastTimestamp: CumulativeMetricsTotals;
};
export type CumulativeMetricsOverTimeData = {
@@ -3397,6 +3429,14 @@ export type CumulativeMetricsTotals = {
totalInstalls: Scalars['Int']['output'];
};
export type CumulativeUpdatesDataset = {
__typename?: 'CumulativeUpdatesDataset';
cumulative: Array<Scalars['Int']['output']>;
difference: Array<Scalars['Int']['output']>;
id: Scalars['String']['output'];
label: Scalars['String']['output'];
};
export type CustomBuildConfigInput = {
path: Scalars['String']['input'];
};
@@ -3863,25 +3903,25 @@ export type EmailSubscriptionMutationAddUserArgs = {
};
export enum EntityTypeName {
Account = 'Account',
AccountSsoConfiguration = 'AccountSSOConfiguration',
AndroidAppCredentials = 'AndroidAppCredentials',
AndroidKeystore = 'AndroidKeystore',
App = 'App',
AppStoreConnectApiKey = 'AppStoreConnectApiKey',
AppleDevice = 'AppleDevice',
AppleDistributionCertificate = 'AppleDistributionCertificate',
AppleProvisioningProfile = 'AppleProvisioningProfile',
AppleTeam = 'AppleTeam',
Branch = 'Branch',
Channel = 'Channel',
Customer = 'Customer',
GoogleServiceAccountKey = 'GoogleServiceAccountKey',
IosAppCredentials = 'IosAppCredentials',
UserInvitation = 'UserInvitation',
UserPermission = 'UserPermission',
Workflow = 'Workflow',
WorkflowRevision = 'WorkflowRevision'
AccountEntity = 'AccountEntity',
AccountSsoConfigurationEntity = 'AccountSSOConfigurationEntity',
AndroidAppCredentialsEntity = 'AndroidAppCredentialsEntity',
AndroidKeystoreEntity = 'AndroidKeystoreEntity',
AppEntity = 'AppEntity',
AppStoreConnectApiKeyEntity = 'AppStoreConnectApiKeyEntity',
AppleDeviceEntity = 'AppleDeviceEntity',
AppleDistributionCertificateEntity = 'AppleDistributionCertificateEntity',
AppleProvisioningProfileEntity = 'AppleProvisioningProfileEntity',
AppleTeamEntity = 'AppleTeamEntity',
BranchEntity = 'BranchEntity',
ChannelEntity = 'ChannelEntity',
CustomerEntity = 'CustomerEntity',
GoogleServiceAccountKeyEntity = 'GoogleServiceAccountKeyEntity',
IosAppCredentialsEntity = 'IosAppCredentialsEntity',
UserInvitationEntity = 'UserInvitationEntity',
UserPermissionEntity = 'UserPermissionEntity',
WorkflowEntity = 'WorkflowEntity',
WorkflowRevisionEntity = 'WorkflowRevisionEntity'
}
export type EnvironmentSecret = {
@@ -3929,9 +3969,10 @@ export type EnvironmentVariable = {
__typename?: 'EnvironmentVariable';
apps: Array<App>;
createdAt: Scalars['DateTime']['output'];
environment?: Maybe<EnvironmentVariableEnvironment>;
environments?: Maybe<Array<EnvironmentVariableEnvironment>>;
fileName?: Maybe<Scalars['String']['output']>;
id: Scalars['ID']['output'];
isGlobal?: Maybe<Scalars['Boolean']['output']>;
linkedEnvironments?: Maybe<Array<EnvironmentVariableEnvironment>>;
name: Scalars['String']['output'];
scope: EnvironmentVariableScope;
@@ -4048,9 +4089,10 @@ export type EnvironmentVariableWithSecret = {
__typename?: 'EnvironmentVariableWithSecret';
apps: Array<App>;
createdAt: Scalars['DateTime']['output'];
environment?: Maybe<EnvironmentVariableEnvironment>;
environments?: Maybe<Array<EnvironmentVariableEnvironment>>;
fileName?: Maybe<Scalars['String']['output']>;
id: Scalars['ID']['output'];
isGlobal: Scalars['Boolean']['output'];
linkedEnvironments?: Maybe<Array<EnvironmentVariableEnvironment>>;
name: Scalars['String']['output'];
scope: EnvironmentVariableScope;
@@ -5034,6 +5076,12 @@ export type LinkSharedEnvironmentVariableInput = {
environmentVariableId: Scalars['ID']['input'];
};
export type LogNameTypeMapping = {
__typename?: 'LogNameTypeMapping';
publicName: Scalars['String']['output'];
typeName: EntityTypeName;
};
export type LogsTimespan = {
end: Scalars['DateTime']['input'];
start?: InputMaybe<Scalars['DateTime']['input']>;
@@ -5041,7 +5089,9 @@ export type LogsTimespan = {
export enum MailchimpAudience {
ExpoDevelopers = 'EXPO_DEVELOPERS',
ExpoDeveloperOnboarding = 'EXPO_DEVELOPER_ONBOARDING'
ExpoDeveloperOnboarding = 'EXPO_DEVELOPER_ONBOARDING',
LaunchParty_2024 = 'LAUNCH_PARTY_2024',
NonprodExpoDevelopers = 'NONPROD_EXPO_DEVELOPERS'
}
export enum MailchimpTag {
@@ -5689,6 +5739,7 @@ export type RootMutation = {
/** Mutations that modify a websiteNotification */
websiteNotifications: WebsiteNotificationMutation;
workflowJob: WorkflowJobMutation;
workflowRun: WorkflowRunMutation;
};
@@ -5818,7 +5869,9 @@ export type RootQuery = {
/** Top-level query object for querying Webhooks. */
webhook: WebhookQuery;
workerDeployment: WorkerDeploymentQuery;
workflowJobs: WorkflowJobQuery;
workflowRevisions: WorkflowRevisionQuery;
workflowRuns: WorkflowRunQuery;
workflows: WorkflowQuery;
};
@@ -6112,6 +6165,8 @@ export type Snack = Project & {
/** Preview image of the running snack */
previewImage?: Maybe<Scalars['String']['output']>;
published: Scalars['Boolean']['output'];
/** SDK version of the snack */
sdkVersion: Scalars['String']['output'];
/** Slug name, e.g. "mysnack", "245631" */
slug: Scalars['String']['output'];
/** Date and time the Snack was last updated */
@@ -6666,7 +6721,9 @@ export type UpdateDeploymentsConnection = {
export type UpdateEnvironmentVariableInput = {
environments?: InputMaybe<Array<EnvironmentVariableEnvironment>>;
fileName?: InputMaybe<Scalars['String']['input']>;
id: Scalars['ID']['input'];
isGlobal?: InputMaybe<Scalars['Boolean']['input']>;
name?: InputMaybe<Scalars['String']['input']>;
type?: InputMaybe<EnvironmentSecretType>;
value?: InputMaybe<Scalars['String']['input']>;
@@ -6705,13 +6762,12 @@ export type UpdateInfoGroup = {
export type UpdateInsights = {
__typename?: 'UpdateInsights';
cumulativeMetrics: CumulativeMetrics;
cumulativeMetricsOverTime: CumulativeMetricsOverTimeData;
id: Scalars['ID']['output'];
totalUniqueUsers: Scalars['Int']['output'];
};
export type UpdateInsightsCumulativeMetricsOverTimeArgs = {
export type UpdateInsightsCumulativeMetricsArgs = {
timespan: InsightsTimespan;
};
@@ -6781,13 +6837,28 @@ export type UpdatesFilter = {
sdkVersions?: InputMaybe<Array<Scalars['String']['input']>>;
};
export type UpdatesMetricsData = {
__typename?: 'UpdatesMetricsData';
failedInstallsDataset: CumulativeUpdatesDataset;
installsDataset: CumulativeUpdatesDataset;
labels: Array<Scalars['String']['output']>;
};
export type UploadSession = {
__typename?: 'UploadSession';
/** Create an Upload Session for a specific account */
createAccountScopedUploadSession: Scalars['JSONObject']['output'];
/** Create an Upload Session */
createUploadSession: Scalars['JSONObject']['output'];
};
export type UploadSessionCreateAccountScopedUploadSessionArgs = {
accountID: Scalars['ID']['input'];
type: AccountUploadSessionType;
};
export type UploadSessionCreateUploadSessionArgs = {
type: UploadSessionType;
};
@@ -7152,7 +7223,8 @@ export type UserAuditLog = {
metadata?: Maybe<Scalars['JSONObject']['output']>;
targetEntityId: Scalars['ID']['output'];
targetEntityMutationType: TargetEntityMutationType;
targetEntityTypeName: Scalars['String']['output'];
targetEntityTypeName: UserEntityTypeName;
targetEntityTypePublicName: Scalars['String']['output'];
user: User;
websiteMessage: Scalars['String']['output'];
};
@@ -7199,6 +7271,7 @@ export type UserAuditLogQuery = {
/** Audit logs for user */
byId: UserAuditLog;
byUserIdPaginated: UserAuditLogConnection;
typeNamesMap: Array<UserLogNameTypeMapping>;
};
@@ -7227,15 +7300,15 @@ export type UserDataInput = {
};
export enum UserEntityTypeName {
AccessToken = 'AccessToken',
DiscordUser = 'DiscordUser',
GitHubUser = 'GitHubUser',
Password = 'Password',
SsoUser = 'SSOUser',
User = 'User',
UserPermission = 'UserPermission',
UserSecondFactorBackupCodes = 'UserSecondFactorBackupCodes',
UserSecondFactorDevice = 'UserSecondFactorDevice'
AccessTokenEntity = 'AccessTokenEntity',
DiscordUserEntity = 'DiscordUserEntity',
GitHubUserEntity = 'GitHubUserEntity',
PasswordEntity = 'PasswordEntity',
SsoUserEntity = 'SSOUserEntity',
UserEntity = 'UserEntity',
UserPermissionEntity = 'UserPermissionEntity',
UserSecondFactorBackupCodesEntity = 'UserSecondFactorBackupCodesEntity',
UserSecondFactorDeviceEntity = 'UserSecondFactorDeviceEntity'
}
/** An pending invitation sent to an email granting membership on an Account. */
@@ -7339,6 +7412,12 @@ export type UserInvitationPublicDataQueryByTokenArgs = {
token: Scalars['ID']['input'];
};
export type UserLogNameTypeMapping = {
__typename?: 'UserLogNameTypeMapping';
publicName: Scalars['String']['output'];
typeName: UserEntityTypeName;
};
export type UserPermission = {
__typename?: 'UserPermission';
actor: Actor;
@@ -7633,7 +7712,7 @@ export type WorkerDeploymentCrashesAggregationNode = {
distinctCrashes: Scalars['Int']['output'];
firstOccurredAt: Scalars['DateTime']['output'];
mostRecentlyOccurredAt: Scalars['DateTime']['output'];
sampleRate: Scalars['Float']['output'];
sampleRate?: Maybe<Scalars['Float']['output']>;
};
export type WorkerDeploymentCrashesHashEdge = {
@@ -7827,7 +7906,7 @@ export type WorkerDeploymentRequestsAggregationNode = {
durationP99: Scalars['Float']['output'];
requestsPerMs?: Maybe<Scalars['Float']['output']>;
requestsSum: Scalars['Int']['output'];
sampleRate: Scalars['Float']['output'];
sampleRate?: Maybe<Scalars['Float']['output']>;
serverErrorRatio: Scalars['Float']['output'];
serverErrorRatioP50: Scalars['Float']['output'];
serverErrorRatioP90: Scalars['Float']['output'];
@@ -7922,10 +8001,52 @@ export type Workflow = {
fileName: Scalars['String']['output'];
id: Scalars['ID']['output'];
name?: Maybe<Scalars['String']['output']>;
revisions: Array<WorkflowRevision>;
revisionsPaginated: WorkflowRevisionsConnection;
runsPaginated: WorkflowRunsConnection;
updatedAt: Scalars['DateTime']['output'];
};
export type WorkflowRevisionsPaginatedArgs = {
after?: InputMaybe<Scalars['String']['input']>;
before?: InputMaybe<Scalars['String']['input']>;
first?: InputMaybe<Scalars['Int']['input']>;
last?: InputMaybe<Scalars['Int']['input']>;
};
export type WorkflowRunsPaginatedArgs = {
after?: InputMaybe<Scalars['String']['input']>;
before?: InputMaybe<Scalars['String']['input']>;
first?: InputMaybe<Scalars['Int']['input']>;
last?: InputMaybe<Scalars['Int']['input']>;
};
export type WorkflowJob = {
__typename?: 'WorkflowJob';
createdAt: Scalars['DateTime']['output'];
credentialsAppleDeviceRegistrationRequest?: Maybe<AppleDeviceRegistrationRequest>;
errors: Array<WorkflowJobError>;
id: Scalars['ID']['output'];
key: Scalars['String']['output'];
name: Scalars['String']['output'];
outputs: Scalars['JSONObject']['output'];
requiredJobKeys: Array<Scalars['String']['output']>;
status: WorkflowJobStatus;
turtleBuild?: Maybe<Build>;
turtleJobRun?: Maybe<JobRun>;
turtleSubmission?: Maybe<Submission>;
type: WorkflowJobType;
updatedAt: Scalars['DateTime']['output'];
workflowRun: WorkflowRun;
};
export type WorkflowJobError = {
__typename?: 'WorkflowJobError';
message: Scalars['String']['output'];
title: Scalars['String']['output'];
};
export type WorkflowJobMutation = {
__typename?: 'WorkflowJobMutation';
approveWorkflowJob: Scalars['ID']['output'];
@@ -7936,6 +8057,46 @@ export type WorkflowJobMutationApproveWorkflowJobArgs = {
workflowJobId: Scalars['ID']['input'];
};
export type WorkflowJobQuery = {
__typename?: 'WorkflowJobQuery';
byId: WorkflowJob;
};
export type WorkflowJobQueryByIdArgs = {
workflowJobId: Scalars['ID']['input'];
};
export enum WorkflowJobStatus {
ActionRequired = 'ACTION_REQUIRED',
Canceled = 'CANCELED',
Failure = 'FAILURE',
InProgress = 'IN_PROGRESS',
New = 'NEW',
Skipped = 'SKIPPED',
Success = 'SUCCESS'
}
export enum WorkflowJobType {
AppleDeviceRegistrationRequest = 'APPLE_DEVICE_REGISTRATION_REQUEST',
Build = 'BUILD',
Custom = 'CUSTOM',
MaestroTest = 'MAESTRO_TEST',
RequireApproval = 'REQUIRE_APPROVAL',
Submission = 'SUBMISSION',
Update = 'UPDATE'
}
export type WorkflowProjectSourceInput = {
easJsonBucketKey: Scalars['String']['input'];
projectArchiveBucketKey: Scalars['String']['input'];
type: WorkflowProjectSourceType;
};
export enum WorkflowProjectSourceType {
Gcs = 'GCS'
}
/** Look up Workflow by ID */
export type WorkflowQuery = {
__typename?: 'WorkflowQuery';
@@ -7951,13 +8112,24 @@ export type WorkflowQueryByIdArgs = {
export type WorkflowRevision = {
__typename?: 'WorkflowRevision';
blobSha: Scalars['String']['output'];
commitSha: Scalars['String']['output'];
commitSha?: Maybe<Scalars['String']['output']>;
createdAt: Scalars['DateTime']['output'];
id: Scalars['ID']['output'];
workflow: Workflow;
yamlConfig: Scalars['String']['output'];
};
export type WorkflowRevisionEdge = {
__typename?: 'WorkflowRevisionEdge';
cursor: Scalars['String']['output'];
node: WorkflowRevision;
};
export type WorkflowRevisionInput = {
fileName: Scalars['String']['input'];
yamlConfig: Scalars['String']['input'];
};
export type WorkflowRevisionQuery = {
__typename?: 'WorkflowRevisionQuery';
byId: WorkflowRevision;
@@ -7968,6 +8140,77 @@ export type WorkflowRevisionQueryByIdArgs = {
workflowRevisionId: Scalars['ID']['input'];
};
export type WorkflowRevisionsConnection = {
__typename?: 'WorkflowRevisionsConnection';
edges: Array<WorkflowRevisionEdge>;
pageInfo: PageInfo;
};
export type WorkflowRun = {
__typename?: 'WorkflowRun';
createdAt: Scalars['DateTime']['output'];
gitCommitHash?: Maybe<Scalars['String']['output']>;
gitCommitMessage?: Maybe<Scalars['String']['output']>;
githubRepository?: Maybe<GitHubRepository>;
id: Scalars['ID']['output'];
initiatingUser?: Maybe<User>;
jobs: Array<WorkflowJob>;
name: Scalars['String']['output'];
pullRequestNumber?: Maybe<Scalars['Int']['output']>;
requestedGitRef?: Maybe<Scalars['String']['output']>;
status: WorkflowRunStatus;
updatedAt: Scalars['DateTime']['output'];
workflow: Workflow;
workflowRevision?: Maybe<WorkflowRevision>;
};
export type WorkflowRunEdge = {
__typename?: 'WorkflowRunEdge';
cursor: Scalars['String']['output'];
node: WorkflowRun;
};
export type WorkflowRunInput = {
projectSource: WorkflowProjectSourceInput;
};
export type WorkflowRunMutation = {
__typename?: 'WorkflowRunMutation';
createWorkflowRun: WorkflowRun;
};
export type WorkflowRunMutationCreateWorkflowRunArgs = {
appId: Scalars['ID']['input'];
workflowRevisionInput: WorkflowRevisionInput;
workflowRunInput: WorkflowRunInput;
};
export type WorkflowRunQuery = {
__typename?: 'WorkflowRunQuery';
byId: WorkflowRun;
};
export type WorkflowRunQueryByIdArgs = {
workflowRunId: Scalars['ID']['input'];
};
export enum WorkflowRunStatus {
ActionRequired = 'ACTION_REQUIRED',
Canceled = 'CANCELED',
Failure = 'FAILURE',
InProgress = 'IN_PROGRESS',
New = 'NEW',
Success = 'SUCCESS'
}
export type WorkflowRunsConnection = {
__typename?: 'WorkflowRunsConnection';
edges: Array<WorkflowRunEdge>;
pageInfo: PageInfo;
};
export type DeleteAndroidAppBuildCredentialsResult = {
__typename?: 'deleteAndroidAppBuildCredentialsResult';
id: Scalars['ID']['output'];
@@ -8686,6 +8929,14 @@ export type CreateUploadSessionMutationVariables = Exact<{
export type CreateUploadSessionMutation = { __typename?: 'RootMutation', uploadSession: { __typename?: 'UploadSession', createUploadSession: any } };
export type CreateAccountScopedUploadSessionMutationVariables = Exact<{
accountID: Scalars['ID']['input'];
type: AccountUploadSessionType;
}>;
export type CreateAccountScopedUploadSessionMutation = { __typename?: 'RootMutation', uploadSession: { __typename?: 'UploadSession', createAccountScopedUploadSession: any } };
export type MarkCliDoneInOnboardingUserPreferencesMutationVariables = Exact<{
preferences: UserPreferencesInput;
}>;
@@ -8716,6 +8967,15 @@ export type DeleteWebhookMutationVariables = Exact<{
export type DeleteWebhookMutation = { __typename?: 'RootMutation', webhook: { __typename?: 'WebhookMutation', deleteWebhook: { __typename?: 'DeleteWebhookResult', id: string } } };
export type CreateWorkflowRunMutationVariables = Exact<{
appId: Scalars['ID']['input'];
workflowRevisionInput: WorkflowRevisionInput;
workflowRunInput: WorkflowRunInput;
}>;
export type CreateWorkflowRunMutation = { __typename?: 'RootMutation', workflowRun: { __typename?: 'WorkflowRunMutation', createWorkflowRun: { __typename?: 'WorkflowRun', id: string } } };
export type AppByIdQueryVariables = Exact<{
appId: Scalars['String']['input'];
}>;
@@ -8862,7 +9122,7 @@ export type EnvironmentVariablesIncludingSensitiveByAppIdQueryVariables = Exact<
}>;
export type EnvironmentVariablesIncludingSensitiveByAppIdQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, environmentVariablesIncludingSensitive: Array<{ __typename?: 'EnvironmentVariableWithSecret', id: string, name: string, value?: string | null, environments?: Array<EnvironmentVariableEnvironment> | null, valueWithFileContent?: string | null }> } } };
export type EnvironmentVariablesIncludingSensitiveByAppIdQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, environmentVariablesIncludingSensitive: Array<{ __typename?: 'EnvironmentVariableWithSecret', id: string, name: string, value?: string | null, environments?: Array<EnvironmentVariableEnvironment> | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility: EnvironmentVariableVisibility, type: EnvironmentSecretType, valueWithFileContent?: string | null }> } } };
export type EnvironmentVariablesByAppIdQueryVariables = Exact<{
appId: Scalars['String']['input'];
@@ -8892,7 +9152,7 @@ export type EnvironmentVariablesSharedWithSensitiveQueryVariables = Exact<{
}>;
export type EnvironmentVariablesSharedWithSensitiveQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, ownerAccount: { __typename?: 'Account', id: string, environmentVariablesIncludingSensitive: Array<{ __typename?: 'EnvironmentVariableWithSecret', id: string, name: string, value?: string | null, environments?: Array<EnvironmentVariableEnvironment> | null, valueWithFileContent?: string | null }> } } } };
export type EnvironmentVariablesSharedWithSensitiveQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, ownerAccount: { __typename?: 'Account', id: string, environmentVariablesIncludingSensitive: Array<{ __typename?: 'EnvironmentVariableWithSecret', id: string, name: string, value?: string | null, environments?: Array<EnvironmentVariableEnvironment> | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility: EnvironmentVariableVisibility, type: EnvironmentSecretType, valueWithFileContent?: string | null }> } } } };
export type GoogleServiceAccountKeyByIdQueryVariables = Exact<{
ascApiKeyId: Scalars['ID']['input'];
@@ -9013,6 +9273,8 @@ export type EnvironmentSecretFragment = { __typename?: 'EnvironmentSecret', id:
export type EnvironmentVariableFragment = { __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environments?: Array<EnvironmentVariableEnvironment> | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null, type: EnvironmentSecretType };
export type EnvironmentVariableWithSecretFragment = { __typename?: 'EnvironmentVariableWithSecret', id: string, name: string, value?: string | null, environments?: Array<EnvironmentVariableEnvironment> | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility: EnvironmentVariableVisibility, type: EnvironmentSecretType };
export type RuntimeFragment = { __typename?: 'Runtime', id: string, version: string };
export type StatuspageServiceFragment = { __typename?: 'StatuspageService', id: string, name: StatuspageServiceName, status: StatuspageServiceStatus, incidents: Array<{ __typename?: 'StatuspageIncident', id: string, status: StatuspageIncidentStatus, name: string, impact: StatuspageIncidentImpact, shortlink: string }> };
@@ -3,6 +3,9 @@ import gql from 'graphql-tag';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
import { withErrorHandlingAsync } from '../client';
import {
AccountUploadSessionType,
CreateAccountScopedUploadSessionMutation,
CreateAccountScopedUploadSessionMutationVariables,
CreateUploadSessionMutation,
CreateUploadSessionMutationVariables,
UploadSessionType,
@@ -37,4 +40,39 @@ export const UploadSessionMutation = {
);
return data.uploadSession.createUploadSession;
},
async createAccountScopedUploadSessionAsync(
graphqlClient: ExpoGraphqlClient,
{
type,
accountID,
}: {
type: AccountUploadSessionType;
accountID: string;
}
): Promise<SignedUrl> {
const data = await withErrorHandlingAsync(
graphqlClient
.mutation<
CreateAccountScopedUploadSessionMutation,
CreateAccountScopedUploadSessionMutationVariables
>(
gql`
mutation CreateAccountScopedUploadSessionMutation(
$accountID: ID!
$type: AccountUploadSessionType!
) {
uploadSession {
createAccountScopedUploadSession(accountID: $accountID, type: $type)
}
}
`,
{
type,
accountID,
}
)
.toPromise()
);
return data.uploadSession.createAccountScopedUploadSession;
},
};
@@ -0,0 +1,55 @@
import gql from 'graphql-tag';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
import { withErrorHandlingAsync } from '../client';
import {
CreateWorkflowRunMutation,
CreateWorkflowRunMutationVariables,
WorkflowRevisionInput,
WorkflowRunInput,
} from '../generated';
export namespace WorkflowRunMutation {
export async function createWorkflowRunAsync(
graphqlClient: ExpoGraphqlClient,
{
appId,
workflowRevisionInput,
workflowRunInput,
}: {
appId: string;
workflowRevisionInput: WorkflowRevisionInput;
workflowRunInput: WorkflowRunInput;
}
): Promise<{ id: string }> {
const data = await withErrorHandlingAsync(
graphqlClient
.mutation<CreateWorkflowRunMutation, CreateWorkflowRunMutationVariables>(
gql`
mutation CreateWorkflowRun(
$appId: ID!
$workflowRevisionInput: WorkflowRevisionInput!
$workflowRunInput: WorkflowRunInput!
) {
workflowRun {
createWorkflowRun(
appId: $appId
workflowRevisionInput: $workflowRevisionInput
workflowRunInput: $workflowRunInput
) {
id
}
}
}
`,
{
appId,
workflowRevisionInput,
workflowRunInput,
}
)
.toPromise()
);
return { id: data.workflowRun.createWorkflowRun.id };
}
}
@@ -1,10 +1,21 @@
import { AgeRatingDeclaration, KidsAge, Rating } from '@expo/apple-utils';
import {
AgeRatingDeclaration,
KidsAgeBand,
KoreaRatingOverride,
Rating,
RatingOverride,
} from '@expo/apple-utils';
import { AttributesOf } from '../../../../utils/asc';
// @ts-expect-error: Deprecated property `gamblingAndContests` needs to be deleted from the types
// Note, both `seventeenPlus` and `gamlingAndContests` are deprecated
type AgeRatingDeclarationProps = Omit<
AttributesOf<AgeRatingDeclaration>,
'seventeenPlus' | 'gamblingAndContests'
>;
// These attributes is what we get from the API when no questions are answered
export const emptyAdvisory: AttributesOf<AgeRatingDeclaration> = {
export const emptyAdvisory: AgeRatingDeclarationProps = {
alcoholTobaccoOrDrugUseOrReferences: null,
contests: null,
gamblingSimulated: null,
@@ -20,11 +31,12 @@ export const emptyAdvisory: AttributesOf<AgeRatingDeclaration> = {
gambling: false,
unrestrictedWebAccess: false,
kidsAgeBand: null,
seventeenPlus: false,
ageRatingOverride: null,
koreaAgeRatingOverride: null,
lootBox: null,
};
// @ts-expect-error: Deprecated property `gamblingAndContests` needs to be deleted from the types
export const leastRestrictiveAdvisory: AttributesOf<AgeRatingDeclaration> = {
export const leastRestrictiveAdvisory: AgeRatingDeclarationProps = {
alcoholTobaccoOrDrugUseOrReferences: Rating.NONE,
contests: Rating.NONE,
gamblingSimulated: Rating.NONE,
@@ -40,11 +52,12 @@ export const leastRestrictiveAdvisory: AttributesOf<AgeRatingDeclaration> = {
gambling: false,
unrestrictedWebAccess: false,
kidsAgeBand: null,
seventeenPlus: false,
ageRatingOverride: RatingOverride.NONE,
koreaAgeRatingOverride: KoreaRatingOverride.NONE,
lootBox: false,
};
// @ts-expect-error: Deprecated property `gamblingAndContests` needs to be deleted from the types
export const mostRestrictiveAdvisory: AttributesOf<AgeRatingDeclaration> = {
export const mostRestrictiveAdvisory: AgeRatingDeclarationProps = {
alcoholTobaccoOrDrugUseOrReferences: Rating.FREQUENT_OR_INTENSE,
contests: Rating.FREQUENT_OR_INTENSE,
gamblingSimulated: Rating.FREQUENT_OR_INTENSE,
@@ -60,11 +73,12 @@ export const mostRestrictiveAdvisory: AttributesOf<AgeRatingDeclaration> = {
gambling: true,
unrestrictedWebAccess: true,
kidsAgeBand: null,
seventeenPlus: true,
ageRatingOverride: RatingOverride.SEVENTEEN_PLUS,
koreaAgeRatingOverride: KoreaRatingOverride.NINETEEN_PLUS,
lootBox: true,
};
// @ts-expect-error: Deprecated property `gamblingAndContests` needs to be deleted from the types
export const kidsSixToEightAdvisory: AttributesOf<AgeRatingDeclaration> = {
export const kidsSixToEightAdvisory: AgeRatingDeclarationProps = {
alcoholTobaccoOrDrugUseOrReferences: Rating.NONE,
contests: Rating.NONE,
gamblingSimulated: Rating.NONE,
@@ -79,6 +93,8 @@ export const kidsSixToEightAdvisory: AttributesOf<AgeRatingDeclaration> = {
violenceRealisticProlongedGraphicOrSadistic: Rating.NONE,
gambling: false,
unrestrictedWebAccess: false,
kidsAgeBand: KidsAge.SIX_TO_EIGHT,
seventeenPlus: false,
kidsAgeBand: KidsAgeBand.SIX_TO_EIGHT,
ageRatingOverride: RatingOverride.NONE,
koreaAgeRatingOverride: KoreaRatingOverride.NONE,
lootBox: false,
};
@@ -1,4 +1,11 @@
import { AppStoreState, AppStoreVersion, Platform, ReleaseType } from '@expo/apple-utils';
import {
AppStoreState,
AppStoreVersion,
AppVersionState,
Platform,
ReleaseType,
ReviewType,
} from '@expo/apple-utils';
import { AttributesOf } from '../../../../utils/asc';
@@ -6,43 +13,43 @@ export const manualRelease: AttributesOf<AppStoreVersion> = {
platform: Platform.IOS,
versionString: '1.0.0',
appStoreState: AppStoreState.WAITING_FOR_REVIEW,
appVersionState: AppVersionState.WAITING_FOR_REVIEW,
storeIcon: null,
watchStoreIcon: null,
copyright: '2022 - ACME',
releaseType: ReleaseType.MANUAL,
earliestReleaseDate: null,
usesIdfa: null,
isWatchOnly: false,
downloadable: false,
createdDate: '2022-05-23T00:00:00.000Z',
reviewType: ReviewType.APP_STORE,
};
export const automaticRelease: AttributesOf<AppStoreVersion> = {
platform: Platform.IOS,
versionString: '2.0.0',
appStoreState: AppStoreState.WAITING_FOR_REVIEW,
appVersionState: AppVersionState.WAITING_FOR_REVIEW,
storeIcon: null,
watchStoreIcon: null,
copyright: '2022 - ACME',
releaseType: ReleaseType.AFTER_APPROVAL,
earliestReleaseDate: null,
usesIdfa: null,
isWatchOnly: false,
downloadable: false,
createdDate: '2022-05-23T00:00:00.000Z',
reviewType: ReviewType.APP_STORE,
};
export const scheduledRelease: AttributesOf<AppStoreVersion> = {
platform: Platform.IOS,
versionString: '3.0.0',
appStoreState: AppStoreState.READY_FOR_SALE,
appVersionState: AppVersionState.ACCEPTED,
storeIcon: null,
watchStoreIcon: null,
copyright: '2022 - ACME',
releaseType: ReleaseType.SCHEDULED,
earliestReleaseDate: '2022-05-29T00:00:00.000Z',
usesIdfa: null,
isWatchOnly: false,
downloadable: false,
createdDate: '2022-05-23T00:00:00.000Z',
reviewType: ReviewType.APP_STORE,
};
@@ -6,8 +6,10 @@ import {
AppStoreVersionLocalization,
AppStoreVersionPhasedRelease,
CategoryIds,
KoreaRatingOverride,
PhasedReleaseState,
Rating,
RatingOverride,
ReleaseType,
} from '@expo/apple-utils';
@@ -35,24 +37,26 @@ export class AppleConfigReader {
}
return {
ageRatingOverride: attributes.ageRatingOverride ?? RatingOverride.NONE,
alcoholTobaccoOrDrugUseOrReferences:
attributes.alcoholTobaccoOrDrugUseOrReferences ?? Rating.NONE,
contests: attributes.contests ?? Rating.NONE,
gambling: attributes.gambling ?? false,
gamblingSimulated: attributes.gamblingSimulated ?? Rating.NONE,
horrorOrFearThemes: attributes.horrorOrFearThemes ?? Rating.NONE,
kidsAgeBand: attributes.kidsAgeBand ?? null,
koreaAgeRatingOverride: attributes.koreaAgeRatingOverride ?? KoreaRatingOverride.NONE,
lootBox: attributes.lootBox ?? false,
matureOrSuggestiveThemes: attributes.matureOrSuggestiveThemes ?? Rating.NONE,
medicalOrTreatmentInformation: attributes.medicalOrTreatmentInformation ?? Rating.NONE,
profanityOrCrudeHumor: attributes.profanityOrCrudeHumor ?? Rating.NONE,
sexualContentGraphicAndNudity: attributes.sexualContentGraphicAndNudity ?? Rating.NONE,
sexualContentOrNudity: attributes.sexualContentOrNudity ?? Rating.NONE,
unrestrictedWebAccess: attributes.unrestrictedWebAccess ?? false,
violenceCartoonOrFantasy: attributes.violenceCartoonOrFantasy ?? Rating.NONE,
violenceRealistic: attributes.violenceRealistic ?? Rating.NONE,
violenceRealisticProlongedGraphicOrSadistic:
attributes.violenceRealisticProlongedGraphicOrSadistic ?? Rating.NONE,
gambling: attributes.gambling ?? false,
unrestrictedWebAccess: attributes.unrestrictedWebAccess ?? false,
kidsAgeBand: attributes.kidsAgeBand ?? null,
seventeenPlus: attributes.seventeenPlus ?? false,
};
}
@@ -6,7 +6,9 @@ import {
AppStoreVersion,
AppStoreVersionLocalization,
AppStoreVersionPhasedRelease,
KoreaRatingOverride,
Rating,
RatingOverride,
ReleaseType,
} from '@expo/apple-utils';
@@ -28,26 +30,31 @@ export class AppleConfigWriter {
};
}
public setAgeRating(attributes: AttributesOf<AgeRatingDeclaration>): void {
// Note, both `seventeenPlus` and `gamlingAndContests` are deprecated
public setAgeRating(
attributes: Omit<AttributesOf<AgeRatingDeclaration>, 'seventeenPlus' | 'gamblingAndContests'>
): void {
this.schema.advisory = {
ageRatingOverride: attributes.ageRatingOverride ?? RatingOverride.NONE,
alcoholTobaccoOrDrugUseOrReferences:
attributes.alcoholTobaccoOrDrugUseOrReferences ?? Rating.NONE,
contests: attributes.contests ?? Rating.NONE,
gambling: attributes.gambling ?? false,
gamblingSimulated: attributes.gamblingSimulated ?? Rating.NONE,
horrorOrFearThemes: attributes.horrorOrFearThemes ?? Rating.NONE,
kidsAgeBand: attributes.kidsAgeBand ?? null,
koreaAgeRatingOverride: attributes.koreaAgeRatingOverride ?? KoreaRatingOverride.NONE,
lootBox: attributes.lootBox ?? false,
matureOrSuggestiveThemes: attributes.matureOrSuggestiveThemes ?? Rating.NONE,
medicalOrTreatmentInformation: attributes.medicalOrTreatmentInformation ?? Rating.NONE,
profanityOrCrudeHumor: attributes.profanityOrCrudeHumor ?? Rating.NONE,
sexualContentGraphicAndNudity: attributes.sexualContentGraphicAndNudity ?? Rating.NONE,
sexualContentOrNudity: attributes.sexualContentOrNudity ?? Rating.NONE,
unrestrictedWebAccess: attributes.unrestrictedWebAccess ?? false,
violenceCartoonOrFantasy: attributes.violenceCartoonOrFantasy ?? Rating.NONE,
violenceRealistic: attributes.violenceRealistic ?? Rating.NONE,
violenceRealisticProlongedGraphicOrSadistic:
attributes.violenceRealisticProlongedGraphicOrSadistic ?? Rating.NONE,
gambling: attributes.gambling ?? false,
unrestrictedWebAccess: attributes.unrestrictedWebAccess ?? false,
kidsAgeBand: attributes.kidsAgeBand ?? null,
seventeenPlus: attributes.seventeenPlus ?? false,
};
}
+5 -1
View File
@@ -13,7 +13,11 @@ export interface AppleMetadata {
review?: AppleReview;
}
export type AppleAdvisory = Partial<AgeRatingDeclarationProps>;
// The omited properties are deprecated
export type AppleAdvisory = Omit<
Partial<AgeRatingDeclarationProps>,
'seventeenPlus' | 'gamblingAndContests'
>;
/** Apps can define up to two categories, or categories with up to two subcategories */
export type AppleCategory = (string | string[])[];
@@ -11,12 +11,12 @@ import { uploadFileAtPathToGCSAsync } from '../uploads';
import { getTmpDirectory } from '../utils/paths';
export async function maybeUploadFingerprintAsync({
runtimeVersion,
hash,
fingerprint,
graphqlClient,
localBuildMode,
}: {
runtimeVersion: string;
hash: string;
fingerprint: {
fingerprintSources: object[];
isDebugFingerprintSource: boolean;
@@ -24,20 +24,20 @@ export async function maybeUploadFingerprintAsync({
graphqlClient: ExpoGraphqlClient;
localBuildMode?: LocalBuildMode;
}): Promise<{
runtimeVersion: string;
hash: string;
fingerprintSource?: FingerprintSource;
}> {
await fs.mkdirp(getTmpDirectory());
const fingerprintLocation = path.join(getTmpDirectory(), `${uuidv4()}-runtime-fingerprint.json`);
await fs.writeJSON(fingerprintLocation, {
hash: runtimeVersion,
hash,
sources: fingerprint.fingerprintSources,
});
if (localBuildMode === LocalBuildMode.LOCAL_BUILD_PLUGIN) {
return {
runtimeVersion,
hash,
fingerprintSource: {
type: FingerprintSourceType.PATH,
path: fingerprintLocation,
@@ -62,14 +62,14 @@ export async function maybeUploadFingerprintAsync({
Log.warn(errMessage);
return {
runtimeVersion,
hash,
};
} finally {
await fs.remove(fingerprintLocation);
}
return {
runtimeVersion,
hash,
fingerprintSource: {
type: FingerprintSourceType.GCS,
bucketKey: fingerprintGCSBucketKey,
@@ -0,0 +1,47 @@
import chalk from 'chalk';
import fs from 'node:fs';
import path from 'node:path';
import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
import { AccountUploadSessionType } from '../graphql/generated';
import { uploadAccountScopedFileAtPathToGCSAsync } from '../uploads';
import { formatBytes } from '../utils/files';
import { createProgressTracker } from '../utils/progress';
/**
* Uploads the `eas.json` file to GCS as account-scoped object.
* Used in workflows. Takes care of logging progress.
*/
export async function uploadAccountScopedEasJsonAsync({
graphqlClient,
accountId,
projectDir,
}: {
graphqlClient: ExpoGraphqlClient;
accountId: string;
projectDir: string;
}): Promise<{ easJsonBucketKey: string }> {
const easJsonFilePath = path.join(projectDir, 'eas.json');
const easJsonFileStat = await fs.promises.stat(easJsonFilePath);
if (easJsonFileStat.size > 1024 * 1024) {
throw new Error('eas.json is too big. Maximum allowed size is 1MB.');
}
const easJsonBucketKey = await uploadAccountScopedFileAtPathToGCSAsync(graphqlClient, {
accountId,
type: AccountUploadSessionType.WorkflowsProjectSources,
path: easJsonFilePath,
handleProgressEvent: createProgressTracker({
total: easJsonFileStat.size,
message: ratio =>
`Uploading eas.json to EAS (${formatBytes(easJsonFileStat.size * ratio)} / ${formatBytes(
easJsonFileStat.size
)})`,
completedMessage: (duration: string) => `Uploaded eas.json to EAS ${chalk.dim(duration)}`,
}),
});
return { easJsonBucketKey };
}
@@ -0,0 +1,74 @@
import chalk from 'chalk';
import fs from 'node:fs';
import { makeProjectTarballAsync } from '../build/utils/repository';
import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
import { AccountUploadSessionType } from '../graphql/generated';
import Log, { learnMore } from '../log';
import { uploadAccountScopedFileAtPathToGCSAsync } from '../uploads';
import { formatBytes } from '../utils/files';
import { createProgressTracker } from '../utils/progress';
import { Client } from '../vcs/vcs';
/**
* Archives the project and uploads it to GCS as account-scoped object.
* Used in workflows. Takes care of logging progress and cleaning up the tarball.
*/
export async function uploadAccountScopedProjectSourceAsync({
graphqlClient,
vcsClient,
accountId,
}: {
graphqlClient: ExpoGraphqlClient;
vcsClient: Client;
accountId: string;
}): Promise<{ projectArchiveBucketKey: string }> {
let projectTarballPath;
try {
Log.newLine();
Log.log(
`Compressing project files and uploading to EAS. ${learnMore(
'https://expo.fyi/eas-build-archive'
)}`
);
const projectTarball = await makeProjectTarballAsync(vcsClient);
projectTarballPath = projectTarball.path;
if (projectTarball.size > 1024 * 1024 * 100) {
Log.warn(
`Your project archive is ${formatBytes(
projectTarball.size
)}. You can reduce its size and the time it takes to upload by excluding files that are unnecessary for the build process in ${chalk.bold(
'.easignore'
)} file. ${learnMore('https://expo.fyi/eas-build-archive')}`
);
}
if (projectTarball.size > 2 * 1024 * 1024 * 1024) {
throw new Error('Project archive is too big. Maximum allowed size is 2GB.');
}
const projectArchiveBucketKey = await uploadAccountScopedFileAtPathToGCSAsync(graphqlClient, {
accountId,
type: AccountUploadSessionType.WorkflowsProjectSources,
path: projectTarball.path,
handleProgressEvent: createProgressTracker({
total: projectTarball.size,
message: ratio =>
`Uploading project archive to EAS (${formatBytes(
projectTarball.size * ratio
)} / ${formatBytes(projectTarball.size)})`,
completedMessage: (duration: string) =>
`Uploaded project archive to EAS ${chalk.dim(duration)}`,
}),
});
return { projectArchiveBucketKey };
} finally {
if (projectTarballPath) {
await fs.promises.rm(projectTarballPath);
}
}
}
+24 -1
View File
@@ -5,7 +5,7 @@ import promiseRetry from 'promise-retry';
import { ExpoGraphqlClient } from './commandUtils/context/contextUtils/createGraphqlClient';
import fetch from './fetch';
import { UploadSessionType } from './graphql/generated';
import { AccountUploadSessionType, UploadSessionType } from './graphql/generated';
import { SignedUrl, UploadSessionMutation } from './graphql/mutations/UploadSessionMutation';
import { ProgressHandler } from './utils/progress';
@@ -26,6 +26,29 @@ export async function uploadFileAtPathToGCSAsync(
return signedUrl.bucketKey;
}
export async function uploadAccountScopedFileAtPathToGCSAsync(
graphqlClient: ExpoGraphqlClient,
{
type,
accountId,
path,
handleProgressEvent,
}: {
type: AccountUploadSessionType;
accountId: string;
path: string;
handleProgressEvent: ProgressHandler;
}
): Promise<string> {
const signedUrl = await UploadSessionMutation.createAccountScopedUploadSessionAsync(
graphqlClient,
{ type, accountID: accountId }
);
await uploadWithSignedUrlWithProgressAsync(path, signedUrl, handleProgressEvent);
return signedUrl.bucketKey;
}
export async function uploadWithPresignedPostWithRetryAsync(
file: string,
presignedPost: PresignedPost,
@@ -0,0 +1,36 @@
import { Env, Workflow } from '@expo/eas-build-job';
import { silent as silentResolveFrom } from 'resolve-from';
export async function createFingerprintAsync(
projectDir: string,
options: {
workflow: Workflow;
platform: string;
debug?: boolean;
env: Env | undefined;
cwd?: string;
}
): Promise<{
hash: string;
sources: object[];
isDebugSource: boolean;
} | null> {
// @expo/fingerprint is exported in the expo package for SDK 52+
const fingerprintPath = silentResolveFrom(projectDir, 'expo/fingerprint');
if (!fingerprintPath) {
return null;
}
const Fingerprint = require(fingerprintPath);
const fingerprintOptions: Record<string, any> = {};
if (options.platform) {
fingerprintOptions.platforms = [options.platform];
}
if (options.workflow === Workflow.MANAGED) {
fingerprintOptions.ignorePaths = ['android/**/*', 'ios/**/*'];
}
if (options.debug) {
fingerprintOptions.debug = true;
}
// eslint-disable-next-line @typescript-eslint/return-await
return await Fingerprint.createFingerprintAsync(projectDir, fingerprintOptions);
}
+2 -1
View File
@@ -1,4 +1,5 @@
import chalk from 'chalk';
import { randomUUID } from 'node:crypto';
import { endTimer, formatMilliseconds, startTimer } from './timer';
import { Ora, ora } from '../ora';
@@ -29,7 +30,7 @@ export function createProgressTracker({
let transferredSoFar = 0;
let current = 0;
const timerLabel = String(Date.now());
const timerLabel = String(randomUUID());
const getMessage = (v: number, total: number): string => {
const ratio = Math.min(Math.max(v, 0), 1);
@@ -0,0 +1,109 @@
import fs from 'fs/promises';
import { vol } from 'memfs';
import { WorkflowValidate } from '../../commands/workflow/validate';
jest.mock('fs/promises');
jest.mock('../../log');
jest.mock('../../ora', () => ({
ora: () => ({
start: () => ({
succeed: jest.fn(),
fail: jest.fn(),
}),
}),
}));
describe('WorkflowValidate', () => {
const mockValidYaml = `
name: workflow
on: push
jobs:
build:
steps:
- run: echo "Hello"
`;
const mockInvalidYaml = `
name: workflow
on: : : : invalid
`;
let command: WorkflowValidate;
beforeEach(() => {
vol.reset();
jest.resetAllMocks();
process.exit = jest.fn(() => {
throw new Error();
});
});
describe('file validation', () => {
describe('when file exists', () => {
beforeEach(() => {
(fs.access as jest.Mock).mockResolvedValue(undefined);
});
it('validates a correct YAML file', async () => {
(fs.readFile as jest.Mock).mockResolvedValue(mockValidYaml);
command = new WorkflowValidate(['./workflow.yml'], {} as any);
await expect(command.runAsync()).resolves.not.toThrow();
});
it('accepts both .yml and .yaml extensions', async () => {
(fs.readFile as jest.Mock).mockResolvedValue(mockValidYaml);
command = new WorkflowValidate(['./workflow.yml'], {} as any);
await expect(command.runAsync()).resolves.not.toThrow();
command = new WorkflowValidate(['./workflow.yaml'], {} as any);
await expect(command.runAsync()).resolves.not.toThrow();
});
it('throws error for empty YAML file', async () => {
(fs.readFile as jest.Mock).mockResolvedValue('');
command = new WorkflowValidate(['./workflow.yml'], {} as any);
await expect(command.runAsync()).rejects.toThrow();
});
it('throws error for invalid YAML syntax', async () => {
(fs.readFile as jest.Mock).mockResolvedValue(mockInvalidYaml);
command = new WorkflowValidate(['./workflow.yml'], {} as any);
await expect(command.runAsync()).rejects.toThrow();
});
it('throws error for invalid file extension', async () => {
command = new WorkflowValidate(['./workflow.txt'], {} as any);
await expect(command.runAsync()).rejects.toThrow();
});
});
describe('when file does not exist', () => {
beforeEach(() => {
(fs.access as jest.Mock).mockRejectedValue(new Error('ENOENT'));
});
it('throws appropriate error', async () => {
command = new WorkflowValidate(['./nonexistent.yml'], {} as any);
await expect(command.runAsync()).rejects.toThrow();
});
});
});
describe('error handling', () => {
it('handles unexpected errors gracefully', async () => {
(fs.access as jest.Mock).mockResolvedValue(undefined);
(fs.readFile as jest.Mock).mockRejectedValue(new Error('Unexpected error'));
command = new WorkflowValidate(['./workflow.yml'], {} as any);
await expect(command.runAsync()).rejects.toThrow();
});
});
});
Generated
+9 -4
View File
@@ -1359,10 +1359,10 @@
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.56.0.tgz#ef20350fec605a7f7035a01764731b2de0f3782b"
integrity sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==
"@expo/apple-utils@2.0.3":
version "2.0.3"
resolved "https://registry.yarnpkg.com/@expo/apple-utils/-/apple-utils-2.0.3.tgz#558f185a44533ee7b33fc9da3a76ebb953ab8777"
integrity sha512-RvV6rCvwdYvCv9c/57XHDAUfTq3RM/wQMmurrLLuYADEurwRveltO7SQ/ajpa4SrTpCzQDx2L3WZGXah7Syr6Q==
"@expo/apple-utils@2.1.0":
version "2.1.0"
resolved "https://registry.yarnpkg.com/@expo/apple-utils/-/apple-utils-2.1.0.tgz#9cabfb9fc9dab5e7835b499804ecd6da289eb3fd"
integrity sha512-RzZkPiPtdBuswnTM44LowiScej5M9J/OqTPjWTKSIXhB8veJwb1f5iAE1aqzsceXibOaz0F+4135XahRaPjVvw==
"@expo/bunyan@^4.0.0":
version "4.0.0"
@@ -14809,6 +14809,11 @@ yaml-ast-parser@^0.0.43:
resolved "https://registry.yarnpkg.com/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz#e8a23e6fb4c38076ab92995c5dca33f3d3d7c9bb"
integrity sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==
[email protected]:
version "2.6.0"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.6.0.tgz#14059ad9d0b1680d0f04d3a60fe00f3a857303c3"
integrity sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==
yaml@^1.7.2:
version "1.10.0"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.0.tgz#3b593add944876077d4d683fee01081bd9fff31e"