Compare commits

..
Author SHA1 Message Date
Will Schurman bcf2c62066 [eas-cli] fix env overriding in getExpoConfig 2022-11-17 13:50:00 -08:00
31 changed files with 267 additions and 919 deletions

No files matched your search

-22
View File
@@ -8,34 +8,12 @@ This is the log of notable changes to EAS CLI and related packages.
### 🎉 New features
- Add caching for `eas build:run` command. ([#1542](https://github.com/expo/eas-cli/pull/1542) by [@szdziedzic](https://github.com/szdziedzic))
- Add `isGitWorkingTreeDirty` to EAS Update records. ([#1550](https://github.com/expo/eas-cli/pull/1550) by [@FiberJW](https://github.com/FiberJW))
- Prompt developer to download the app after the simulator build is finished. ([#1554](https://github.com/expo/eas-cli/pull/1554) by [@szdziedzic](https://github.com/szdziedzic))
### 🐛 Bug fixes
- Ask for the missing application identifier consistently in `eas build:version:sync` command. ([#1543](https://github.com/expo/eas-cli/pull/1543) by [@wkozyra95](https://github.com/wkozyra95))
- Disable selecting builds whose artifacts have expired in the `eas build:run` command. ([#1547](https://github.com/expo/eas-cli/pull/1547) by [@szdziedzic](https://github.com/szdziedzic))
- Change intent with which the `eas build:run` command opens an Android app to `android.intent.action.MAIN`. ([#1556](https://github.com/expo/eas-cli/pull/1556) by [@szdziedzic](https://github.com/szdziedzic))
### 🧹 Chores
## [2.8.0](https://github.com/expo/eas-cli/releases/tag/v2.8.0) - 2022-11-28
### 🎉 New features
- Add `eas build:run` support for Android. ([#1485](https://github.com/expo/eas-cli/pull/1485) by [@szdziedzic](https://github.com/szdziedzic))
### 🐛 Bug fixes
- Only create a new channel when update branch is new. ([#1507](https://github.com/expo/eas-cli/pull/1507) by [@byCedric](https://github.com/byCedric))
### 🧹 Chores
- Better wording in eas submit. ([#1527](https://github.com/expo/eas-cli/pull/1527) by [@dsokal](https://github.com/dsokal))
- Upload project sources for EAS Build and archives for EAS Submit to GCS. ([#1524](https://github.com/expo/eas-cli/pull/1524) by [@wkozyra95](https://github.com/wkozyra95))
- Add a better error message for when an invalid `image` is set in `eas-json`. ([#1531](https://github.com/expo/eas-cli/pull/1531) by [@szdziedzic](https://github.com/szdziedzic))
- Remove internal expo id from device formatter. ([#1541](https://github.com/expo/eas-cli/pull/1541) by [@dsokal](https://github.com/dsokal))
## [2.7.1](https://github.com/expo/eas-cli/releases/tag/v2.7.1) - 2022-11-16
+1 -1
View File
@@ -1,5 +1,5 @@
{
"npmClient": "yarn",
"useWorkspaces": true,
"version": "2.9.0"
"version": "2.7.1"
}
+53 -78
View File
@@ -70,7 +70,6 @@ eas --help COMMAND
* [`eas build:configure`](#eas-buildconfigure)
* [`eas build:inspect`](#eas-buildinspect)
* [`eas build:list`](#eas-buildlist)
* [`eas build:run`](#eas-buildrun)
* [`eas build:submit`](#eas-buildsubmit)
* [`eas build:version:set`](#eas-buildversionset)
* [`eas build:version:sync`](#eas-buildversionsync)
@@ -130,7 +129,7 @@ ALIASES
$ eas login
```
_See code: [src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/account/login.ts)_
_See code: [src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/account/login.ts)_
## `eas account:logout`
@@ -147,7 +146,7 @@ ALIASES
$ eas logout
```
_See code: [src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/account/logout.ts)_
_See code: [src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/account/logout.ts)_
## `eas account:view`
@@ -164,7 +163,7 @@ ALIASES
$ eas whoami
```
_See code: [src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/account/view.ts)_
_See code: [src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/account/view.ts)_
## `eas analytics [STATUS]`
@@ -178,7 +177,7 @@ DESCRIPTION
display or change analytics settings
```
_See code: [src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/analytics.ts)_
_See code: [src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/analytics.ts)_
## `eas autocomplete [SHELL]`
@@ -228,7 +227,7 @@ DESCRIPTION
create a branch
```
_See code: [src/commands/branch/create.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/branch/create.ts)_
_See code: [src/commands/branch/create.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/branch/create.ts)_
## `eas branch:delete [NAME]`
@@ -249,7 +248,7 @@ DESCRIPTION
delete a branch
```
_See code: [src/commands/branch/delete.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/branch/delete.ts)_
_See code: [src/commands/branch/delete.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/branch/delete.ts)_
## `eas branch:list`
@@ -269,7 +268,7 @@ DESCRIPTION
list all branches
```
_See code: [src/commands/branch/list.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/branch/list.ts)_
_See code: [src/commands/branch/list.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/branch/list.ts)_
## `eas branch:rename`
@@ -289,7 +288,7 @@ DESCRIPTION
rename a branch
```
_See code: [src/commands/branch/rename.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/branch/rename.ts)_
_See code: [src/commands/branch/rename.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/branch/rename.ts)_
## `eas branch:view [NAME]`
@@ -312,7 +311,7 @@ DESCRIPTION
view a branch
```
_See code: [src/commands/branch/view.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/branch/view.ts)_
_See code: [src/commands/branch/view.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/branch/view.ts)_
## `eas build`
@@ -342,7 +341,7 @@ DESCRIPTION
start a build
```
_See code: [src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/build/index.ts)_
_See code: [src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/build/index.ts)_
## `eas build:cancel [BUILD_ID]`
@@ -359,7 +358,7 @@ DESCRIPTION
cancel a build
```
_See code: [src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/build/cancel.ts)_
_See code: [src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/build/cancel.ts)_
## `eas build:configure`
@@ -376,7 +375,7 @@ DESCRIPTION
configure the project to support EAS Build
```
_See code: [src/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/build/configure.ts)_
_See code: [src/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/build/configure.ts)_
## `eas build:inspect`
@@ -411,7 +410,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/v2.9.0/packages/eas-cli/src/commands/build/inspect.ts)_
_See code: [src/commands/build/inspect.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/build/inspect.ts)_
## `eas build:list`
@@ -448,31 +447,7 @@ DESCRIPTION
list all builds for your project
```
_See code: [src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/build/list.ts)_
## `eas build:run`
run simulator/emulator builds from eas-cli
```
USAGE
$ eas build:run [--latest | --id <value> | --path <value> | --url <value>] [-p android|ios] [--offset
<value>] [--limit <value>]
FLAGS
-p, --platform=(android|ios)
--id=<value> ID of the simulator/emulator build to run
--latest Run the latest simulator/emulator build for specified platform
--limit=<value> The number of items to fetch each query. Defaults to 50 and is capped at 100.
--offset=<value> Start queries from specified index. Use for paginating results. Defaults to 0.
--path=<value> Path to the simulator/emulator build archive or app
--url=<value> Simulator/Emulator build archive url
DESCRIPTION
run simulator/emulator builds from eas-cli
```
_See code: [src/commands/build/run.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/build/run.ts)_
_See code: [src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/build/list.ts)_
## `eas build:submit`
@@ -492,7 +467,7 @@ FLAGS
--non-interactive Run command in non-interactive mode
--path=<value> Path to the .apk/.aab/.ipa file
--url=<value> App archive url
--verbose Always print logs from EAS Submit
--verbose Always print logs from Submission Service
--[no-]wait Wait for submission to complete
DESCRIPTION
@@ -519,7 +494,7 @@ DESCRIPTION
Update version of an app.
```
_See code: [src/commands/build/version/set.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/build/version/set.ts)_
_See code: [src/commands/build/version/set.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/build/version/set.ts)_
## `eas build:version:sync`
@@ -538,7 +513,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/v2.9.0/packages/eas-cli/src/commands/build/version/sync.ts)_
_See code: [src/commands/build/version/sync.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/build/version/sync.ts)_
## `eas build:view [BUILD_ID]`
@@ -555,7 +530,7 @@ DESCRIPTION
view a build for your project
```
_See code: [src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/build/view.ts)_
_See code: [src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/build/view.ts)_
## `eas channel:create [NAME]`
@@ -576,7 +551,7 @@ DESCRIPTION
create a channel
```
_See code: [src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/channel/create.ts)_
_See code: [src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/channel/create.ts)_
## `eas channel:edit [NAME]`
@@ -598,7 +573,7 @@ DESCRIPTION
point a channel at a new branch
```
_See code: [src/commands/channel/edit.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/channel/edit.ts)_
_See code: [src/commands/channel/edit.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/channel/edit.ts)_
## `eas channel:list`
@@ -618,7 +593,7 @@ DESCRIPTION
list all channels
```
_See code: [src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/channel/list.ts)_
_See code: [src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/channel/list.ts)_
## `eas channel:view [NAME]`
@@ -641,7 +616,7 @@ DESCRIPTION
view a channel
```
_See code: [src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/channel/view.ts)_
_See code: [src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/channel/view.ts)_
## `eas config`
@@ -660,7 +635,7 @@ DESCRIPTION
display project configuration (app.json + eas.json)
```
_See code: [src/commands/config.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/config.ts)_
_See code: [src/commands/config.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/config.ts)_
## `eas credentials`
@@ -677,7 +652,7 @@ DESCRIPTION
manage credentials
```
_See code: [src/commands/credentials.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/credentials.ts)_
_See code: [src/commands/credentials.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/credentials.ts)_
## `eas device:create`
@@ -691,7 +666,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/v2.9.0/packages/eas-cli/src/commands/device/create.ts)_
_See code: [src/commands/device/create.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/device/create.ts)_
## `eas device:delete`
@@ -711,7 +686,7 @@ DESCRIPTION
remove a registered device from your account
```
_See code: [src/commands/device/delete.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/device/delete.ts)_
_See code: [src/commands/device/delete.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/device/delete.ts)_
## `eas device:list`
@@ -732,7 +707,7 @@ DESCRIPTION
list all registered devices for your account
```
_See code: [src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/device/list.ts)_
_See code: [src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/device/list.ts)_
## `eas device:view [UDID]`
@@ -746,7 +721,7 @@ DESCRIPTION
view a device for your project
```
_See code: [src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/device/view.ts)_
_See code: [src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/device/view.ts)_
## `eas diagnostics`
@@ -760,7 +735,7 @@ DESCRIPTION
display environment info
```
_See code: [src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/diagnostics.ts)_
_See code: [src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/diagnostics.ts)_
## `eas help [COMMAND]`
@@ -848,7 +823,7 @@ DESCRIPTION
validate the local store configuration
```
_See code: [src/commands/metadata/lint.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/metadata/lint.ts)_
_See code: [src/commands/metadata/lint.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/metadata/lint.ts)_
## `eas metadata:pull`
@@ -865,7 +840,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/v2.9.0/packages/eas-cli/src/commands/metadata/pull.ts)_
_See code: [src/commands/metadata/pull.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/metadata/pull.ts)_
## `eas metadata:push`
@@ -882,7 +857,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/v2.9.0/packages/eas-cli/src/commands/metadata/push.ts)_
_See code: [src/commands/metadata/push.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/metadata/push.ts)_
## `eas open`
@@ -896,7 +871,7 @@ DESCRIPTION
open the project page in a web browser
```
_See code: [src/commands/open.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/open.ts)_
_See code: [src/commands/open.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/open.ts)_
## `eas project:info`
@@ -910,7 +885,7 @@ DESCRIPTION
information about the current project
```
_See code: [src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/project/info.ts)_
_See code: [src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/project/info.ts)_
## `eas project:init`
@@ -932,7 +907,7 @@ ALIASES
$ eas init
```
_See code: [src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/project/init.ts)_
_See code: [src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/project/init.ts)_
## `eas run`
@@ -956,7 +931,7 @@ DESCRIPTION
run simulator build
```
_See code: [src/commands/run/index.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/run/index.ts)_
_See code: [src/commands/run/index.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/run/index.ts)_
## `eas run:run`
@@ -980,7 +955,7 @@ DESCRIPTION
run simulator build
```
_See code: [src/commands/run/run.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/run/run.ts)_
_See code: [src/commands/run/run.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/run/run.ts)_
## `eas secret:create`
@@ -1003,7 +978,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/v2.9.0/packages/eas-cli/src/commands/secret/create.ts)_
_See code: [src/commands/secret/create.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/secret/create.ts)_
## `eas secret:delete`
@@ -1021,7 +996,7 @@ DESCRIPTION
delete an environment secret by ID
```
_See code: [src/commands/secret/delete.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/secret/delete.ts)_
_See code: [src/commands/secret/delete.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/secret/delete.ts)_
## `eas secret:list`
@@ -1035,7 +1010,7 @@ DESCRIPTION
list environment secrets available for your current app
```
_See code: [src/commands/secret/list.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/secret/list.ts)_
_See code: [src/commands/secret/list.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/secret/list.ts)_
## `eas secret:push`
@@ -1055,7 +1030,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/v2.9.0/packages/eas-cli/src/commands/secret/push.ts)_
_See code: [src/commands/secret/push.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/secret/push.ts)_
## `eas submit`
@@ -1075,7 +1050,7 @@ FLAGS
--non-interactive Run command in non-interactive mode
--path=<value> Path to the .apk/.aab/.ipa file
--url=<value> App archive url
--verbose Always print logs from EAS Submit
--verbose Always print logs from Submission Service
--[no-]wait Wait for submission to complete
DESCRIPTION
@@ -1085,7 +1060,7 @@ ALIASES
$ eas build:submit
```
_See code: [src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/submit.ts)_
_See code: [src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/submit.ts)_
## `eas update`
@@ -1115,7 +1090,7 @@ DESCRIPTION
publish an update group
```
_See code: [src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/update/index.ts)_
_See code: [src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/update/index.ts)_
## `eas update:configure`
@@ -1133,7 +1108,7 @@ DESCRIPTION
configure the project to support EAS Update
```
_See code: [src/commands/update/configure.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/update/configure.ts)_
_See code: [src/commands/update/configure.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/update/configure.ts)_
## `eas update:delete GROUPID`
@@ -1154,7 +1129,7 @@ DESCRIPTION
delete all the updates in an update group
```
_See code: [src/commands/update/delete.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/update/delete.ts)_
_See code: [src/commands/update/delete.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/update/delete.ts)_
## `eas update:list`
@@ -1176,7 +1151,7 @@ DESCRIPTION
view the recent updates
```
_See code: [src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/update/list.ts)_
_See code: [src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/update/list.ts)_
## `eas update:view GROUPID`
@@ -1196,7 +1171,7 @@ DESCRIPTION
update group details
```
_See code: [src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/update/view.ts)_
_See code: [src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/update/view.ts)_
## `eas webhook:create`
@@ -1217,7 +1192,7 @@ DESCRIPTION
create a webhook
```
_See code: [src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/webhook/create.ts)_
_See code: [src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/webhook/create.ts)_
## `eas webhook:delete [ID]`
@@ -1237,7 +1212,7 @@ DESCRIPTION
delete a webhook
```
_See code: [src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/webhook/delete.ts)_
_See code: [src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/webhook/delete.ts)_
## `eas webhook:list`
@@ -1254,7 +1229,7 @@ DESCRIPTION
list webhooks
```
_See code: [src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/webhook/list.ts)_
_See code: [src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/webhook/list.ts)_
## `eas webhook:update`
@@ -1276,7 +1251,7 @@ DESCRIPTION
update a webhook
```
_See code: [src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/webhook/update.ts)_
_See code: [src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/webhook/update.ts)_
## `eas webhook:view ID`
@@ -1293,7 +1268,7 @@ DESCRIPTION
view a webhook
```
_See code: [src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v2.9.0/packages/eas-cli/src/commands/webhook/view.ts)_
_See code: [src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v2.7.1/packages/eas-cli/src/commands/webhook/view.ts)_
## `eas whoami`
-48
View File
@@ -23267,26 +23267,6 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "excludedAssets",
"description": "",
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "INPUT_OBJECT",
"name": "PartialManifestAsset",
"ofType": null
}
}
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "gitCommitHash",
"description": "",
@@ -23299,18 +23279,6 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "isGitWorkingTreeDirty",
"description": "",
"type": {
"kind": "SCALAR",
"name": "Boolean",
"ofType": null
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "message",
"description": "",
@@ -27691,22 +27659,6 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "isGitWorkingTreeDirty",
"description": "",
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Boolean",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "manifestFragment",
"description": "",
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "eas-cli",
"description": "EAS command line tool",
"version": "2.9.0",
"version": "2.7.1",
"author": "Expo <[email protected]>",
"bin": {
"eas": "./bin/run"
@@ -14,7 +14,7 @@
"@expo/config-plugins": "5.0.1",
"@expo/config-types": "46.0.2",
"@expo/eas-build-job": "0.2.97",
"@expo/eas-json": "2.8.0",
"@expo/eas-json": "2.7.1",
"@expo/json-file": "8.2.36",
"@expo/multipart-body-parser": "1.1.0",
"@expo/osascript": "2.0.33",
+3 -3
View File
@@ -160,7 +160,7 @@ export async function ensureBranchExistsAsync(
appId: string;
branchName: string;
}
): Promise<{ branchId: string; createdBranch: boolean }> {
): Promise<{ branchId: string }> {
try {
const updateBranch = await BranchQuery.getBranchByNameAsync(graphqlClient, {
appId,
@@ -168,14 +168,14 @@ export async function ensureBranchExistsAsync(
});
const { id } = updateBranch;
return { branchId: id, createdBranch: false };
return { branchId: id };
} catch (error) {
if (error instanceof BranchNotFoundError) {
const newUpdateBranch = await createUpdateBranchOnAppAsync(graphqlClient, {
appId,
name: branchName,
});
return { branchId: newUpdateBranch.id, createdBranch: true };
return { branchId: newUpdateBranch.id };
} else {
throw error;
}
+1 -1
View File
@@ -281,7 +281,7 @@ async function sendBuildRequestAsync<TPlatform extends Platform, Credentials, TJ
);
}
export type MaybeBuildFragment = BuildFragment | null;
type MaybeBuildFragment = BuildFragment | null;
export async function waitForBuildEndAsync(
graphqlClient: ExpoGraphqlClient,
+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 = '0.0.120';
const PLUGIN_PACKAGE_VERSION = '0.0.119';
export interface LocalBuildOptions {
enable: boolean;
+9 -48
View File
@@ -2,11 +2,11 @@ import chalk from 'chalk';
import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
import { PaginatedQueryOptions } from '../commandUtils/pagination';
import { AppPlatform, BuildFilter, BuildFragment } from '../graphql/generated';
import { BuildFilter, BuildFragment } from '../graphql/generated';
import { BuildQuery } from '../graphql/queries/BuildQuery';
import Log from '../log';
import { appPlatformDisplayNames } from '../platform';
import { promptAsync } from '../prompts';
import { fromNow } from '../utils/date';
import { printJsonOnlyOutput } from '../utils/json';
import { paginatedQueryWithConfirmPromptAsync } from '../utils/queries';
import { formatGraphQLBuild } from './utils/formatBuild';
@@ -55,51 +55,18 @@ export async function listAndRenderBuildsOnAppAsync(
}
}
function formatBuildChoiceValue(value: string | undefined | null): string {
return value ? chalk.bold(value) : chalk.dim('Unknown');
}
function formatBuildChoiceTitleAndDescription(build: BuildFragment): {
title: string;
description: string;
} {
const splitCommitMessage = build.gitCommitMessage?.split('\n');
const formattedCommitData =
build.gitCommitHash && splitCommitMessage && splitCommitMessage.length > 0
? `${chalk.dim(build.gitCommitHash.slice(0, 7))} "${chalk.bold(
splitCommitMessage[0] + (splitCommitMessage.length > 1 ? '…' : '')
)}"`
: 'Unknown';
return {
title: `ID: ${chalk.dim(build.id)} (${chalk.dim(`${fromNow(new Date(build.updatedAt))} ago`)})`,
description: [
`\tVersion: ${formatBuildChoiceValue(build.appVersion)}`,
`\t${
build.platform === AppPlatform.Ios ? 'Build number' : 'Version code'
}: ${formatBuildChoiceValue(build.appBuildVersion)}`,
`\tCommit: ${formattedCommitData}`,
].join('\n'),
};
}
export async function listAndSelectBuildsOnAppAsync(
graphqlClient: ExpoGraphqlClient,
selectedPlatform: AppPlatform,
{
projectId,
projectDisplayName,
filter,
queryOptions,
selectPromptDisabledFunction,
warningMessage,
}: {
projectId: string;
projectDisplayName: string;
filter?: BuildFilter;
queryOptions: PaginatedQueryOptions;
selectPromptDisabledFunction?: (build: BuildFragment) => boolean;
warningMessage?: string;
}
): Promise<BuildFragment> {
const builds = await BuildQuery.viewBuildsOnAppAsync(graphqlClient, {
@@ -115,20 +82,14 @@ export async function listAndSelectBuildsOnAppAsync(
const { selectedSimulatorBuild } = await promptAsync({
type: 'select',
message: `Select ${selectedPlatform === AppPlatform.Ios ? 'iOS' : 'Android'} ${
selectedPlatform === AppPlatform.Ios ? 'simulator' : 'emulator'
} build to run for ${projectDisplayName} app`,
message: `Select simulator build to run for ${projectDisplayName} app`,
name: 'selectedSimulatorBuild',
choices: builds.map(build => {
const buildChoice = formatBuildChoiceTitleAndDescription(build);
return {
title: buildChoice.title,
description: buildChoice.description,
value: build,
disabled: selectPromptDisabledFunction?.(build),
};
}),
warn: warningMessage,
choices: builds.map(build => ({
title: `id: ${build.id}, platform: ${appPlatformDisplayNames[build.platform]}, version: ${
build.appVersion
}, build number: ${build.appBuildVersion}`,
value: build,
})),
});
return selectedSimulatorBuild;
}
@@ -7,7 +7,6 @@ import {
EasJsonUtils,
SubmitProfile,
} from '@expo/eas-json';
import assert from 'assert';
import chalk from 'chalk';
import nullthrows from 'nullthrows';
@@ -38,9 +37,6 @@ import {
validateAppConfigForRemoteVersionSource,
validateBuildProfileVersionSettings,
} from '../project/remoteVersionSource';
import { confirmAsync } from '../prompts';
import { runAsync } from '../run/run';
import { isRunnableOnSimulatorOrEmulator } from '../run/utils';
import { createSubmissionContextAsync } from '../submit/context';
import {
exitWithNonZeroCodeIfSomeSubmissionsDidntFinish,
@@ -50,13 +46,11 @@ import {
import { printSubmissionDetailsUrls } from '../submit/utils/urls';
import { validateBuildProfileConfigMatchesProjectConfigAsync } from '../update/utils';
import { Actor } from '../user/User';
import { downloadAndMaybeExtractAppAsync } from '../utils/download';
import { truthy } from '../utils/expodash/filter';
import { printJsonOnlyOutput } from '../utils/json';
import { ProfileData, getProfilesAsync } from '../utils/profiles';
import { getVcsClient } from '../vcs';
import { prepareAndroidBuildAsync } from './android/build';
import { BuildRequestSender, MaybeBuildFragment, waitForBuildEndAsync } from './build';
import { BuildRequestSender, waitForBuildEndAsync } from './build';
import { ensureProjectConfiguredAsync } from './configure';
import { BuildContext } from './context';
import { createBuildContextAsync } from './createContext';
@@ -248,9 +242,6 @@ export async function runBuildAndSubmitAsync(
const haveAllBuildsFailedOrCanceled = builds.every(
build => build?.status && [BuildStatus.Errored, BuildStatus.Canceled].includes(build?.status)
);
await maybeDownloadAndRunSimulatorBuildsAsync(builds, flags);
if (haveAllBuildsFailedOrCanceled || !flags.autoSubmit) {
if (flags.json) {
printJsonOnlyOutput(builds);
@@ -418,35 +409,3 @@ function exitWithNonZeroCodeIfSomeBuildsFailed(maybeBuilds: (BuildFragment | nul
process.exit(1);
}
}
async function downloadAndRunAsync(build: BuildFragment): Promise<void> {
assert(build.artifacts?.applicationArchiveUrl);
const buildPath = await downloadAndMaybeExtractAppAsync(
build.artifacts.applicationArchiveUrl,
build.platform
);
await runAsync(buildPath, build.platform);
}
async function maybeDownloadAndRunSimulatorBuildsAsync(
builds: MaybeBuildFragment[],
flags: BuildFlags
): Promise<void> {
const simBuilds = builds.filter(truthy).filter(isRunnableOnSimulatorOrEmulator);
if (simBuilds.length > 0 && !flags.autoSubmit && !flags.nonInteractive) {
for (const simBuild of simBuilds) {
if (simBuild.platform === AppPlatform.Android || process.platform === 'darwin') {
Log.newLine();
const confirm = await confirmAsync({
message: `Install and run the ${
simBuild.platform === AppPlatform.Android ? 'Android' : 'iOS'
} build on ${simBuild.platform === AppPlatform.Android ? 'an emulator' : 'a simulator'}?`,
});
if (confirm) {
await downloadAndRunAsync(simBuild);
}
}
}
}
}
+21 -62
View File
@@ -1,9 +1,9 @@
import { Errors, Flags } from '@oclif/core';
import { pathExists } from 'fs-extra';
import { existsSync } from 'fs-extra';
import assert from 'node:assert';
import path from 'path';
import { getLatestBuildAsync, listAndSelectBuildsOnAppAsync } from '../../build/queries';
import { BuildDistributionType } from '../../build/types';
import EasCommand from '../../commandUtils/EasCommand';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
import {
@@ -11,18 +11,13 @@ import {
PaginatedQueryOptions,
getPaginatedQueryOptions,
} from '../../commandUtils/pagination';
import { AppPlatform, BuildFragment, BuildStatus, DistributionType } from '../../graphql/generated';
import { AppPlatform, BuildFragment, BuildStatus } from '../../graphql/generated';
import { BuildQuery } from '../../graphql/queries/BuildQuery';
import Log from '../../log';
import { getDisplayNameForProjectIdAsync } from '../../project/projectUtils';
import { promptAsync } from '../../prompts';
import { RunArchiveFlags, runAsync } from '../../run/run';
import { isRunnableOnSimulatorOrEmulator } from '../../run/utils';
import {
downloadAndMaybeExtractAppAsync,
extractAppFromLocalArchiveAsync,
} from '../../utils/download';
import { getEasBuildRunCacheDirectoryPath } from '../../utils/paths';
import { buildDistributionTypeToGraphQLDistributionType } from '../../utils/buildDistribution';
import { downloadAndExtractAppAsync, extractAppFromLocalArchiveAsync } from '../../utils/download';
interface RawRunFlags {
latest?: boolean;
@@ -42,6 +37,8 @@ interface RunCommandFlags {
}
export default class Run extends EasCommand {
static override hidden = true;
static override description = 'run simulator/emulator builds from eas-cli';
static override flags = {
@@ -54,7 +51,7 @@ export default class Run extends EasCommand {
exclusive: ['latest', 'id', 'path'],
}),
path: Flags.string({
description: 'Path to the simulator/emulator build archive or app',
description: 'Path to the simulator/emulator build archive or simulator build app',
exclusive: ['latest', 'id', 'url'],
}),
id: Flags.string({
@@ -100,19 +97,13 @@ export default class Run extends EasCommand {
const selectedPlatform = await resolvePlatformAsync(platform);
if (platform === 'ios' && process.platform !== 'darwin') {
Errors.error('You can only use an iOS simulator to run apps on macOS devices', {
exit: 1,
});
}
if (
runArchiveFlags.path &&
!(
(runArchiveFlags.path.endsWith('.tar.gz') ||
runArchiveFlags.path.endsWith('.app') ||
runArchiveFlags.path.endsWith('.apk')) &&
(await pathExists(runArchiveFlags.path))
existsSync(runArchiveFlags.path)
)
) {
Errors.error('The path must point to a .tar.gz archive, .apk file, or .app directory', {
@@ -130,10 +121,6 @@ export default class Run extends EasCommand {
}
async function resolvePlatformAsync(platform?: string): Promise<AppPlatform> {
if (process.platform !== 'darwin') {
return AppPlatform.Android;
}
if (platform && Object.values(AppPlatform).includes(platform.toUpperCase() as AppPlatform)) {
return platform.toUpperCase() as AppPlatform;
}
@@ -156,9 +143,6 @@ async function maybeGetBuildAsync(
projectId: string,
paginatedQueryOptions: PaginatedQueryOptions
): Promise<BuildFragment | null> {
const distributionType =
flags.selectedPlatform === AppPlatform.Ios ? DistributionType.Simulator : undefined;
if (flags.runArchiveFlags.id) {
return BuildQuery.byIdAsync(graphqlClient, flags.runArchiveFlags.id);
} else if (
@@ -167,25 +151,26 @@ async function maybeGetBuildAsync(
!flags.runArchiveFlags.url &&
!flags.runArchiveFlags.latest
) {
return await listAndSelectBuildsOnAppAsync(graphqlClient, flags.selectedPlatform, {
return await listAndSelectBuildsOnAppAsync(graphqlClient, {
projectId,
projectDisplayName: await getDisplayNameForProjectIdAsync(graphqlClient, projectId),
filter: {
platform: flags.selectedPlatform,
distribution: distributionType,
distribution: buildDistributionTypeToGraphQLDistributionType(
BuildDistributionType.SIMULATOR
),
status: BuildStatus.Finished,
},
queryOptions: paginatedQueryOptions,
selectPromptDisabledFunction: build => !isRunnableOnSimulatorOrEmulator(build),
warningMessage:
'Artifacts for this build have expired and are no longer available, or this is not a simulator/emulator build.',
});
} else if (flags.runArchiveFlags.latest) {
return await getLatestBuildAsync(graphqlClient, {
projectId,
filter: {
platform: flags.selectedPlatform,
distribution: distributionType,
distribution: buildDistributionTypeToGraphQLDistributionType(
BuildDistributionType.SIMULATOR
),
status: BuildStatus.Finished,
},
});
@@ -194,17 +179,6 @@ async function maybeGetBuildAsync(
}
}
function getEasBuildRunCachedAppPath(
projectId: string,
buildId: string,
platform: AppPlatform
): string {
return path.join(
getEasBuildRunCacheDirectoryPath(),
`${projectId}_${buildId}.${platform === AppPlatform.Ios ? 'app' : 'apk'}`
);
}
async function getPathToSimulatorBuildAppAsync(
graphqlClient: ExpoGraphqlClient,
projectId: string,
@@ -212,40 +186,25 @@ async function getPathToSimulatorBuildAppAsync(
queryOptions: PaginatedQueryOptions
): Promise<string> {
const maybeBuild = await maybeGetBuildAsync(graphqlClient, flags, projectId, queryOptions);
const appExtension = flags.selectedPlatform === AppPlatform.Ios ? 'app' : 'apk';
if (maybeBuild) {
const cachedAppPath = getEasBuildRunCachedAppPath(
projectId,
maybeBuild.id,
flags.selectedPlatform
);
if (await pathExists(cachedAppPath)) {
Log.newLine();
Log.log(`Using cached app...`);
return cachedAppPath;
}
if (!maybeBuild.artifacts?.applicationArchiveUrl) {
throw new Error('Build does not have an application archive url');
}
return await downloadAndMaybeExtractAppAsync(
return await downloadAndExtractAppAsync(
maybeBuild.artifacts.applicationArchiveUrl,
flags.selectedPlatform,
cachedAppPath
appExtension
);
}
if (flags.runArchiveFlags.url) {
return await downloadAndMaybeExtractAppAsync(flags.runArchiveFlags.url, flags.selectedPlatform);
return await downloadAndExtractAppAsync(flags.runArchiveFlags.url, appExtension);
}
if (flags.runArchiveFlags.path?.endsWith('.tar.gz')) {
return await extractAppFromLocalArchiveAsync(
flags.runArchiveFlags.path,
flags.selectedPlatform
);
return await extractAppFromLocalArchiveAsync(flags.runArchiveFlags.path!, appExtension);
}
// this should never fail, due to the validation in sanitizeFlagsAsync
+8 -22
View File
@@ -412,24 +412,18 @@ export default class UpdatePublish extends EasCommand {
}
}
const { branchId, createdBranch } = await ensureBranchExistsAsync(graphqlClient, {
const { branchId } = await ensureBranchExistsAsync(graphqlClient, {
appId: projectId,
branchName,
});
if (createdBranch) {
await ensureChannelExistsAsync(graphqlClient, {
appId: projectId,
branchId,
channelName: branchName,
});
}
await ensureChannelExistsAsync(graphqlClient, {
appId: projectId,
branchId,
channelName: branchName,
});
Log.withTick(`Channel: ${chalk.bold(branchName)} pointed at branch: ${chalk.bold(branchName)}`);
const vcsClient = getVcsClient();
const gitCommitHash = await vcsClient.getCommitHashAsync();
const isGitWorkingTreeDirty = await vcsClient.hasUncommittedChangesAsync();
const gitCommitHash = await getVcsClient().getCommitHashAsync();
// Sort the updates into different groups based on their platform specific runtime versions
const updateGroups: PublishUpdateGroupInput[] = runtimeToPlatformMapping.map(
@@ -452,7 +446,6 @@ export default class UpdatePublish extends EasCommand {
runtimeVersion: republish ? oldRuntimeVersion : runtimeVersion,
message: truncatedMessage,
gitCommitHash,
isGitWorkingTreeDirty,
awaitingCodeSigningInfo: !!codeSigningInfo,
};
}
@@ -554,14 +547,7 @@ export default class UpdatePublish extends EasCommand {
: []),
...(newIosUpdate ? [{ label: 'iOS update ID', value: newIosUpdate.id }] : []),
{ label: 'Message', value: truncatedMessage },
...(gitCommitHash
? [
{
label: 'Commit',
value: `${gitCommitHash}${isGitWorkingTreeDirty ? '*' : ''}`,
},
]
: []),
...(gitCommitHash ? [{ label: 'Commit', value: gitCommitHash }] : []),
{ label: 'Website link', value: updateGroupLink },
])
);
@@ -23,12 +23,13 @@ function formatDeviceClass(device: Device | NewDevice): string {
export default function formatDevice(device: Device, team?: AppleTeamIdAndName): string {
const fields: FormatFieldsItem[] = [
{ label: 'UDID', value: device.identifier },
{ label: 'ID', value: device.id },
{ label: 'Name', value: device.name ?? 'Unknown' },
{
label: 'Class',
value: formatDeviceClass(device),
},
{ label: 'UDID', value: device.identifier },
];
if (team) {
-3
View File
@@ -3347,9 +3347,7 @@ export type PublicArtifacts = {
export type PublishUpdateGroupInput = {
awaitingCodeSigningInfo?: InputMaybe<Scalars['Boolean']>;
branchId: Scalars['String'];
excludedAssets?: InputMaybe<Array<PartialManifestAsset>>;
gitCommitHash?: InputMaybe<Scalars['String']>;
isGitWorkingTreeDirty?: InputMaybe<Scalars['Boolean']>;
message?: InputMaybe<Scalars['String']>;
runtimeVersion: Scalars['String'];
updateInfoGroup: UpdateInfoGroup;
@@ -4009,7 +4007,6 @@ export type Update = ActivityTimelineProjectActivity & {
gitCommitHash?: Maybe<Scalars['String']>;
group: Scalars['String'];
id: Scalars['ID'];
isGitWorkingTreeDirty: Scalars['Boolean'];
manifestFragment: Scalars['String'];
manifestPermalink: Scalars['String'];
message?: Maybe<Scalars['String']>;
@@ -0,0 +1,67 @@
import { ProjectConfig, getConfig } from '@expo/config';
import { getExpoConfig } from '../expoConfig';
jest.mock('@expo/config');
describe(getExpoConfig, () => {
it('correctly restores process.env as best as possible', () => {
process.env.BEFORE_CALL_KEY = 'BEFORE';
process.env.BEFORE_CALL_KEY_OVERRIDDEN_BY_WITHIN = 'BEFORE_OVERRIDDEN_BY_WITHIN';
process.env.BEFORE_CALL_KEY_OVERRIDDEN_BY_OPTS = 'BEFORE_OVERRIDDEN_BY_OPTS';
process.env.BEFORE_CALL_KEY_OVERRIDDEN_BY_OPTS_AND_WITHIN =
'BEFORE_CALL_KEY_OVERRIDDEN_BY_OPTS_AND_WITHIN';
jest.mocked(getConfig).mockImplementation(() => {
process.env.WITHIN_CALL_KEY = 'WITHIN';
process.env.BEFORE_CALL_KEY_OVERRIDDEN_BY_WITHIN = 'OVERRIDDEN_VALUE';
process.env.OPTS_KEY_OVERRIDDEN_BY_WITHIN = 'OVERRIDDEN_VALUE';
process.env.OPTS_KEY_OVERRIDDEN_BY_WITHIN_TO_SAME_VALUE =
'OPTS_KEY_OVERRIDDEN_BY_WITHIN_TO_SAME_VALUE';
process.env.BEFORE_CALL_KEY_OVERRIDDEN_BY_OPTS_AND_WITHIN = 'OVERRIDDEN_WITHIN';
return {} as ProjectConfig;
});
// ensure idempotent (run N times)
for (let i = 0; i < 2; i++) {
getExpoConfig('', {
env: {
OPTS_KEY: 'OPTS',
BEFORE_CALL_KEY_OVERRIDDEN_BY_OPTS: 'OVERRIDDEN_VALUE',
OPTS_KEY_OVERRIDDEN_BY_WITHIN: 'OPTS_KEY_OVERRIDDEN_BY_WITHIN',
OPTS_KEY_OVERRIDDEN_BY_WITHIN_TO_SAME_VALUE:
'OPTS_KEY_OVERRIDDEN_BY_WITHIN_TO_SAME_VALUE',
BEFORE_CALL_KEY_OVERRIDDEN_BY_OPTS_AND_WITHIN: 'OVERRIDDEN_OPTS',
},
});
// env from before the call should be restored
expect(process.env.BEFORE_CALL_KEY).toEqual('BEFORE');
// env from before the call but overridden within the call should not be restored
expect(process.env.BEFORE_CALL_KEY_OVERRIDDEN_BY_WITHIN).toEqual('OVERRIDDEN_VALUE');
// env from before the call but overridden by opts should be restored
expect(process.env.BEFORE_CALL_KEY_OVERRIDDEN_BY_OPTS).toEqual('BEFORE_OVERRIDDEN_BY_OPTS');
// env added within the call should be kept
expect(process.env.WITHIN_CALL_KEY).toEqual('WITHIN');
// env added by opts should be removed
expect(process.env.OPTS_KEY).toBeUndefined();
// env added by opts but overridden within the call should be retained and have overridden value
expect(process.env.OPTS_KEY_OVERRIDDEN_BY_WITHIN).toEqual('OVERRIDDEN_VALUE');
// env added by opts but overridden within the call to the same value will be removed
// note that this is a known bug/limitation of this approach
expect(process.env.OPTS_KEY_OVERRIDDEN_BY_WITHIN_TO_SAME_VALUE).toBeUndefined();
// env from before but overridden within the call and by opts should retain value from
// within the call
expect(process.env.BEFORE_CALL_KEY_OVERRIDDEN_BY_OPTS_AND_WITHIN).toEqual(
'OVERRIDDEN_WITHIN'
);
}
});
});
@@ -8,10 +8,7 @@ import {
getApplicationIdAsync,
} from './android/applicationId';
import { resolveGradleBuildContextAsync } from './android/gradle';
import {
ensureBundleIdentifierIsDefinedForManagedProjectAsync,
getBundleIdentifierAsync,
} from './ios/bundleIdentifier';
import { getBundleIdentifierAsync } from './ios/bundleIdentifier';
import { resolveXcodeBuildContextAsync } from './ios/scheme';
import { findApplicationTarget, resolveTargetsAsync } from './ios/target';
import { resolveWorkflowAsync } from './workflow';
@@ -26,20 +23,15 @@ export async function getApplicationIdentifierAsync(
if (platform === Platform.ANDROID) {
const profile = buildProfile as BuildProfile<Platform.ANDROID>;
const workflow = await resolveWorkflowAsync(projectDir, Platform.ANDROID);
const gradleContext = await resolveGradleBuildContextAsync(projectDir, profile);
if (workflow === Workflow.MANAGED) {
return await ensureApplicationIdIsDefinedForManagedProjectAsync(projectDir, exp, actor);
await ensureApplicationIdIsDefinedForManagedProjectAsync(projectDir, exp, actor);
}
const gradleContext = await resolveGradleBuildContextAsync(projectDir, profile);
return await getApplicationIdAsync(projectDir, exp, gradleContext);
} else {
const workflow = await resolveWorkflowAsync(projectDir, Platform.IOS);
const profile = buildProfile as BuildProfile<Platform.IOS>;
if (workflow === Workflow.MANAGED) {
return await ensureBundleIdentifierIsDefinedForManagedProjectAsync(projectDir, exp, actor);
}
const xcodeBuildContext = await resolveXcodeBuildContextAsync(
{ exp, projectDir, nonInteractive: false },
profile
+25 -1
View File
@@ -1,5 +1,6 @@
import { ExpoConfig, getConfig } from '@expo/config';
import { Env } from '@expo/eas-build-job';
import nullthrows from 'nullthrows';
export interface ExpoConfigOptions {
env?: Env;
@@ -9,6 +10,11 @@ export interface ExpoConfigOptions {
export function getExpoConfig(projectDir: string, opts: ExpoConfigOptions = {}): ExpoConfig {
const originalProcessEnv: NodeJS.ProcessEnv = process.env;
const optsEnvKeys = opts.env ? Object.keys(opts.env) : [];
const originalEnvKeys = new Set(Object.keys(process.env));
const newKeysAddedToProcessEnv = new Set(optsEnvKeys.filter(k => !originalEnvKeys.has(k)));
try {
process.env = {
...process.env,
@@ -20,6 +26,24 @@ export function getExpoConfig(projectDir: string, opts: ExpoConfigOptions = {}):
});
return exp;
} finally {
process.env = originalProcessEnv;
optsEnvKeys.forEach(k => {
// if new key added, remove unless it was modified
if (newKeysAddedToProcessEnv.has(k)) {
if (k in originalProcessEnv) {
if (process.env[k] === originalProcessEnv[k]) {
delete process.env[k];
}
} else {
if (nullthrows(opts.env)[k] === process.env[k]) {
delete process.env[k];
}
}
} else {
// opts key overrode env key, but only if the value is equal to the one declared by opts
if (process.env[k] === nullthrows(opts.env)[k]) {
process.env[k] = originalProcessEnv[k];
}
}
});
}
}
-57
View File
@@ -1,57 +0,0 @@
import spawnAsync, { SpawnResult } from '@expo/spawn-async';
import glob from 'fast-glob';
import path from 'path';
import Log from '../../log';
import { getAndroidSdkRootAsync } from './sdk';
async function aaptAsync(...options: string[]): Promise<SpawnResult> {
try {
return await spawnAsync(await getAaptExecutableAsync(), options);
} catch (error: any) {
if (error.stderr) {
Log.error(error.stderr);
}
throw error;
}
}
export async function getAaptExecutableAsync(): Promise<string> {
const sdkRoot = await getAndroidSdkRootAsync();
if (!sdkRoot) {
Log.debug('Failed to resolve the Android SDK path, falling back to global aapt executable');
return 'aapt';
}
const aaptPaths = await glob(
path.posix.join('build-tools/**', process.platform === 'win32' ? 'aapt.exe' : 'aapt'),
{ cwd: sdkRoot, absolute: true }
);
if (aaptPaths.length === 0) {
throw new Error('Failed to resolve the Android aapt path');
}
const sorted = aaptPaths.sort();
return sorted[sorted.length - 1];
}
export async function getAptParametersAsync(
appPath: string
): Promise<{ packageName: string; activityName: string }> {
const { stdout } = await aaptAsync('dump', 'badging', appPath);
const packageNameMatch = stdout.match(/package: name='([^']+)'/);
if (!packageNameMatch) {
throw new Error(`Could not read package name from ${appPath}`);
}
// get activity name
const activityNameMatch = stdout.match(/launchable-activity: name='([^']+)'/);
if (!activityNameMatch) {
throw new Error(`Could not read activity name from ${appPath}`);
}
return {
packageName: packageNameMatch[1],
activityName: activityNameMatch[1],
};
}
-132
View File
@@ -1,132 +0,0 @@
import spawnAsync, { SpawnResult } from '@expo/spawn-async';
import os from 'os';
import path from 'path';
import Log from '../../log';
import { truthy } from '../../utils/expodash/filter';
import { sleepAsync } from '../../utils/promise';
import { getAndroidSdkRootAsync } from './sdk';
export interface AndroidEmulator {
pid?: string;
name: string;
}
const BEGINNING_OF_ADB_ERROR_MESSAGE = 'error: ';
export async function adbAsync(...args: string[]): Promise<SpawnResult> {
const adbExecutable = await getAdbExecutableAsync();
try {
return await spawnAsync(adbExecutable, args);
} catch (error: any) {
let errorMessage = (error.stderr || error.stdout || error.message).trim();
if (errorMessage.startsWith(BEGINNING_OF_ADB_ERROR_MESSAGE)) {
errorMessage = errorMessage.substring(BEGINNING_OF_ADB_ERROR_MESSAGE.length);
}
error.message = errorMessage;
throw error;
}
}
export async function getAdbExecutableAsync(): Promise<string> {
const sdkRoot = await getAndroidSdkRootAsync();
if (!sdkRoot) {
Log.debug('Failed to resolve the Android SDK path, falling back to global adb executable');
return 'adb';
}
return path.join(sdkRoot, 'platform-tools/adb');
}
export function sanitizeAdbDeviceName(deviceName: string): string | undefined {
return deviceName.trim().split(/[\r\n]+/)[0];
}
/**
* Return the Emulator name for an emulator ID, this can be used to determine if an emulator is booted.
*
* @param devicePid a value like `emulator-5554` from `abd devices`
*/
export async function getAdbNameForDeviceIdAsync(emulatorPid: string): Promise<string | null> {
const { stdout } = await adbAsync('-s', emulatorPid, 'emu', 'avd', 'name');
if (stdout.match(/could not connect to TCP port .*: Connection refused/)) {
// Can also occur when the emulator does not exist.
throw new Error(`Emulator not found: ${stdout}`);
}
return sanitizeAdbDeviceName(stdout) ?? null;
}
// TODO: This is very expensive for some operations.
export async function getRunningEmulatorsAsync(): Promise<AndroidEmulator[]> {
const { stdout } = await adbAsync('devices', '-l');
const splitItems = stdout.trim().split(os.EOL);
const attachedDevices: {
pid: string;
type: string;
}[] = splitItems
// First line is `"List of devices attached"`, remove it
.slice(1, splitItems.length)
.map(line => {
// unauthorized: ['FA8251A00719', 'unauthorized', 'usb:338690048X', 'transport_id:5']
// authorized: ['FA8251A00719', 'device', 'usb:336592896X', 'product:walleye', 'model:Pixel_2', 'device:walleye', 'transport_id:4']
// emulator: ['emulator-5554', 'offline', 'transport_id:1']
const [pid] = line.split(' ').filter(truthy);
const type = line.includes('emulator') ? 'emulator' : 'device';
return { pid, type };
})
.filter(({ pid, type }) => !!pid && type === 'emulator');
const devicePromises = attachedDevices.map<Promise<AndroidEmulator>>(async ({ pid }) => {
const name = (await getAdbNameForDeviceIdAsync(pid)) ?? '';
return {
pid,
name,
};
});
return Promise.all(devicePromises);
}
export async function getFirstRunningEmulatorAsync(): Promise<AndroidEmulator | null> {
const emulators = await getRunningEmulatorsAsync();
return emulators[0] ?? null;
}
/**
* Returns true if emulator is booted
*
* @param emulatorPid
*/
export async function isEmulatorBootedAsync(emulatorPid: string): Promise<boolean> {
try {
const { stdout } = await adbAsync('-s', emulatorPid, 'shell', 'getprop', 'sys.boot_completed');
if (stdout.trim() === '1') {
return true;
}
return false;
} catch {
return false;
}
}
export async function waitForEmulatorToBeBootedAsync(
maxWaitTimeMs: number,
intervalMs: number
): Promise<AndroidEmulator> {
Log.newLine();
Log.log('Waiting for the Android emulator to start...');
const startTime = Date.now();
while (Date.now() - startTime < maxWaitTimeMs) {
const emulator = await getFirstRunningEmulatorAsync();
if (emulator?.pid && (await isEmulatorBootedAsync(emulator.pid))) {
return emulator;
}
await sleepAsync(intervalMs);
}
throw new Error('Timed out waiting for the Android emulator to start.');
}
@@ -1,160 +0,0 @@
import spawnAsync, { SpawnResult } from '@expo/spawn-async';
import chalk from 'chalk';
import assert from 'node:assert';
import os from 'os';
import path from 'path';
import Log from '../../log';
import { promptAsync } from '../../prompts';
import { truthy } from '../../utils/expodash/filter';
import {
AndroidEmulator,
adbAsync,
getFirstRunningEmulatorAsync,
isEmulatorBootedAsync,
waitForEmulatorToBeBootedAsync,
} from './adb';
import { getAndroidSdkRootAsync } from './sdk';
export const EMULATOR_MAX_WAIT_TIMEOUT_MS = 60 * 1000 * 3;
export async function getEmulatorExecutableAsync(): Promise<string> {
const sdkRoot = await getAndroidSdkRootAsync();
if (sdkRoot) {
return path.join(sdkRoot, 'emulator', 'emulator');
}
return 'emulator';
}
async function emulatorAsync(...options: string[]): Promise<SpawnResult> {
const emulatorExecutable = await getEmulatorExecutableAsync();
try {
return await spawnAsync(emulatorExecutable, options);
} catch (error: any) {
if (error.stderr) {
Log.error(error.stderr);
}
throw error;
}
}
async function getAvaliableAndroidEmulatorsAsync(): Promise<AndroidEmulator[]> {
try {
const { stdout } = await emulatorAsync('-list-avds');
return stdout
.split(os.EOL)
.filter(truthy)
.map(name => ({
name,
}));
} catch {
return [];
}
}
/** Start an Android device and wait until it is booted. */
async function bootEmulatorAsync(
emulator: AndroidEmulator,
{
timeout = EMULATOR_MAX_WAIT_TIMEOUT_MS,
interval = 1000,
}: {
/** Time in milliseconds to wait before asserting a timeout error. */
timeout?: number;
interval?: number;
} = {}
): Promise<AndroidEmulator> {
Log.newLine();
Log.log(`Opening emulator ${chalk.bold(emulator.name)}`);
const emulatorExecutable = await getEmulatorExecutableAsync();
// Start a process to open an emulator
const emulatorProcess = spawnAsync(emulatorExecutable, [`@${emulator.name}`], {
stdio: 'ignore',
detached: true,
});
// we don't want to wait for the emulator process to exit before we can finish `eas build:run` command
// https://github.com/expo/eas-cli/pull/1485#discussion_r1007935871
emulatorProcess.child.unref();
return await waitForEmulatorToBeBootedAsync(timeout, interval);
}
export async function selectEmulatorAsync(): Promise<AndroidEmulator> {
const runningEmulator = await getFirstRunningEmulatorAsync();
if (runningEmulator) {
Log.newLine();
Log.log(`Using open emulator: ${chalk.bold(runningEmulator.name)}`);
return runningEmulator;
}
const emulators = await getAvaliableAndroidEmulatorsAsync();
Log.newLine();
const { selectedEmulator } = await promptAsync({
type: 'select',
message: `Select an emulator to run your app on`,
name: 'selectedEmulator',
choices: emulators.map(emulator => ({
title: emulator.name,
value: emulator,
})),
});
return selectedEmulator;
}
export async function ensureEmulatorBootedAsync(
emulator: AndroidEmulator
): Promise<AndroidEmulator> {
if (!emulator.pid || !(await isEmulatorBootedAsync(emulator.pid))) {
return await bootEmulatorAsync(emulator);
}
return emulator;
}
export async function installAppAsync(
emulator: AndroidEmulator,
apkFilePath: string
): Promise<void> {
Log.newLine();
Log.log('Installing your app...');
assert(emulator.pid);
await adbAsync('-s', emulator.pid, 'install', '-r', '-d', apkFilePath);
Log.succeed('Successfully installed your app!');
}
export async function startAppAsync(
emulator: AndroidEmulator,
packageName: string,
activityName: string
): Promise<void> {
Log.newLine();
Log.log('Starting your app...');
assert(emulator.pid);
await adbAsync(
'-s',
emulator.pid,
'shell',
'am',
'start',
'-a',
'android.intent.action.MAIN',
'-f',
'0x20000000', // FLAG_ACTIVITY_SINGLE_TOP -- If set, the activity will not be launched if it is already running at the top of the history stack.
'-n',
`${packageName}/${activityName}`
);
Log.succeed('Successfully started your app!');
}
+3 -10
View File
@@ -1,12 +1,5 @@
import { getAptParametersAsync } from './aapt';
import * as emulator from './emulator';
import { assertExecutablesExistAsync } from './systemRequirements';
import Log from '../../log';
export async function runAppOnAndroidEmulatorAsync(appPath: string): Promise<void> {
await assertExecutablesExistAsync();
const selectedEmulator = await emulator.selectEmulatorAsync();
const bootedEmulator = await emulator.ensureEmulatorBootedAsync(selectedEmulator);
await emulator.installAppAsync(bootedEmulator, appPath);
const { packageName, activityName } = await getAptParametersAsync(appPath);
await emulator.startAppAsync(bootedEmulator, packageName, activityName);
export async function runAppOnAndroidEmulatorAsync(_appPath: string): Promise<void> {
Log.error('Not implemented!');
}
-26
View File
@@ -1,26 +0,0 @@
import { pathExists } from 'fs-extra';
import os from 'os';
import path from 'path';
export const ANDROID_DEFAULT_LOCATION: Readonly<Partial<Record<NodeJS.Platform, string>>> = {
darwin: path.join(os.homedir(), 'Library', 'Android', 'sdk'),
linux: path.join(os.homedir(), 'Android', 'Sdk'),
win32: path.join(os.homedir(), 'AppData', 'Local', 'Android', 'Sdk'),
};
const ANDROID_DEFAULT_LOCATION_FOR_CURRENT_PLATFORM = ANDROID_DEFAULT_LOCATION[process.platform];
export async function getAndroidSdkRootAsync(): Promise<string | null> {
if (process.env.ANDROID_HOME && (await pathExists(process.env.ANDROID_HOME))) {
return process.env.ANDROID_HOME;
} else if (process.env.ANDROID_SDK_ROOT && (await pathExists(process.env.ANDROID_SDK_ROOT))) {
return process.env.ANDROID_SDK_ROOT;
} else if (
ANDROID_DEFAULT_LOCATION_FOR_CURRENT_PLATFORM &&
(await pathExists(ANDROID_DEFAULT_LOCATION_FOR_CURRENT_PLATFORM))
) {
return ANDROID_DEFAULT_LOCATION_FOR_CURRENT_PLATFORM;
} else {
return null;
}
}
@@ -1,27 +0,0 @@
import spawnAsync from '@expo/spawn-async';
import chalk from 'chalk';
import { getAaptExecutableAsync } from './aapt';
import { getAdbExecutableAsync } from './adb';
import { getEmulatorExecutableAsync } from './emulator';
async function assertExecutableExistsAsync(executable: string, options?: string[]): Promise<void> {
try {
await spawnAsync(executable, options);
} catch (err: any) {
throw new Error(
`${chalk.bold(
executable
)} executable doesn't seem to work. Please make sure Android Studio is installed on your device and ${chalk.bold(
'ANDROID_HOME'
)} or ${chalk.bold('ANDROID_SDK_ROOT')} env variables are set.
${err.message}`
);
}
}
export async function assertExecutablesExistAsync(): Promise<void> {
await assertExecutableExistsAsync(await getAdbExecutableAsync(), ['--version']);
await assertExecutableExistsAsync(await getEmulatorExecutableAsync(), ['-list-avds']);
await assertExecutableExistsAsync(await getAaptExecutableAsync(), ['version']);
}
+1 -1
View File
@@ -33,7 +33,7 @@ export async function selectSimulatorAsync(): Promise<IosSimulator> {
message: `Select a simulator to run your app on`,
name: 'selectedSimulator',
choices: simulators.map(simulator => ({
title: `iOS ${simulator.osVersion} ${simulator.name}`,
title: `ios ${simulator.osVersion} ${simulator.name}`,
value: simulator,
})),
});
-19
View File
@@ -1,19 +0,0 @@
import { AppPlatform, BuildFragment, BuildStatus, DistributionType } from '../graphql/generated';
function isAab(build: BuildFragment): boolean {
return build.artifacts?.applicationArchiveUrl?.endsWith('.aab') ?? false;
}
function didArtifactsExpire(build: BuildFragment): boolean {
return new Date().getTime() - new Date(build.updatedAt).getTime() > 30 * 24 * 60 * 60 * 1000; // 30 days
}
export function isRunnableOnSimulatorOrEmulator(build: BuildFragment): boolean {
return (
build.status === BuildStatus.Finished &&
!!build.artifacts?.applicationArchiveUrl &&
((build.platform === AppPlatform.Ios && build.distribution === DistributionType.Simulator) ||
(build.platform === AppPlatform.Android && !isAab(build))) &&
!didArtifactsExpire(build)
);
}
+45 -82
View File
@@ -1,28 +1,23 @@
import spawnAsync from '@expo/spawn-async';
import cliProgress from 'cli-progress';
import glob from 'fast-glob';
import fs from 'fs-extra';
import fs from 'fs';
import path from 'path';
import { Stream } from 'stream';
import { extract } from 'tar';
import { promisify } from 'util';
import { v4 as uuidv4 } from 'uuid';
import fetch, { RequestInit, Response } from '../fetch';
import { AppPlatform } from '../graphql/generated';
import fetch, { RequestInit } from '../fetch';
import Log from '../log';
import { formatBytes } from './files';
import { getTmpDirectory } from './paths';
import { ProgressHandler, createProgressTracker } from './progress';
const pipeline = promisify(Stream.pipeline);
function wrapFetchWithProgress(): (
url: string,
init: RequestInit,
progressHandler: ProgressHandler
) => Promise<Response> {
let didProgressBarFinish = false;
return async (url: string, init: RequestInit, progressHandler: ProgressHandler) => {
type ProgressCallback = (progress: number, total: number, loaded: number) => void;
function wrapFetchWithProgress() {
return async (url: string, init: RequestInit, onProgressCallback: ProgressCallback) => {
const response = await fetch(url, init);
if (response.ok) {
@@ -45,15 +40,7 @@ function wrapFetchWithProgress(): (
const progress = length / total;
if (!didProgressBarFinish) {
progressHandler({
progress: { total, percent: progress, transferred: length },
isComplete: total === length,
});
if (total === length) {
didProgressBarFinish = true;
}
}
onProgressCallback(progress, total, length);
};
response.body.on('data', chunk => {
@@ -69,96 +56,72 @@ function wrapFetchWithProgress(): (
};
}
async function downloadFileWithProgressTrackerAsync(
async function downloadFileWithProgressBarAsync(
url: string,
outputPath: string,
progressTrackerMessage: string | ((ratio: number, total: number) => string),
progressTrackerCompletedMessage: string
infoMessage?: string
): Promise<void> {
Log.newLine();
Log.log(infoMessage ? infoMessage : `Downloading file from ${url}...`);
try {
const response = await wrapFetchWithProgress()(
url,
{
timeout: 1000 * 60 * 5, // 5 minutes
},
createProgressTracker({
message: progressTrackerMessage,
completedMessage: progressTrackerCompletedMessage,
})
);
const downloadProgressBar = new cliProgress.SingleBar(
{ format: '|{bar}|' },
cliProgress.Presets.rect
);
if (!response.ok) {
throw new Error(`Failed to download file from ${url}`);
let downloadProgressBarStarted = false;
const response = await wrapFetchWithProgress()(
url,
{
timeout: 1000 * 60 * 5, // 5 minutes
},
(_progress: number, total: number, loaded: number): void => {
if (!downloadProgressBarStarted) {
downloadProgressBar.start(total, loaded);
downloadProgressBarStarted = true;
} else if (loaded < total) {
downloadProgressBar.update(loaded);
} else {
downloadProgressBar.stop();
}
}
);
await pipeline(response.body, fs.createWriteStream(outputPath));
} catch (error: any) {
if (await fs.pathExists(outputPath)) {
await fs.remove(outputPath);
}
throw error;
if (!response.ok) {
throw new Error(`Failed to download file from ${url}`);
}
await pipeline(response.body, fs.createWriteStream(outputPath));
}
async function maybeCacheAppAsync(appPath: string, cachedAppPath?: string): Promise<string> {
if (cachedAppPath) {
await fs.ensureDir(path.dirname(cachedAppPath));
await fs.move(appPath, cachedAppPath);
return cachedAppPath;
}
return appPath;
}
export async function downloadAndMaybeExtractAppAsync(
export async function downloadAndExtractAppAsync(
url: string,
platform: AppPlatform,
cachedAppPath?: string
applicationExtension: string
): Promise<string> {
const outputDir = path.join(getTmpDirectory(), uuidv4());
await fs.promises.mkdir(outputDir, { recursive: true });
if (url.endsWith('apk')) {
const apkFilePath = path.join(outputDir, `${uuidv4()}.apk`);
await downloadFileWithProgressTrackerAsync(
url,
apkFilePath,
(ratio, total) => `Downloading app (${formatBytes(total * ratio)} / ${formatBytes(total)})`,
'Successfully downloaded app'
);
return maybeCacheAppAsync(apkFilePath, cachedAppPath);
} else {
const tmpArchivePathDir = path.join(getTmpDirectory(), uuidv4());
await fs.mkdir(tmpArchivePathDir, { recursive: true });
const tmpArchivePathDir = path.join(getTmpDirectory(), uuidv4());
await fs.promises.mkdir(tmpArchivePathDir, { recursive: true });
const tmpArchivePath = path.join(tmpArchivePathDir, `${uuidv4()}.tar.gz`);
const tmpArchivePath = path.join(tmpArchivePathDir, `${uuidv4()}.tar.gz`);
await downloadFileWithProgressTrackerAsync(
url,
tmpArchivePath,
(ratio, total) =>
`Downloading app archive (${formatBytes(total * ratio)} / ${formatBytes(total)})`,
'Successfully downloaded app archive'
);
await tarExtractAsync(tmpArchivePath, outputDir);
await downloadFileWithProgressBarAsync(url, tmpArchivePath, 'Downloading app archive...');
await tarExtractAsync(tmpArchivePath, outputDir);
const appPath = await getAppPathAsync(outputDir, platform === AppPlatform.Ios ? 'app' : 'apk');
return maybeCacheAppAsync(appPath, cachedAppPath);
}
return await getAppPathAsync(outputDir, applicationExtension);
}
export async function extractAppFromLocalArchiveAsync(
appArchivePath: string,
platform: AppPlatform
applicationExtension: string
): Promise<string> {
const outputDir = path.join(getTmpDirectory(), uuidv4());
await fs.promises.mkdir(outputDir, { recursive: true });
await tarExtractAsync(appArchivePath, outputDir);
return await getAppPathAsync(outputDir, platform === AppPlatform.Android ? 'apk' : 'app');
return await getAppPathAsync(outputDir, applicationExtension);
}
async function getAppPathAsync(outputDir: string, applicationExtension: string): Promise<string> {
+15 -9
View File
@@ -23,10 +23,7 @@ function dotExpoHomeDirectory(): string {
return dirPath;
}
export const getStateJsonPath = (): string => path.join(dotExpoHomeDirectory(), 'state.json');
export const getEasBuildRunCacheDirectoryPath = (): string =>
path.join(getTmpDirectory(), 'eas-build-run-cache');
const getStateJsonPath = (): string => path.join(dotExpoHomeDirectory(), 'state.json');
// Paths for storing things like data, config, cache, etc.
// Should use the correct OS-specific paths (e.g. XDG base directory on Linux)
@@ -38,8 +35,17 @@ const {
temp: TEMP_PATH,
} = envPaths('eas-cli');
export const getDataDirectory = (): string => DATA_PATH;
export const getConfigDirectory = (): string => CONFIG_PATH;
export const getCacheDirectory = (): string => CACHE_PATH;
export const getLogDirectory = (): string => LOG_PATH;
export const getTmpDirectory = (): string => TEMP_PATH;
const getDataDirectory = (): string => DATA_PATH;
const getConfigDirectory = (): string => CONFIG_PATH;
const getCacheDirectory = (): string => CACHE_PATH;
const getLogDirectory = (): string => LOG_PATH;
const getTmpDirectory = (): string => TEMP_PATH;
export {
getDataDirectory,
getConfigDirectory,
getCacheDirectory,
getLogDirectory,
getTmpDirectory,
getStateJsonPath,
};
+5 -7
View File
@@ -21,7 +21,7 @@ export function createProgressTracker({
completedMessage,
}: {
total?: number;
message: string | ((ratio: number, total: number) => string);
message: string | ((ratio: number) => string);
completedMessage: string | ((duration: string) => string);
}): ProgressHandler {
let bar: Ora | null = null;
@@ -31,19 +31,17 @@ export function createProgressTracker({
const timerLabel = String(Date.now());
const getMessage = (v: number, total: number): string => {
const getMessage = (v: number): string => {
const ratio = Math.min(Math.max(v, 0), 1);
const percent = Math.floor(ratio * 100);
return typeof message === 'string'
? `${message} ${percent.toFixed(0)}%`
: message(ratio, total);
return typeof message === 'string' ? `${message} ${percent.toFixed(0)}%` : message(ratio);
};
return ({ progress, isComplete, error }) => {
if (progress) {
if (!bar && (progress.total !== undefined || total !== undefined)) {
calcTotal = (total ?? progress.total) as number;
bar = ora(getMessage(0, calcTotal)).start();
bar = ora(getMessage(0)).start();
startTimer(timerLabel);
}
if (progress.total) {
@@ -58,7 +56,7 @@ export function createProgressTracker({
percentage = current / calcTotal;
}
bar.text = getMessage(percentage, calcTotal);
bar.text = getMessage(percentage);
}
transferredSoFar = progress.transferred;
}
+1 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@expo/eas-json",
"description": "A library for interacting with eas.json",
"version": "2.8.0",
"version": "2.7.1",
"author": "Expo <[email protected]>",
"bugs": "https://github.com/expo/eas-cli/issues",
"dependencies": {
@@ -14,7 +14,6 @@
"joi": "17.6.4",
"log-symbols": "4.1.0",
"semver": "7.3.8",
"terminal-link": "2.1.1",
"tslib": "2.4.0"
},
"devDependencies": {
-25
View File
@@ -3,33 +3,12 @@ import assert from 'assert';
import chalk from 'chalk';
import fs from 'fs-extra';
import * as fleece from 'golden-fleece';
import { ValidationError } from 'joi';
import path from 'path';
import { InvalidEasJsonError, MissingEasJsonError } from './errors';
import { link } from './log';
import { EasJsonSchema } from './schema';
import { EasJson } from './types';
const customErrorMessageHandlers: ((err: ValidationError) => void)[] = [
// Ask user to upgrade eas-cli version or check the docs when image is invalid.
(err: ValidationError) => {
for (const detail of err.details) {
if (detail.path[detail.path.length - 1] === 'image') {
throw new InvalidEasJsonError(
chalk.red(
`Specified build image '${
detail?.context?.value
}' is not recognized. Please update your EAS CLI and see ${link(
'https://docs.expo.dev/build-reference/infrastructure/'
)} for supported build images.`
)
);
}
}
},
];
export class EasJsonAccessor {
private easJsonPath: string;
@@ -60,10 +39,6 @@ export class EasJsonAccessor {
noDefaults: true,
});
if (error) {
for (const handler of customErrorMessageHandlers) {
handler(error);
}
const errorMessages = error.message.split('. ');
throw new InvalidEasJsonError(
`${chalk.bold('eas.json')} is not valid.\n- ${errorMessages.join('\n- ')}`
-16
View File
@@ -1,16 +0,0 @@
import chalk from 'chalk';
import terminalLink from 'terminal-link';
// link function from packages/eas-cli/src/log.ts
export function link(
url: string,
{ text = url, dim = true }: { text?: string; dim?: boolean } = {}
): string {
let output: string;
if (terminalLink.isSupported) {
output = terminalLink(text, url);
} else {
output = `${text === url ? '' : text + ': '}${chalk.underline(url)}`;
}
return dim ? chalk.dim(output) : output;
}