Compare commits

...
24 Commits
Author SHA1 Message Date
Szymon Dziedzic 008279e1dd v5.0.2 2023-08-29 13:15:39 +02:00
Cedric van Putten d00814f84b fix(eas-cli): implement variadic --platform flag when creating EAS updates (#1939)
* fix(eas-cli): implement variadic `--platform` flag when creating EAS updates

* fix(eas-cli): finish todo and set minimum `@expo/[email protected]` version for multiple `--platform` flags during export

* update CHANGELOG.md

* fix(eas-cli): be verbose about `--platform=<flag>` in bundle script
2023-08-29 13:11:49 +02:00
Expo CI 81aa127e28 update CHANGELOG.md 2023-08-28 19:05:12 +00:00
Szymon Dziedzic d321a0bccb v5.0.1 2023-08-28 20:54:10 +02:00
Szymon Dziedzic a1d86549ed [eas-cli] fix eas update passing platform argument incorrectly to expo-cli (#2028)
* [eas-cli] fix `eas update` passing `platform` argument incorrectly to `expo-cli`

* update CHANGELOG.md
2023-08-28 20:51:18 +02:00
Expo CI f7e9af913c update CHANGELOG.md 2023-08-28 14:00:12 +00:00
Szymon Dziedzic 137f9d4ac7 v5.0.0 2023-08-28 14:20:36 +02:00
Szymon Dziedzic 2ac863a9e3 upgrade eas-cli-local-build-plugin to 1.0.39 2023-08-28 14:19:20 +02:00
Quinlan Jung 11be9eba49 [ENG-9685][eas-cli] create a linked channel on build if not exists (#2017)
* [eas-cli] create linked channel on build

* refactor

* update CHANGELOG.md

* amend doc block
2023-08-25 12:07:59 -07:00
Will Schurman b36db15601 [eas-cli][updates] configure updates as well when somebody tries to run a build with channel set (#2016) 2023-08-25 09:14:29 -07:00
Piotr Szeremeta 93c5dc1a32 [ENG-9422] nvmrc support for setting node version (#1998)
* [ENG-9422][eas-cli] Use .nvmrc to set node version

* update CHANGELOG.md
2023-08-25 15:46:55 +02:00
Szymon Dziedzic c86550c0c8 [eas-cli][eas-json] add developmentClient to metadata (#2015)
* [eas-cli][eas-json] add `developmentClient` to metadata

* update CHANGELOG.md
2023-08-25 13:26:33 +02:00
Brent Vatne 36b4296d3c [.github] Add issue template config 2023-08-24 17:09:47 -07:00
Brent Vatne 8c08541ca3 Create SECURITY.md 2023-08-24 17:06:03 -07:00
Will Schurman 5a1406d39c [eas-cli] Add info to EAS Update asset upload process about asset counts and limits (#2013) 2023-08-24 09:22:30 -07:00
Radosław Krzemień 78ea88cc5f [eas-cli] [ENG-7591] Detect not provisioned devices (#2011)
* [eas-cli] Detect not provisioned devices

After selecting devices to be provisioned and making a call to App Store Connect API the result is compared with the list of chosen devices. If any are missing, a message is displayed to the user

See: https://linear.app/expo/issue/ENG-7591/detect-processing-devices-on-apple-developer-portal-and-dont-allow-the

* [eas-cli] Adjust message

Updated the message with the link to the devices page in the Apple Developer portal

See: https://linear.app/expo/issue/ENG-7591/detect-processing-devices-on-apple-developer-portal-and-dont-allow-the

* update CHANGELOG.md
2023-08-24 15:35:48 +02:00
Will Schurman 6cb02d0ccd [eas-cli][eas-update] Support republishing roll back to embedded updates (#2006) 2023-08-15 11:39:24 -04:00
Will Schurman d6c7623718 [eas-cli][eas-update] Add rollback disambiguation command (#2004) 2023-08-15 11:36:18 -04:00
Quinlan Jung 32142b4fe8 [eas-cli] more branch mapping utils (#2003)
* [eas-cli] more branch mapping utils

* update CHANGELOG.md
2023-08-14 14:51:29 -07:00
Will Schurman 6bdee0f395 [eas-cli][update] Only export at most ios and android dist (#2002) 2023-08-14 17:28:06 -04:00
Quinlan Jung baf94a21c3 [eas-cli] more branch map utility functions (#2001)
* [eas-cli] more branch map utility functions

* update CHANGELOG.md

* feedback
2023-08-11 11:35:47 -07:00
Radoslaw Krzemien 162d64bce6 Revert "[eas-cli] Update oclif version"
This reverts commit d16c1fc757.
2023-08-11 12:22:56 +02:00
Radoslaw Krzemien d16c1fc757 [eas-cli] Update oclif version
Updated oclif version

See: https://linear.app/expo/issue/ENG-9175/update-oclif-in-eas-cli
2023-08-11 12:22:17 +02:00
Expo CI e42ea7e2ec update CHANGELOG.md 2023-08-10 10:26:10 +00:00
38 changed files with 806 additions and 201 deletions

No files matched your search

+5
View File
@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Expo Developers Discord
url: https://chat.expo.dev/
about: Join other developers in discussions regarding Expo and EAS.
+37
View File
@@ -10,6 +10,43 @@ This is the log of notable changes to EAS CLI and related packages.
### 🐛 Bug fixes
- Add proper expo cli `--platform` flag handling when exporting updates. ([#1939](https://github.com/expo/eas-cli/pull/1939) by [@byCedric](https://github.com/byCedric))
### 🧹 Chores
## [5.0.1](https://github.com/expo/eas-cli/releases/tag/v5.0.1) - 2023-08-28
### 🐛 Bug fixes
- Pass `platform` argument to expo-cli correctly when using the `eas update` command. ([#2028](https://github.com/expo/eas-cli/pull/2028) by [@szdziedzic](https://github.com/szdziedzic))
## [5.0.0](https://github.com/expo/eas-cli/releases/tag/v5.0.0) - 2023-08-28
### 🛠 Breaking changes
- Only export at most ios and android dist for EAS updates. ([#2002](https://github.com/expo/eas-cli/pull/2002) by [@wschurman](https://github.com/wschurman))
### 🎉 New features
- Add rollback disambiguation command. ([#2004](https://github.com/expo/eas-cli/pull/2004) by [@wschurman](https://github.com/wschurman))
- Detect devices that fail to be provisioned, list them to the user and show the explanation message with the link to the devices page to check actual status. ([#2011](https://github.com/expo/eas-cli/pull/2011) by [@radoslawkrzemien](https://github.com/radoslawkrzemien))
- Add info to EAS Update asset upload process about asset counts and limits. ([#2013](https://github.com/expo/eas-cli/pull/2013) by [@wschurman](https://github.com/wschurman))
- .nvmrc support for setting node version. ([#1954](https://github.com/expo/eas-cli/pull/1954) by [@khamilowicz](https://github.com/khamilowicz))
### 🐛 Bug fixes
- Support republishing roll back to embedded updates. ([#2006](https://github.com/expo/eas-cli/pull/2006) by [@wschurman](https://github.com/wschurman))
- Configure updates as well when somebody tries to run a build with channel set. ([#2016](https://github.com/expo/eas-cli/pull/2016) by [@wschurman](https://github.com/wschurman))
### 🧹 Chores
- More branch map utility functions. ([#2001](https://github.com/expo/eas-cli/pull/2001) by [@quinlanj](https://github.com/quinlanj))
- More branch mapping utils. ([#2003](https://github.com/expo/eas-cli/pull/2003) by [@quinlanj](https://github.com/quinlanj))
- Create a linked channel on build if not exists. ([#2017](https://github.com/expo/eas-cli/pull/2017) by [@quinlanj](https://github.com/quinlanj))
- Add `developmentClient` to metadata. ([#2015](https://github.com/expo/eas-cli/pull/2015) by [@szdziedzic](https://github.com/szdziedzic))
## [4.1.2](https://github.com/expo/eas-cli/releases/tag/v4.1.2) - 2023-08-10
### 🧹 Chores
- Make branch mapping utility files have no dependencies. ([#1993](https://github.com/expo/eas-cli/pull/1993) by [@quinlanj](https://github.com/quinlanj))
+5
View File
@@ -0,0 +1,5 @@
# Security Policy
## Reporting a Vulnerability
Instead of opening a GitHub issue for security vulnerabilities, send an email to our secure inbox: secure@expo.io.
+1 -1
View File
@@ -1,6 +1,6 @@
{
"npmClient": "yarn",
"useWorkspaces": true,
"version": "4.1.2",
"version": "5.0.2",
"$schema": "node_modules/lerna/schemas/lerna-schema.json"
}
+55 -55
View File
@@ -133,7 +133,7 @@ ALIASES
$ eas login
```
_See code: [src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/account/login.ts)_
_See code: [src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/account/login.ts)_
## `eas account:logout`
@@ -150,7 +150,7 @@ ALIASES
$ eas logout
```
_See code: [src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/account/logout.ts)_
_See code: [src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/account/logout.ts)_
## `eas account:view`
@@ -167,7 +167,7 @@ ALIASES
$ eas whoami
```
_See code: [src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/account/view.ts)_
_See code: [src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/account/view.ts)_
## `eas analytics [STATUS]`
@@ -181,7 +181,7 @@ DESCRIPTION
display or change analytics settings
```
_See code: [src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/analytics.ts)_
_See code: [src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/analytics.ts)_
## `eas autocomplete [SHELL]`
@@ -231,7 +231,7 @@ DESCRIPTION
create a branch
```
_See code: [src/commands/branch/create.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/branch/create.ts)_
_See code: [src/commands/branch/create.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/branch/create.ts)_
## `eas branch:delete [NAME]`
@@ -252,7 +252,7 @@ DESCRIPTION
delete a branch
```
_See code: [src/commands/branch/delete.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/branch/delete.ts)_
_See code: [src/commands/branch/delete.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/branch/delete.ts)_
## `eas branch:list`
@@ -272,7 +272,7 @@ DESCRIPTION
list all branches
```
_See code: [src/commands/branch/list.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/branch/list.ts)_
_See code: [src/commands/branch/list.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/branch/list.ts)_
## `eas branch:rename`
@@ -292,7 +292,7 @@ DESCRIPTION
rename a branch
```
_See code: [src/commands/branch/rename.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/branch/rename.ts)_
_See code: [src/commands/branch/rename.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/branch/rename.ts)_
## `eas branch:view [NAME]`
@@ -315,7 +315,7 @@ DESCRIPTION
view a branch
```
_See code: [src/commands/branch/view.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/branch/view.ts)_
_See code: [src/commands/branch/view.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/branch/view.ts)_
## `eas build`
@@ -345,7 +345,7 @@ DESCRIPTION
start a build
```
_See code: [src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/build/index.ts)_
_See code: [src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/build/index.ts)_
## `eas build:cancel [BUILD_ID]`
@@ -362,7 +362,7 @@ DESCRIPTION
cancel a build
```
_See code: [src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/build/cancel.ts)_
_See code: [src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/build/cancel.ts)_
## `eas build:configure`
@@ -379,7 +379,7 @@ DESCRIPTION
configure the project to support EAS Build
```
_See code: [src/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/build/configure.ts)_
_See code: [src/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/build/configure.ts)_
## `eas build:inspect`
@@ -414,7 +414,7 @@ DESCRIPTION
inspect the state of the project at specific build stages, useful for troubleshooting
```
_See code: [src/commands/build/inspect.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/build/inspect.ts)_
_See code: [src/commands/build/inspect.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/build/inspect.ts)_
## `eas build:list`
@@ -452,7 +452,7 @@ DESCRIPTION
list all builds for your project
```
_See code: [src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/build/list.ts)_
_See code: [src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/build/list.ts)_
## `eas build:resign`
@@ -478,7 +478,7 @@ DESCRIPTION
re-sign a build archive
```
_See code: [src/commands/build/resign.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/build/resign.ts)_
_See code: [src/commands/build/resign.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/build/resign.ts)_
## `eas build:run`
@@ -502,7 +502,7 @@ DESCRIPTION
run simulator/emulator builds from eas-cli
```
_See code: [src/commands/build/run.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/build/run.ts)_
_See code: [src/commands/build/run.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/build/run.ts)_
## `eas build:submit`
@@ -551,7 +551,7 @@ DESCRIPTION
get the latest version from EAS servers
```
_See code: [src/commands/build/version/get.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/build/version/get.ts)_
_See code: [src/commands/build/version/get.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/build/version/get.ts)_
## `eas build:version:set`
@@ -570,7 +570,7 @@ DESCRIPTION
update version of an app
```
_See code: [src/commands/build/version/set.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/build/version/set.ts)_
_See code: [src/commands/build/version/set.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/build/version/set.ts)_
## `eas build:version:sync`
@@ -589,7 +589,7 @@ DESCRIPTION
update a version in native code with a value stored on EAS servers
```
_See code: [src/commands/build/version/sync.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/build/version/sync.ts)_
_See code: [src/commands/build/version/sync.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/build/version/sync.ts)_
## `eas build:view [BUILD_ID]`
@@ -606,7 +606,7 @@ DESCRIPTION
view a build for your project
```
_See code: [src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/build/view.ts)_
_See code: [src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/build/view.ts)_
## `eas channel:create [NAME]`
@@ -627,7 +627,7 @@ DESCRIPTION
create a channel
```
_See code: [src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/channel/create.ts)_
_See code: [src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/channel/create.ts)_
## `eas channel:edit [NAME]`
@@ -649,7 +649,7 @@ DESCRIPTION
point a channel at a new branch
```
_See code: [src/commands/channel/edit.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/channel/edit.ts)_
_See code: [src/commands/channel/edit.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/channel/edit.ts)_
## `eas channel:list`
@@ -669,7 +669,7 @@ DESCRIPTION
list all channels
```
_See code: [src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/channel/list.ts)_
_See code: [src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/channel/list.ts)_
## `eas channel:rollout [CHANNEL]`
@@ -701,7 +701,7 @@ DESCRIPTION
Roll a new branch out on a channel incrementally.
```
_See code: [src/commands/channel/rollout.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/channel/rollout.ts)_
_See code: [src/commands/channel/rollout.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/channel/rollout.ts)_
## `eas channel:view [NAME]`
@@ -724,7 +724,7 @@ DESCRIPTION
view a channel
```
_See code: [src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/channel/view.ts)_
_See code: [src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/channel/view.ts)_
## `eas config`
@@ -745,7 +745,7 @@ DESCRIPTION
display project configuration (app.json + eas.json)
```
_See code: [src/commands/config.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/config.ts)_
_See code: [src/commands/config.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/config.ts)_
## `eas credentials`
@@ -762,7 +762,7 @@ DESCRIPTION
manage credentials
```
_See code: [src/commands/credentials.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/credentials.ts)_
_See code: [src/commands/credentials.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/credentials.ts)_
## `eas device:create`
@@ -776,7 +776,7 @@ DESCRIPTION
register new Apple Devices to use for internal distribution
```
_See code: [src/commands/device/create.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/device/create.ts)_
_See code: [src/commands/device/create.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/device/create.ts)_
## `eas device:delete`
@@ -796,7 +796,7 @@ DESCRIPTION
remove a registered device from your account
```
_See code: [src/commands/device/delete.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/device/delete.ts)_
_See code: [src/commands/device/delete.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/device/delete.ts)_
## `eas device:list`
@@ -817,7 +817,7 @@ DESCRIPTION
list all registered devices for your account
```
_See code: [src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/device/list.ts)_
_See code: [src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/device/list.ts)_
## `eas device:rename`
@@ -838,7 +838,7 @@ DESCRIPTION
rename a registered device
```
_See code: [src/commands/device/rename.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/device/rename.ts)_
_See code: [src/commands/device/rename.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/device/rename.ts)_
## `eas device:view [UDID]`
@@ -852,7 +852,7 @@ DESCRIPTION
view a device for your project
```
_See code: [src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/device/view.ts)_
_See code: [src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/device/view.ts)_
## `eas diagnostics`
@@ -866,7 +866,7 @@ DESCRIPTION
display environment info
```
_See code: [src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/diagnostics.ts)_
_See code: [src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/diagnostics.ts)_
## `eas help [COMMAND]`
@@ -954,7 +954,7 @@ DESCRIPTION
validate the local store configuration
```
_See code: [src/commands/metadata/lint.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/metadata/lint.ts)_
_See code: [src/commands/metadata/lint.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/metadata/lint.ts)_
## `eas metadata:pull`
@@ -971,7 +971,7 @@ DESCRIPTION
generate the local store configuration from the app stores
```
_See code: [src/commands/metadata/pull.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/metadata/pull.ts)_
_See code: [src/commands/metadata/pull.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/metadata/pull.ts)_
## `eas metadata:push`
@@ -988,7 +988,7 @@ DESCRIPTION
sync the local store configuration to the app stores
```
_See code: [src/commands/metadata/push.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/metadata/push.ts)_
_See code: [src/commands/metadata/push.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/metadata/push.ts)_
## `eas open`
@@ -1002,7 +1002,7 @@ DESCRIPTION
open the project page in a web browser
```
_See code: [src/commands/open.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/open.ts)_
_See code: [src/commands/open.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/open.ts)_
## `eas project:info`
@@ -1016,7 +1016,7 @@ DESCRIPTION
information about the current project
```
_See code: [src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/project/info.ts)_
_See code: [src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/project/info.ts)_
## `eas project:init`
@@ -1038,7 +1038,7 @@ ALIASES
$ eas init
```
_See code: [src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/project/init.ts)_
_See code: [src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/project/init.ts)_
## `eas secret:create`
@@ -1061,7 +1061,7 @@ DESCRIPTION
create an environment secret on the current project or owner account
```
_See code: [src/commands/secret/create.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/secret/create.ts)_
_See code: [src/commands/secret/create.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/secret/create.ts)_
## `eas secret:delete`
@@ -1079,7 +1079,7 @@ DESCRIPTION
delete an environment secret by ID
```
_See code: [src/commands/secret/delete.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/secret/delete.ts)_
_See code: [src/commands/secret/delete.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/secret/delete.ts)_
## `eas secret:list`
@@ -1093,7 +1093,7 @@ DESCRIPTION
list environment secrets available for your current app
```
_See code: [src/commands/secret/list.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/secret/list.ts)_
_See code: [src/commands/secret/list.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/secret/list.ts)_
## `eas secret:push`
@@ -1113,7 +1113,7 @@ DESCRIPTION
read environment secrets from env file and store on the server
```
_See code: [src/commands/secret/push.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/secret/push.ts)_
_See code: [src/commands/secret/push.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/secret/push.ts)_
## `eas submit`
@@ -1143,7 +1143,7 @@ ALIASES
$ eas build:submit
```
_See code: [src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/submit.ts)_
_See code: [src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/submit.ts)_
## `eas update`
@@ -1176,7 +1176,7 @@ DESCRIPTION
publish an update group
```
_See code: [src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/update/index.ts)_
_See code: [src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/update/index.ts)_
## `eas update:configure`
@@ -1194,7 +1194,7 @@ DESCRIPTION
configure the project to support EAS Update
```
_See code: [src/commands/update/configure.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/update/configure.ts)_
_See code: [src/commands/update/configure.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/update/configure.ts)_
## `eas update:delete GROUPID`
@@ -1215,7 +1215,7 @@ DESCRIPTION
delete all the updates in an update group
```
_See code: [src/commands/update/delete.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/update/delete.ts)_
_See code: [src/commands/update/delete.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/update/delete.ts)_
## `eas update:list`
@@ -1237,7 +1237,7 @@ DESCRIPTION
view the recent updates
```
_See code: [src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/update/list.ts)_
_See code: [src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/update/list.ts)_
## `eas update:republish`
@@ -1264,7 +1264,7 @@ DESCRIPTION
roll back to an existing update
```
_See code: [src/commands/update/republish.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/update/republish.ts)_
_See code: [src/commands/update/republish.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/update/republish.ts)_
## `eas update:view GROUPID`
@@ -1284,7 +1284,7 @@ DESCRIPTION
update group details
```
_See code: [src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/update/view.ts)_
_See code: [src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/update/view.ts)_
## `eas webhook:create`
@@ -1305,7 +1305,7 @@ DESCRIPTION
create a webhook
```
_See code: [src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/webhook/create.ts)_
_See code: [src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/webhook/create.ts)_
## `eas webhook:delete [ID]`
@@ -1325,7 +1325,7 @@ DESCRIPTION
delete a webhook
```
_See code: [src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/webhook/delete.ts)_
_See code: [src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/webhook/delete.ts)_
## `eas webhook:list`
@@ -1343,7 +1343,7 @@ DESCRIPTION
list webhooks
```
_See code: [src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/webhook/list.ts)_
_See code: [src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/webhook/list.ts)_
## `eas webhook:update`
@@ -1365,7 +1365,7 @@ DESCRIPTION
update a webhook
```
_See code: [src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/webhook/update.ts)_
_See code: [src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/webhook/update.ts)_
## `eas webhook:view ID`
@@ -1382,7 +1382,7 @@ DESCRIPTION
view a webhook
```
_See code: [src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v4.1.2/packages/eas-cli/src/commands/webhook/view.ts)_
_See code: [src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v5.0.2/packages/eas-cli/src/commands/webhook/view.ts)_
## `eas whoami`
+3 -3
View File
@@ -1,7 +1,7 @@
{
"name": "eas-cli",
"description": "EAS command line tool",
"version": "4.1.2",
"version": "5.0.2",
"author": "Expo <[email protected]>",
"bin": {
"eas": "./bin/run"
@@ -13,8 +13,8 @@
"@expo/config": "8.1.2",
"@expo/config-plugins": "7.2.4",
"@expo/config-types": "49.0.0",
"@expo/eas-build-job": "1.0.30",
"@expo/eas-json": "4.1.0",
"@expo/eas-build-job": "1.0.39",
"@expo/eas-json": "5.0.0",
"@expo/json-file": "8.2.37",
"@expo/multipart-body-parser": "1.1.0",
"@expo/osascript": "2.0.33",
+1
View File
@@ -55,4 +55,5 @@ export interface BuildContext<T extends Platform> {
customBuildConfigMetadata?: CustomBuildConfigMetadata;
android: T extends Platform.ANDROID ? AndroidBuildContext : undefined;
ios: T extends Platform.IOS ? IosBuildContext : undefined;
developmentClient: boolean;
}
@@ -60,6 +60,12 @@ export async function createBuildContextAsync<T extends Platform>({
const workflow = await resolveWorkflowAsync(projectDir, platform);
const accountId = account.id;
const runFromCI = getenv.boolish('CI', false);
const developmentClient =
buildProfile.developmentClient ??
(platform === Platform.ANDROID
? (buildProfile as BuildProfile<Platform.ANDROID>)?.gradleCommand === ':app:assembleDebug'
: (buildProfile as BuildProfile<Platform.IOS>)?.buildConfiguration === 'Debug') ??
false;
const credentialsCtx = new CredentialsContext({
projectInfo: { exp, projectId },
@@ -120,6 +126,7 @@ export async function createBuildContextAsync<T extends Platform>({
message,
runFromCI,
customBuildConfigMetadata,
developmentClient,
};
if (platform === Platform.ANDROID) {
const common = commonContext as CommonContext<Platform.ANDROID>;
+1 -1
View File
@@ -6,7 +6,7 @@ import semver from 'semver';
import { ora } from '../ora';
const PLUGIN_PACKAGE_NAME = 'eas-cli-local-build-plugin';
const PLUGIN_PACKAGE_VERSION = '1.0.38';
const PLUGIN_PACKAGE_VERSION = '1.0.39';
export enum LocalBuildMode {
/**
+1
View File
@@ -63,6 +63,7 @@ export async function collectMetadataAsync<T extends Platform>(
runFromCI: ctx.runFromCI,
buildMode: ctx.buildProfile.config ? BuildMode.CUSTOM : BuildMode.BUILD,
customWorkflowName: ctx.customBuildConfigMetadata?.workflowName,
developmentClient: ctx.developmentClient,
};
return sanitizeMetadata(metadata);
}
@@ -1,3 +1,4 @@
import { ExpoConfig } from '@expo/config-types';
import { Platform, Workflow } from '@expo/eas-build-job';
import {
AppVersionSource,
@@ -13,6 +14,7 @@ import chalk from 'chalk';
import nullthrows from 'nullthrows';
import { Analytics } from '../analytics/AnalyticsManager';
import { createAndLinkChannelAsync, doesChannelExistAsync } from '../channel/queries';
import { DynamicConfigContextFn } from '../commandUtils/context/DynamicProjectConfigContextField';
import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
import {
@@ -38,9 +40,9 @@ import {
import { checkExpoSdkIsSupportedAsync } from '../project/expoSdk';
import { validateMetroConfigForManagedWorkflowAsync } from '../project/metroConfig';
import {
installExpoUpdatesAsync,
isExpoUpdatesInstalledAsDevDependency,
isExpoUpdatesInstalledOrAvailable,
isUsingEASUpdate,
validateAppVersionRuntimePolicySupportAsync,
} from '../project/projectUtils';
import {
@@ -57,6 +59,7 @@ import {
waitToCompleteAsync as waitForSubmissionsToCompleteAsync,
} from '../submit/submit';
import { printSubmissionDetailsUrls } from '../submit/utils/urls';
import { ensureEASUpdateIsConfiguredAsync } from '../update/configure';
import { validateBuildProfileConfigMatchesProjectConfigAsync } from '../update/utils';
import { Actor } from '../user/User';
import { downloadAndMaybeExtractAppAsync } from '../utils/download';
@@ -117,6 +120,7 @@ export async function runBuildAndSubmitAsync(
easJsonAccessor,
platforms,
profileName: flags.profile ?? undefined,
projectDir,
});
Log.log(
`Loaded "env" configuration for the "${buildProfiles[0].profileName}" profile: ${
@@ -183,6 +187,7 @@ export async function runBuildAndSubmitAsync(
platforms,
profileName: flags.submitProfile,
type: 'submit',
projectDir,
});
for (const startedBuild of startedBuilds) {
const submitProfile = nullthrows(
@@ -320,11 +325,26 @@ async function prepareAndStartBuildAsync({
);
if (buildProfile.profile.channel) {
await validateExpoUpdatesInstalledAsProjectDependencyAsync({
graphqlClient,
exp: buildCtx.exp,
projectId: buildCtx.projectId,
projectDir,
sdkVersion: buildCtx.exp.sdkVersion,
nonInteractive: flags.nonInteractive,
buildProfile,
});
if (isUsingEASUpdate(buildCtx.exp, buildCtx.projectId)) {
const doesChannelExist = await doesChannelExistAsync(graphqlClient, {
appId: buildCtx.projectId,
channelName: buildProfile.profile.channel,
});
if (!doesChannelExist) {
await createAndLinkChannelAsync(graphqlClient, {
appId: buildCtx.projectId,
channelName: buildProfile.profile.channel,
});
}
}
}
await validateAppVersionRuntimePolicySupportAsync(buildCtx.projectDir, buildCtx.exp);
@@ -447,11 +467,17 @@ async function maybeDownloadAndRunSimulatorBuildsAsync(
}
async function validateExpoUpdatesInstalledAsProjectDependencyAsync({
exp,
graphqlClient,
projectId,
projectDir,
buildProfile,
nonInteractive,
sdkVersion,
}: {
graphqlClient: ExpoGraphqlClient;
exp: ExpoConfig;
projectId: string;
projectDir: string;
buildProfile: ProfileData<'build'>;
nonInteractive: boolean;
@@ -467,18 +493,24 @@ async function validateExpoUpdatesInstalledAsProjectDependencyAsync({
);
} else if (nonInteractive) {
Log.warn(
`The build profile "${buildProfile.profileName}" has specified the channel "${buildProfile.profile.channel}", but the "expo-updates" package hasn't been installed. To use channels for your builds, install the "expo-updates" package by running "npx expo install expo-updates".`
`The build profile "${buildProfile.profileName}" has specified the channel "${buildProfile.profile.channel}", but the "expo-updates" package hasn't been installed. To use channels for your builds, install the "expo-updates" package by running "npx expo install expo-updates" followed by "eas update:configure".`
);
} else {
Log.warn(
`The build profile "${buildProfile.profileName}" specifies the channel "${buildProfile.profile.channel}", but the "expo-updates" package is missing. To use channels in your builds, install the "expo-updates" package.`
`The build profile "${buildProfile.profileName}" specifies the channel "${buildProfile.profile.channel}", but the "expo-updates" package is missing. To use channels in your builds, install the "expo-updates" package and run "eas update:configure".`
);
const installExpoUpdates = await confirmAsync({
message: `Would you like to install the "expo-updates" package?`,
message: `Would you like to install the "expo-updates" package and configure EAS Update now?`,
});
if (installExpoUpdates) {
await installExpoUpdatesAsync(projectDir, { silent: false });
Log.withTick('Installed expo-updates');
await ensureEASUpdateIsConfiguredAsync(graphqlClient, {
exp,
projectId,
projectDir,
platform: RequestedPlatform.All,
});
Log.withTick('Installed expo-updates and configured EAS Update.');
throw new Error('Command must be re-run to pick up new updates configuration.');
}
}
}
@@ -8,6 +8,7 @@ import {
assertVersion,
getAlwaysTrueBranchMapping,
getBranchMapping,
getEmptyBranchMapping,
getStandardBranchId,
isAlwaysTrueBranchMapping,
isEmptyBranchMapping,
@@ -24,6 +25,12 @@ describe(assertVersion, () => {
});
});
describe(getEmptyBranchMapping, () => {
it('gets an empty branch mapping', () => {
expect(isEmptyBranchMapping(getEmptyBranchMapping())).toBe(true);
});
});
describe(isEmptyBranchMapping, () => {
it('detects empty branch mappings', () => {
expect(isEmptyBranchMapping(emptyBranchMapping)).toBe(true);
@@ -50,6 +50,13 @@ export type EmptyBranchMapping = {
data: [];
};
export function getEmptyBranchMapping(): EmptyBranchMapping {
return {
version: 0,
data: [],
};
}
export function getAlwaysTrueBranchMapping(branchId: string): AlwaysTrueBranchMapping {
return {
version: 0,
+103
View File
@@ -2,6 +2,8 @@ import chalk from 'chalk';
import { print } from 'graphql';
import gql from 'graphql-tag';
import { createUpdateBranchOnAppAsync } from '../branch/queries';
import { BranchNotFoundError } from '../branch/utils';
import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
import { PaginatedQueryOptions } from '../commandUtils/pagination';
import { withErrorHandlingAsync } from '../graphql/client';
@@ -15,13 +17,16 @@ import { BranchQuery, UpdateBranchOnChannelObject } from '../graphql/queries/Bra
import { ChannelQuery, UpdateChannelObject } from '../graphql/queries/ChannelQuery';
import { UpdateChannelBasicInfoFragmentNode } from '../graphql/types/UpdateChannelBasicInfo';
import Log from '../log';
import { getDisplayNameForProjectIdAsync } from '../project/projectUtils';
import formatFields from '../utils/formatFields';
import { printJsonOnlyOutput } from '../utils/json';
import {
paginatedQueryWithConfirmPromptAsync,
paginatedQueryWithSelectPromptAsync,
} from '../utils/queries';
import { ChannelNotFoundError } from './errors';
import { logChannelDetails } from './print-utils';
import { ChannelBasicInfo } from './utils';
export const CHANNELS_LIMIT = 25;
@@ -264,3 +269,101 @@ export async function ensureChannelExistsAsync(
}
}
}
export async function doesChannelExistAsync(
graphqlClient: ExpoGraphqlClient,
{ appId, channelName }: { appId: string; channelName: string }
): Promise<boolean> {
try {
await ChannelQuery.viewUpdateChannelAsync(graphqlClient, {
appId,
channelName,
});
} catch (err) {
if (err instanceof ChannelNotFoundError) {
return false;
}
throw err;
}
return true;
}
/**
*
* Creates a channel and links it to a branch with the same name.
*
* @param appId the app ID, also known as the project ID
* @param channelName the name of the channel to create
* @param shouldPrintJson print only the JSON output
*/
export async function createAndLinkChannelAsync(
graphqlClient: ExpoGraphqlClient,
{
appId,
channelName,
shouldPrintJson,
}: { appId: string; channelName: string; shouldPrintJson?: boolean }
): Promise<ChannelBasicInfo> {
let branchId: string;
let branchMessage: string;
try {
const branch = await BranchQuery.getBranchByNameAsync(graphqlClient, {
appId,
name: channelName,
});
branchId = branch.id;
branchMessage = `We found a branch with the same name`;
} catch (error) {
if (error instanceof BranchNotFoundError) {
const newBranch = await createUpdateBranchOnAppAsync(graphqlClient, {
appId,
name: channelName,
});
branchId = newBranch.id;
branchMessage = `We also went ahead and made a branch with the same name`;
} else {
throw error;
}
}
const {
updateChannel: { createUpdateChannelForApp: newChannel },
} = await createChannelOnAppAsync(graphqlClient, {
appId,
channelName,
branchId,
});
if (!newChannel) {
throw new Error(
`Could not create channel with name ${channelName} on project with id ${appId}`
);
}
if (shouldPrintJson) {
printJsonOnlyOutput(newChannel);
} else {
Log.addNewLineIfNone();
Log.withTick(
`Created a new channel on project ${chalk.bold(
await getDisplayNameForProjectIdAsync(graphqlClient, appId)
)}`
);
Log.log(
formatFields([
{ label: 'Name', value: newChannel.name },
{ label: 'ID', value: newChannel.id },
])
);
Log.addNewLineIfNone();
Log.withTick(`${branchMessage} and have pointed the channel at it.`);
Log.log(
formatFields([
{ label: 'Name', value: newChannel.name },
{ label: 'ID', value: branchId },
])
);
}
return newChannel;
}
@@ -68,6 +68,7 @@ export default class BuildVersionGetView extends EasCommand {
easJsonAccessor,
platforms,
profileName: flags.profile ?? undefined,
projectDir,
});
const results: { [key in Platform]?: string } = {};
for (const { profile, platform } of buildProfiles) {
@@ -80,6 +80,7 @@ export default class BuildVersionSyncView extends EasCommand {
easJsonAccessor,
platforms,
profileName: flags.profile ?? undefined,
projectDir,
});
for (const profileInfo of buildProfiles) {
const { exp, projectId } = await getDynamicPrivateProjectConfigAsync({
@@ -1,16 +1,11 @@
import chalk from 'chalk';
import { createUpdateBranchOnAppAsync } from '../../branch/queries';
import { BranchNotFoundError } from '../../branch/utils';
import { createChannelOnAppAsync } from '../../channel/queries';
import { createAndLinkChannelAsync } from '../../channel/queries';
import EasCommand from '../../commandUtils/EasCommand';
import { EasNonInteractiveAndJsonFlags } from '../../commandUtils/flags';
import { BranchQuery } from '../../graphql/queries/BranchQuery';
import Log from '../../log';
import { getDisplayNameForProjectIdAsync } from '../../project/projectUtils';
import { promptAsync } from '../../prompts';
import formatFields from '../../utils/formatFields';
import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
import { enableJsonOutput } from '../../utils/json';
export default class ChannelCreate extends EasCommand {
static override description = 'create a channel';
@@ -60,69 +55,13 @@ export default class ChannelCreate extends EasCommand {
}));
}
let branchId: string;
let branchMessage: string;
try {
const branch = await BranchQuery.getBranchByNameAsync(graphqlClient, {
appId: projectId,
name: channelName,
});
branchId = branch.id;
branchMessage = `We found a branch with the same name`;
} catch (error) {
if (error instanceof BranchNotFoundError) {
const newBranch = await createUpdateBranchOnAppAsync(graphqlClient, {
appId: projectId,
name: channelName,
});
branchId = newBranch.id;
branchMessage = `We also went ahead and made a branch with the same name`;
} else {
throw error;
}
}
const {
updateChannel: { createUpdateChannelForApp: newChannel },
} = await createChannelOnAppAsync(graphqlClient, {
await createAndLinkChannelAsync(graphqlClient, {
appId: projectId,
channelName,
branchId,
shouldPrintJson: jsonFlag,
});
if (!newChannel) {
throw new Error(
`Could not create channel with name ${channelName} on project with id ${projectId}`
);
}
if (jsonFlag) {
printJsonOnlyOutput(newChannel);
} else {
Log.addNewLineIfNone();
Log.withTick(
`Created a new channel on project ${chalk.bold(
await getDisplayNameForProjectIdAsync(graphqlClient, projectId)
)}`
);
Log.log(
formatFields([
{ label: 'Name', value: newChannel.name },
{ label: 'ID', value: newChannel.id },
])
);
Log.addNewLineIfNone();
Log.withTick(`${branchMessage} and have pointed the channel at it.`);
Log.log(
formatFields([
{ label: 'Name', value: newChannel.name },
{ label: 'ID', value: branchId },
])
);
Log.addNewLineIfNone();
Log.log(chalk.bold('You can now update your app by publishing!'));
}
Log.addNewLineIfNone();
Log.log(chalk.bold('You can now update your app by publishing!'));
}
}
@@ -47,6 +47,7 @@ export default class MetadataLint extends EasCommand {
easJsonAccessor: EasJsonAccessor.fromProjectPath(projectDir),
platforms: [Platform.IOS],
profileName: flags.profile,
projectDir,
});
if (submitProfiles.length !== 1) {
@@ -49,6 +49,7 @@ export default class MetadataPull extends EasCommand {
easJsonAccessor: EasJsonAccessor.fromProjectPath(projectDir),
platforms: [Platform.IOS],
profileName: flags.profile,
projectDir,
});
if (submitProfiles.length !== 1) {
@@ -47,6 +47,7 @@ export default class MetadataPush extends EasCommand {
easJsonAccessor: EasJsonAccessor.fromProjectPath(projectDir),
platforms: [Platform.IOS],
profileName: flags.profile,
projectDir,
});
if (submitProfiles.length !== 1) {
+1
View File
@@ -118,6 +118,7 @@ export default class Submit extends EasCommand {
easJsonAccessor: EasJsonAccessor.fromProjectPath(projectDir),
platforms,
profileName: flagsWithPlatform.profile,
projectDir,
});
const submissions: SubmissionFragment[] = [];
@@ -57,12 +57,6 @@ jest.mock('../../../fetch');
describe(UpdateRepublish.name, () => {
afterEach(() => vol.reset());
it('errors without --channel, --branch, or --group', async () => {
await expect(new UpdateRepublish([], commandOptions).run()).rejects.toThrow(
'--channel, --branch, or --group must be specified'
);
});
it('errors when providing both --group and --branch', async () => {
const flags = ['--group=1234', '--branch=main'];
@@ -35,6 +35,7 @@ import {
getRuntimeVersionObjectAsync,
getUpdateMessageForCommandAsync,
isUploadedAssetCountAboveWarningThreshold,
platformDisplayNames,
resolveInputDirectoryAsync,
uploadAssetsAsync,
} from '../../project/publish';
@@ -325,6 +326,21 @@ export default class UpdatePublish extends EasCommand {
for (const uploadedAssetPath of uploadResults.uniqueUploadedAssetPaths) {
Log.debug(chalk.dim(`- ${uploadedAssetPath}`));
}
const platformString = (Object.keys(assets) as PublishPlatform[])
.map(platform => {
const collectedAssetForPlatform = nullthrows(assets[platform]);
const totalAssetsForPlatform = collectedAssetForPlatform.assets.length + 1; // launch asset
const assetString = totalAssetsForPlatform === 1 ? 'asset' : 'assets';
return `${totalAssetsForPlatform} ${platformDisplayNames[platform]} ${assetString}`;
})
.join(', ');
Log.withInfo(
`${platformString} (maximum: ${assetLimitPerUpdateGroup} total per update). ${learnMore(
'https://expo.fyi/eas-update-asset-limits',
{ learnMoreMessage: 'Learn more about asset limits.' }
)}`
);
} catch (e) {
assetSpinner.fail('Failed to upload');
throw e;
@@ -1,6 +1,8 @@
import { Platform } from '@expo/config';
import { Flags } from '@oclif/core';
import { selectBranchOnAppAsync } from '../../branch/queries';
import { selectChannelOnAppAsync } from '../../channel/queries';
import EasCommand from '../../commandUtils/EasCommand';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
import { EasNonInteractiveAndJsonFlags } from '../../commandUtils/flags';
@@ -151,9 +153,6 @@ export default class UpdateRepublish extends EasCommand {
if (nonInteractive && !groupId) {
throw new Error('Only --group can be used in non-interactive mode');
}
if (!groupId && !(branchName || channelName)) {
throw new Error(`--channel, --branch, or --group must be specified`);
}
const platform =
rawFlags.platform === 'all' ? defaultRepublishPlatforms : ([rawFlags.platform] as Platform[]);
@@ -190,6 +189,10 @@ async function getOrAskUpdatesAsync(
}));
}
if (flags.nonInteractive) {
throw new Error('Must supply --group when in non-interactive mode');
}
if (flags.branchName) {
return await askUpdatesFromBranchNameAsync(graphqlClient, {
...flags,
@@ -206,7 +209,55 @@ async function getOrAskUpdatesAsync(
});
}
throw new Error('--channel, --branch, or --group is required');
const { choice } = await promptAsync({
type: 'select',
message: 'Find update by branch or channel?',
name: 'choice',
choices: [
{ title: 'Branch', value: 'branch' },
{ title: 'Channel', value: 'channel' },
],
});
if (choice === 'channel') {
const { name } = await selectChannelOnAppAsync(graphqlClient, {
projectId,
selectionPromptTitle: 'Select a channel to view',
paginatedQueryOptions: {
json: flags.json,
nonInteractive: flags.nonInteractive,
offset: 0,
},
});
return await askUpdatesFromChannelNameAsync(graphqlClient, {
...flags,
channelName: name,
projectId,
});
} else if (choice === 'branch') {
const { name } = await selectBranchOnAppAsync(graphqlClient, {
projectId,
promptTitle: 'Select branch from which to choose update',
displayTextForListItem: updateBranch => ({
title: updateBranch.name,
}),
// discard limit and offset because this query is not their intended target
paginatedQueryOptions: {
json: flags.json,
nonInteractive: flags.nonInteractive,
offset: 0,
},
});
return await askUpdatesFromBranchNameAsync(graphqlClient, {
...flags,
branchName: name,
projectId,
});
} else {
throw new Error('Must choose update via channel or branch');
}
}
/** Ask the user which update needs to be republished by branch name, this requires interactive mode */
@@ -219,10 +270,6 @@ async function askUpdatesFromBranchNameAsync(
nonInteractive,
}: { projectId: string; branchName: string; json: boolean; nonInteractive: boolean }
): Promise<UpdateToRepublish[]> {
if (nonInteractive) {
throw new Error('Must supply --group when in non-interactive mode');
}
const updateGroup = await selectUpdateGroupOnBranchAsync(graphqlClient, {
projectId,
branchName,
@@ -246,10 +293,6 @@ async function askUpdatesFromChannelNameAsync(
nonInteractive,
}: { projectId: string; channelName: string; json: boolean; nonInteractive: boolean }
): Promise<UpdateToRepublish[]> {
if (nonInteractive) {
throw new Error('Must supply --group when in non-interactive mode');
}
const branchName = await getBranchNameFromChannelNameAsync(graphqlClient, projectId, channelName);
return await askUpdatesFromBranchNameAsync(graphqlClient, {
@@ -86,7 +86,11 @@ export default class UpdateRollBackToEmbedded extends EasCommand {
}),
platform: Flags.enum({
char: 'p',
options: [...defaultPublishPlatforms, 'all'],
options: [
// TODO: Add web when it's fully supported
...defaultPublishPlatforms,
'all',
],
default: 'all',
required: false,
}),
@@ -0,0 +1,42 @@
import { Flags } from '@oclif/core';
import EasCommand from '../../commandUtils/EasCommand';
import { promptAsync } from '../../prompts';
import UpdateRepublish from './republish';
import UpdateRollBackToEmbedded from './roll-back-to-embedded';
export default class UpdateRollback extends EasCommand {
static override description = 'roll back to an embedded update or an existing update';
static override hidden = true;
static override flags = {
'private-key-path': Flags.string({
description: `File containing the PEM-encoded private key corresponding to the certificate in expo-updates' configuration. Defaults to a file named "private-key.pem" in the certificate's directory.`,
required: false,
}),
};
async runAsync(): Promise<void> {
const { flags } = await this.parse(UpdateRollback);
const { choice } = await promptAsync({
type: 'select',
message: 'Which type of update would you like to roll back to?',
name: 'choice',
choices: [
{ title: 'Published Update', value: 'published' },
{ title: 'Embedded Update', value: 'embedded' },
],
});
const privateKeyPathArg = flags['private-key-path']
? ['--private-key-path', flags['private-key-path']]
: [];
if (choice === 'published') {
await UpdateRepublish.run(privateKeyPathArg);
} else {
await UpdateRollBackToEmbedded.run(privateKeyPathArg);
}
}
}
@@ -177,7 +177,23 @@ export class SetUpAdhocProvisioningProfile {
);
}
// 6. Create (or update) app build credentials
// 6. Compare selected devices with the ones actually provisioned
const diffList = differenceBy(
chosenDevices,
appleProvisioningProfile.appleDevices,
'identifier'
);
if (diffList && diffList.length > 0) {
Log.warn(`Failed to provision ${diffList.length} of the selected devices:`);
for (const missingDevice of diffList) {
Log.warn(`- ${formatDeviceLabel(missingDevice)}`);
}
Log.log(
'Most commonly devices fail to to be provisioned while they are still being processed by Apple, which can take up to 24-72 hours. Check your Apple Developer Portal page at https://developer.apple.com/account/resources/devices/list, the devices in "Processing" status cannot be provisioned yet'
);
}
// 7. Create (or update) app build credentials
assert(appleProvisioningProfile);
return await assignBuildCredentialsAsync(
ctx,
@@ -1,4 +1,38 @@
import { doUDIDsMatch } from '../SetUpAdhocProvisioningProfile';
import { Env } from '@expo/eas-build-job';
import { EasJson } from '@expo/eas-json';
import { Analytics } from '../../../../analytics/AnalyticsManager';
import { ExpoGraphqlClient } from '../../../../commandUtils/context/contextUtils/createGraphqlClient';
import {
Account,
AppleAppIdentifierFragment,
AppleDevice,
AppleDeviceClass,
AppleDeviceFragment,
AppleDistributionCertificateFragment,
IosAppBuildCredentialsFragment,
} from '../../../../graphql/generated';
import Log from '../../../../log';
import { getApplePlatformFromTarget } from '../../../../project/ios/target';
import { Actor } from '../../../../user/User';
import { CredentialsContext, CredentialsContextProjectInfo } from '../../../context';
import { ProvisioningProfile } from '../../appstore/Credentials.types';
import { ApplePlatform } from '../../appstore/constants';
import { assignBuildCredentialsAsync, getBuildCredentialsAsync } from '../BuildCredentialsUtils';
import { chooseDevicesAsync } from '../DeviceUtils';
import { SetUpAdhocProvisioningProfile, doUDIDsMatch } from '../SetUpAdhocProvisioningProfile';
jest.mock('../BuildCredentialsUtils');
jest.mock('../../../context');
jest.mock('../../../ios/api/GraphqlClient');
jest.mock('../DeviceUtils', () => {
return {
__esModule: true,
chooseDevicesAsync: jest.fn(),
formatDeviceLabel: jest.requireActual('../DeviceUtils').formatDeviceLabel,
};
});
jest.mock('../../../../project/ios/target');
describe(doUDIDsMatch, () => {
it('return false if UDIDs do not match', () => {
@@ -12,3 +46,104 @@ describe(doUDIDsMatch, () => {
expect(doUDIDsMatch(udidsA, udidsB)).toBe(true);
});
});
describe('runWithDistributionCertificateAsync', () => {
beforeEach(() => {
jest.resetAllMocks();
});
const setUpAdhocProvisioningProfile = new SetUpAdhocProvisioningProfile({
app: { account: {} as Account, projectName: 'projName', bundleIdentifier: 'bundleId' },
target: { targetName: 'targetName', bundleIdentifier: 'bundleId', entitlements: {} },
});
describe('compare chosen and provisioned devices', () => {
describe('not all devices provisioned', () => {
it('displays warning to the user and lists the missing devices', async () => {
const { ctx, distCert } = setUpTest();
jest.mocked(getBuildCredentialsAsync).mockResolvedValue({
provisioningProfile: {
appleTeam: {},
appleDevices: [{ identifier: 'id1' }],
developerPortalIdentifier: 'provisioningProfileId',
},
} as IosAppBuildCredentialsFragment);
const LogWarnSpy = jest.spyOn(Log, 'warn');
const LogLogSpy = jest.spyOn(Log, 'log');
const result = await setUpAdhocProvisioningProfile.runWithDistributionCertificateAsync(
ctx,
distCert
);
expect(result).toEqual({} as IosAppBuildCredentialsFragment);
expect(LogWarnSpy).toHaveBeenCalledTimes(3);
expect(LogWarnSpy).toHaveBeenCalledWith('Failed to provision 2 of the selected devices:');
expect(LogWarnSpy).toHaveBeenCalledWith('- id2 (iPhone) (Device 2)');
expect(LogWarnSpy).toHaveBeenCalledWith('- id3 (Mac) (Device 3)');
expect(LogLogSpy).toHaveBeenCalledTimes(1);
expect(LogLogSpy).toHaveBeenCalledWith(
'Most commonly devices fail to to be provisioned while they are still being processed by Apple, which can take up to 24-72 hours. Check your Apple Developer Portal page at https://developer.apple.com/account/resources/devices/list, the devices in "Processing" status cannot be provisioned yet'
);
});
});
describe('all devices provisioned', () => {
it('does not display warning', async () => {
const { ctx, distCert } = setUpTest();
jest.mocked(getBuildCredentialsAsync).mockResolvedValue({
provisioningProfile: {
appleTeam: {},
appleDevices: [{ identifier: 'id1' }, { identifier: 'id2' }, { identifier: 'id3' }],
developerPortalIdentifier: 'provisioningProfileId',
},
} as IosAppBuildCredentialsFragment);
const LogWarnSpy = jest.spyOn(Log, 'warn');
const LogLogSpy = jest.spyOn(Log, 'log');
const result = await setUpAdhocProvisioningProfile.runWithDistributionCertificateAsync(
ctx,
distCert
);
expect(result).toEqual({} as IosAppBuildCredentialsFragment);
expect(LogWarnSpy).not.toHaveBeenCalled();
expect(LogLogSpy).not.toHaveBeenCalled();
});
});
});
});
function setUpTest(): { ctx: CredentialsContext; distCert: AppleDistributionCertificateFragment } {
const ctx = jest.mocked(
new CredentialsContext(
{} as {
projectInfo: CredentialsContextProjectInfo | null;
easJsonCliConfig?: EasJson['cli'];
nonInteractive: boolean;
projectDir: string;
user: Actor;
graphqlClient: ExpoGraphqlClient;
analytics: Analytics;
env?: Env;
}
)
);
Object.defineProperty(ctx, 'ios', { value: jest.mock('../../../ios/api/GraphqlClient') });
ctx.ios.getDevicesForAppleTeamAsync = jest
.fn()
.mockResolvedValue([
{ identifier: 'id1' },
{ identifier: 'id2' },
{ identifier: 'id3' },
] as AppleDeviceFragment[]);
jest.mocked(chooseDevicesAsync).mockResolvedValue([
{ identifier: 'id1', name: 'Device 1', deviceClass: AppleDeviceClass.Ipad },
{ identifier: 'id2', name: 'Device 2', deviceClass: AppleDeviceClass.Iphone },
{ identifier: 'id3', name: 'Device 3', deviceClass: AppleDeviceClass.Mac },
] as AppleDevice[]);
// @ts-ignore
jest.mocked(getApplePlatformFromTarget).mockResolvedValue(ApplePlatform.IOS);
Object.defineProperty(ctx, 'appStore', { value: jest.mock('../../appstore/AppStoreApi') });
ctx.appStore.createOrReuseAdhocProvisioningProfileAsync = jest.fn().mockResolvedValue({
provisioningProfileId: 'provisioningProfileId',
} as ProvisioningProfile);
ctx.ios.createOrGetExistingAppleAppIdentifierAsync = jest
.fn()
.mockResolvedValue({} as AppleAppIdentifierFragment);
jest.mocked(assignBuildCredentialsAsync).mockResolvedValue({} as IosAppBuildCredentialsFragment);
const distCert = {} as AppleDistributionCertificateFragment;
return { ctx, distCert };
}
+4
View File
@@ -57,6 +57,10 @@ export default class Log {
Log.consoleLog(chalk.green(figures.tick), ...args);
}
public static withInfo(...args: any[]): void {
Log.consoleLog(chalk.green(figures.info), ...args);
}
private static consoleLog(...args: any[]): void {
Log.updateIsLastLineNewLine(args);
// eslint-disable-next-line no-console
+55 -18
View File
@@ -25,7 +25,11 @@ import { promptAsync } from '../prompts';
import { getBranchNameFromChannelNameAsync } from '../update/getBranchNameFromChannelNameAsync';
import { formatUpdateMessage, truncateString as truncateUpdateMessage } from '../update/utils';
import { PresignedPost, uploadWithPresignedPostWithRetryAsync } from '../uploads';
import { expoCommandAsync, shouldUseVersionedExpoCLI } from '../utils/expoCli';
import {
expoCommandAsync,
shouldUseVersionedExpoCLI,
shouldUseVersionedExpoCLIWithExplicitPlatforms,
} from '../utils/expoCli';
import chunk from '../utils/expodash/chunk';
import { truthy } from '../utils/expodash/filter';
import uniqBy from '../utils/expodash/uniqBy';
@@ -184,7 +188,7 @@ export async function buildBundlesAsync({
}: {
projectDir: string;
inputDir: string;
exp: Pick<ExpoConfig, 'sdkVersion'>;
exp: Pick<ExpoConfig, 'sdkVersion' | 'web'>;
platformFlag: ExpoCLIExportPlatformFlag;
clearCache?: boolean;
}): Promise<void> {
@@ -193,20 +197,9 @@ export async function buildBundlesAsync({
throw new Error('Could not locate package.json');
}
if (shouldUseVersionedExpoCLI(projectDir, exp)) {
await expoCommandAsync(projectDir, [
'export',
'--output-dir',
inputDir,
'--dump-sourcemap',
'--dump-assetmap',
'--platform',
platformFlag,
...(clearCache ? ['--clear'] : []),
]);
} else {
// Legacy global Expo CLI
await expoCommandAsync(projectDir, [
// Legacy global Expo CLI
if (!shouldUseVersionedExpoCLI(projectDir, exp)) {
return await expoCommandAsync(projectDir, [
'export',
'--output-dir',
inputDir,
@@ -214,11 +207,49 @@ export async function buildBundlesAsync({
'--non-interactive',
'--dump-sourcemap',
'--dump-assetmap',
'--platform',
platformFlag,
`--platform=${platformFlag}`,
...(clearCache ? ['--clear'] : []),
]);
}
// Versioned Expo CLI, with multiple platform flag support
if (shouldUseVersionedExpoCLIWithExplicitPlatforms(projectDir)) {
// When creating EAS updates, we don't want to build a web bundle
const platformArgs =
platformFlag === 'all'
? ['--platform', 'ios', '--platform', 'android']
: ['--platform', platformFlag];
return await expoCommandAsync(projectDir, [
'export',
'--output-dir',
inputDir,
'--dump-sourcemap',
'--dump-assetmap',
...platformArgs,
...(clearCache ? ['--clear'] : []),
]);
}
// Versioned Expo CLI, without multiple platform flag support
// Warn users about potential export issues when using Metro web
// See: https://github.com/expo/expo/pull/23621
if (exp.web?.bundler === 'metro') {
Log.warn('Exporting bundle for all platforms, including Metro web.');
Log.warn(
'If your app is incompatible with web, remove the "expo.web.bundler" property from your app manifest, or upgrade to the latest Expo SDK.'
);
}
return await expoCommandAsync(projectDir, [
'export',
'--output-dir',
inputDir,
'--dump-sourcemap',
'--dump-assetmap',
`--platform=${platformFlag}`,
...(clearCache ? ['--clear'] : []),
]);
}
export async function resolveInputDirectoryAsync(
@@ -682,3 +713,9 @@ export function getRuntimeToPlatformMappingFromRuntimeVersions(
}
return runtimeToPlatformMapping;
}
export const platformDisplayNames: Record<Platform, string> = {
android: 'Android',
ios: 'iOS',
web: 'Web',
};
@@ -18,6 +18,7 @@ import {
assertRolloutBranchMapping,
composeRollout,
createRolloutBranchMapping,
doesTargetRollout,
editRolloutBranchMapping,
getRollout,
getRolloutInfo,
@@ -33,6 +34,17 @@ import {
standardBranchMapping,
} from './fixtures';
describe(doesTargetRollout, () => {
it('detects whether a runtime targets a constrained rollout', () => {
expect(doesTargetRollout(rolloutBranchMapping, '1.0.0')).toBe(true);
expect(doesTargetRollout(rolloutBranchMapping, '2.0.0')).toBe(false);
});
it('should always return true if the rollout is unconstrained', () => {
expect(doesTargetRollout(rolloutBranchMappingLegacy, '1.0.0')).toBe(true);
expect(doesTargetRollout(rolloutBranchMappingLegacy, '2.0.0')).toBe(true);
});
});
describe(composeRollout, () => {
it('composes a rollout', () => {
const rollout = getRollout(channelInfoWithBranches);
@@ -257,6 +257,17 @@ export function isRollout(channelInfo: ChannelBasicInfo): boolean {
return isRolloutBranchMapping(branchMapping);
}
export function doesTargetRollout(
branchMapping: RolloutBranchMapping,
runtimeVersion: string
): boolean {
const rolloutInfo = getRolloutInfoFromBranchMapping(branchMapping);
if (!isConstrainedRolloutInfo(rolloutInfo)) {
return true;
}
return rolloutInfo.runtimeVersion === runtimeVersion;
}
export function createRolloutBranchMapping({
defaultBranchId,
rolloutBranchId,
+43 -21
View File
@@ -5,14 +5,16 @@ import nullthrows from 'nullthrows';
import { getUpdateGroupUrl } from '../build/utils/url';
import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
import fetch from '../fetch';
import { Update, UpdateInfoGroup } from '../graphql/generated';
import { UpdateFragment, UpdateInfoGroup } from '../graphql/generated';
import { PublishMutation } from '../graphql/mutations/PublishMutation';
import Log, { link } from '../log';
import { ora } from '../ora';
import { getOwnerAccountForProjectIdAsync } from '../project/projectUtils';
import {
CodeSigningInfo,
checkDirectiveBodyAgainstUpdateInfoGroup,
checkManifestBodyAgainstUpdateInfoGroup,
getDirectiveBodyAsync,
getManifestBodyAsync,
signBody,
} from '../utils/code-signing';
@@ -23,15 +25,7 @@ export type UpdateToRepublish = {
groupId: string;
branchId: string;
branchName: string;
} & Pick<
Update,
| 'message'
| 'runtimeVersion'
| 'manifestFragment'
| 'platform'
| 'gitCommitHash'
| 'codeSigningInfo'
>;
} & UpdateFragment;
/**
* @param updatesToPublish The update group to republish
@@ -65,6 +59,13 @@ export async function republishAsync({
update.branchName === arbitraryUpdate.branchName &&
update.runtimeVersion === arbitraryUpdate.runtimeVersion;
assert(updatesToPublish.every(isSameGroup), 'All updates must belong to the same update group');
assert(
updatesToPublish.every(u => u.isRollBackToEmbedded) ||
updatesToPublish.every(u => !u.isRollBackToEmbedded),
'All updates must either be roll back to embedded updates or not'
);
const { runtimeVersion } = arbitraryUpdate;
// If codesigning was created for the original update, we need to add it to the republish.
@@ -96,16 +97,25 @@ export async function republishAsync({
let updatesRepublished: Awaited<ReturnType<typeof PublishMutation.publishUpdateGroupAsync>>;
try {
const updateInfoGroup = Object.fromEntries(
updatesToPublish.map(update => [update.platform, JSON.parse(update.manifestFragment)])
);
const arbitraryUpdate = updatesToPublish[0];
const objectToMergeIn = arbitraryUpdate.isRollBackToEmbedded
? {
rollBackToEmbeddedInfoGroup: Object.fromEntries(
updatesToPublish.map(update => [update.platform, true])
),
}
: {
updateInfoGroup: Object.fromEntries(
updatesToPublish.map(update => [update.platform, JSON.parse(update.manifestFragment)])
),
};
updatesRepublished = await PublishMutation.publishUpdateGroupAsync(graphqlClient, [
{
branchId: targetBranchId,
runtimeVersion,
message: updateMessage,
updateInfoGroup,
...objectToMergeIn,
gitCommitHash: updatesToPublish[0].gitCommitHash,
awaitingCodeSigningInfo: !!codeSigningInfo,
},
@@ -120,19 +130,31 @@ export async function republishAsync({
method: 'GET',
headers: { accept: 'multipart/mixed' },
});
const manifestBody = nullthrows(await getManifestBodyAsync(response));
checkManifestBodyAgainstUpdateInfoGroup(
manifestBody,
nullthrows(nullthrows(updateInfoGroup)[newUpdate.platform as keyof UpdateInfoGroup])
);
let signature;
if (newUpdate.isRollBackToEmbedded) {
const directiveBody = nullthrows(await getDirectiveBodyAsync(response));
const manifestSignature = signBody(manifestBody, codeSigningInfo);
checkDirectiveBodyAgainstUpdateInfoGroup(directiveBody);
signature = signBody(directiveBody, codeSigningInfo);
} else {
const manifestBody = nullthrows(await getManifestBodyAsync(response));
checkManifestBodyAgainstUpdateInfoGroup(
manifestBody,
nullthrows(
nullthrows(objectToMergeIn.updateInfoGroup)[
newUpdate.platform as keyof UpdateInfoGroup
]
)
);
signature = signBody(manifestBody, codeSigningInfo);
}
await PublishMutation.setCodeSigningInfoAsync(graphqlClient, newUpdate.id, {
alg: codeSigningInfo.codeSigningMetadata.alg,
keyid: codeSigningInfo.codeSigningMetadata.keyid,
sig: manifestSignature,
sig: signature,
});
})
);
@@ -1,5 +1,8 @@
import { Platform } from '@expo/eas-build-job';
import { BuildProfile, EasJsonAccessor, EasJsonUtils, errors } from '@expo/eas-json';
import fs from 'fs-extra';
import { vol } from 'memfs';
import os from 'os';
import Log from '../../log';
import { selectAsync } from '../../prompts';
@@ -9,6 +12,7 @@ import {
maybePrintBuildProfileDeprecationWarningsAsync,
} from '../profiles';
jest.mock('fs');
jest.mock('../../prompts');
jest.mock('@expo/eas-json', () => {
const actual = jest.requireActual('@expo/eas-json');
@@ -32,6 +36,7 @@ const getBuildProfileDeprecationWarningsAsync = jest.spyOn(
);
const newLineSpy = jest.spyOn(Log, 'newLine');
const warnSpy = jest.spyOn(Log, 'warn');
const projectDir = '/app';
describe(getProfilesAsync, () => {
afterEach(() => {
@@ -51,6 +56,7 @@ describe(getProfilesAsync, () => {
platforms: [Platform.ANDROID, Platform.IOS],
profileName: undefined,
type: 'build',
projectDir,
});
expect(result[0].profileName).toBe('production');
@@ -71,6 +77,7 @@ describe(getProfilesAsync, () => {
platforms: [Platform.ANDROID],
profileName: undefined,
type: 'build',
projectDir,
})
).rejects.toThrowError(errors.MissingProfileError);
});
@@ -86,6 +93,7 @@ describe(getProfilesAsync, () => {
platforms: [Platform.ANDROID, Platform.IOS],
profileName: 'custom-profile',
type: 'build',
projectDir,
});
expect(result[0].profileName).toBe('custom-profile');
@@ -98,6 +106,52 @@ describe(getProfilesAsync, () => {
expect(getBuildProfileAsync).toBeCalledWith(easJsonAccessor, Platform.IOS, 'custom-profile');
});
describe('node version', () => {
const nodeVersion = '14.17.1';
it('is read from profile', async () => {
const easJsonAccessor = EasJsonAccessor.fromProjectPath(projectDir);
getBuildProfileAsync.mockImplementation(async () => {
return { node: nodeVersion } as BuildProfile<Platform.ANDROID>;
});
const result = await getProfilesAsync({
easJsonAccessor,
platforms: [Platform.ANDROID],
profileName: 'custom-profile',
type: 'build',
projectDir,
});
expect(result[0].profile.node).toBe(nodeVersion);
});
describe('with .nvmrc', () => {
beforeEach(async () => {
vol.reset();
await fs.mkdirp(os.tmpdir());
vol.fromJSON({ '.nvmrc': nodeVersion }, projectDir);
});
it('is read from .nvmrc', async () => {
const easJsonAccessor = EasJsonAccessor.fromProjectPath(projectDir);
getBuildProfileAsync.mockImplementation(async () => {
return {} as BuildProfile<Platform.ANDROID>;
});
const result = await getProfilesAsync({
easJsonAccessor,
platforms: [Platform.ANDROID],
profileName: 'custom-profile',
type: 'build',
projectDir,
});
expect(result[0].profile.node).toBe(nodeVersion);
});
});
});
it('throws validation error if eas.json is invalid', async () => {
getBuildProfileAsync.mockImplementation(() => {
throw new errors.InvalidEasJsonError('eas.json is not valid');
@@ -109,6 +163,7 @@ describe(getProfilesAsync, () => {
platforms: [Platform.ANDROID, Platform.IOS],
profileName: undefined,
type: 'build',
projectDir,
})
).rejects.toThrowError(/eas.json is not valid/);
});
+19
View File
@@ -56,7 +56,26 @@ export function shouldUseVersionedExpoCLIExpensive(
return !!resolveFrom.silent(projectDir, '@expo/cli');
}
/**
* Determine if we can and should use `expo export` with multiple `--platform` flags.
* This is an issue related to `expo export --all` causing issues when users have Metro web configured.
* See: https://github.com/expo/expo/pull/23621
*/
export function shouldUseVersionedExpoCLIWithExplicitPlatformsExpensive(
projectDir: string
): boolean {
const expoCliPath = resolveFrom.silent(projectDir, '@expo/cli/package.json');
if (!expoCliPath) {
return false;
}
return gteSdkVersion(require(expoCliPath).version, '0.10.11');
}
export const shouldUseVersionedExpoCLI = memoize(shouldUseVersionedExpoCLIExpensive);
export const shouldUseVersionedExpoCLIWithExplicitPlatforms = memoize(
shouldUseVersionedExpoCLIWithExplicitPlatformsExpensive
);
export async function expoCommandAsync(
projectDir: string,
+47 -2
View File
@@ -6,6 +6,9 @@ import {
ProfileType,
SubmitProfile,
} from '@expo/eas-json';
import fs from 'fs-extra';
import path from 'path';
import semver from 'semver';
import Log, { learnMore } from '../log';
@@ -24,19 +27,23 @@ export async function getProfilesAsync<T extends ProfileType>({
platforms,
profileName,
type,
projectDir,
}: {
easJsonAccessor: EasJsonAccessor;
platforms: Platform[];
profileName?: string;
projectDir: string;
type: T;
}): Promise<ProfileData<T>[]> {
const results = platforms.map(async function (platform) {
const profile = await readProfileAsync({
const profile = await readProfileWithOverridesAsync({
easJsonAccessor,
platform,
type,
profileName,
projectDir,
});
return {
profile,
profileName: profileName ?? 'production',
@@ -47,16 +54,53 @@ export async function getProfilesAsync<T extends ProfileType>({
return await Promise.all(results);
}
async function readProfileAsync<T extends ProfileType>({
async function maybeSetNodeVersionFromFileAsync(
projectDir: string,
profile: BuildProfile<Platform>
): Promise<void> {
if (profile?.node) {
return;
}
const nodeVersion = await getNodeVersionFromFileAsync(projectDir);
if (nodeVersion) {
Log.log(
`The EAS build profile does not specify a Node.js version. Using the version specified in .nvmrc: ${nodeVersion} `
);
profile.node = nodeVersion;
}
}
async function getNodeVersionFromFileAsync(projectDir: string): Promise<string | undefined> {
const nvmrcPath = path.join(projectDir, '.nvmrc');
if (!(await fs.pathExists(nvmrcPath))) {
return;
}
let nodeVersion: string;
try {
nodeVersion = (await fs.readFile(nvmrcPath, 'utf8')).toString().trim();
} catch {
return undefined;
}
if (!semver.valid(semver.coerce(nodeVersion))) {
throw new Error(`Invalid node version in .nvmrc: ${nodeVersion}`);
}
return nodeVersion;
}
async function readProfileWithOverridesAsync<T extends ProfileType>({
easJsonAccessor,
platform,
type,
profileName,
projectDir,
}: {
easJsonAccessor: EasJsonAccessor;
platform: Platform;
type: T;
profileName?: string;
projectDir: string;
}): Promise<EasProfile<T>> {
if (type === 'build') {
const buildProfile = await EasJsonUtils.getBuildProfileAsync(
@@ -66,6 +110,7 @@ async function readProfileAsync<T extends ProfileType>({
);
await maybePrintBuildProfileDeprecationWarningsAsync(easJsonAccessor, platform, profileName);
await maybeSetNodeVersionFromFileAsync(projectDir, buildProfile);
return buildProfile as EasProfile<T>;
} else {
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "@expo/eas-json",
"description": "A library for interacting with eas.json",
"version": "4.1.0",
"version": "5.0.0",
"author": "Expo <[email protected]>",
"bugs": "https://github.com/expo/eas-cli/issues",
"dependencies": {
"@babel/code-frame": "7.18.6",
"@expo/eas-build-job": "1.0.30",
"@expo/eas-build-job": "1.0.39",
"chalk": "4.1.2",
"env-string": "1.0.1",
"fs-extra": "10.1.0",
Generated
+4 -4
View File
@@ -1395,10 +1395,10 @@
slugify "^1.3.4"
sucrase "^3.20.0"
"@expo/[email protected]0":
version "1.0.30"
resolved "https://registry.yarnpkg.com/@expo/eas-build-job/-/eas-build-job-1.0.30.tgz#f8c57a673a2cc328f4041346996c480c3d910e92"
integrity sha512-KQGn9POn5p3guMNQJ5ykG3wffRlSEpjTCLO87d5lJll9E4u1grpqHJH2chOh5ICxg7tiWcO4iXt5S8tU7Ogpig==
"@expo/[email protected]9":
version "1.0.39"
resolved "https://registry.yarnpkg.com/@expo/eas-build-job/-/eas-build-job-1.0.39.tgz#d3bc6cd50c499f07255bceeb9460e092a19505f7"
integrity sha512-OqCCxLx9HRMFQDiZvfpOfNmGhsTrV15IUOhmbp9iIa+uO/VyPpBvXqiA4ENCN9Jmf6yXtirIranCeJcm+jAuSA==
dependencies:
joi "^17.9.2"
semver "^7.5.4"