Compare commits

...
17 Commits
Author SHA1 Message Date
Dominik Sokal 0cc5b74081 v2.1.0 2022-09-05 14:02:46 +02:00
Wojciech Kozyra 6c6f9b079d [eas-cli] resolve paths from root when checking for gitignored values (#1336) 2022-09-05 14:00:26 +02:00
Dominik Sokal 7da0db0237 Update CHANGELOG.md 2022-09-05 13:56:02 +02:00
Dominik SokalandKim Brandwijk 66f916ac02 [ENG-3865] add support for uploading build artifacts (#1321)
* add support for uploading build artifacts

* handle auto-renaming artifactPath -> applicationArchivePath

* update eas.schema.json

* upgrade @expo/eas-build-job

* rename buildArtifactsPaths -> buildArtifactPaths

* Apply suggestions from code review

Co-authored-by: Kim Brandwijk <[email protected]>

* fix ts error

* address PR feedback

Co-authored-by: Kim Brandwijk <[email protected]>
2022-09-05 13:55:07 +02:00
Bartosz Kaszubowski 0e500ec827 [eas-cli] bump oclif help plugin (#1341)
* [eas-cli] bump oclif help plugin

* update CHANGELOG.md

* cleanup changelog
2022-09-05 13:54:26 +02:00
Dominik Sokal 00f1d24aa5 [ENG-6186] add "eas open" command (#1337)
* add "eas open" command

* update CHANGELOG.md
2022-09-05 11:53:56 +02:00
Dominik Sokal b909409c54 Update CHANGELOG.md 2022-09-05 10:28:46 +02:00
HBiedeandKim Brandwijk d18d7a6e21 Fix typos (#1340)
* Fix typos

* Revert “re-authentication”

Co-authored-by: Kim Brandwijk <[email protected]>

Co-authored-by: Kim Brandwijk <[email protected]>
2022-09-05 10:25:14 +02:00
Quinlan Jung 0131cdbf4b [ENG-6070][cli] generate tvOS credentials for adhoc and prod (#1325)
* [cli] generate tvOS credentials for adhoc and prod

* update CHANGELOG.md

* pr feedback: dsokal

* pr feedback: wojtek

* fix tsc

* tricky mocks
2022-09-02 00:45:09 +02:00
Will Schurman 114190c52e [eas-cli] Add noImplicitOverride to tsconfigs (#1327) 2022-09-01 09:23:08 -07:00
HBiede a06352d150 [eas-cli] Fix viewing branch list when a branch has no associated platforms (#1326) 2022-09-01 09:12:22 -07:00
Expo CI 1969eea8a7 update CHANGELOG.md 2022-09-01 11:40:30 +00:00
Dominik Sokal 8c758fa413 v2.0.0 2022-09-01 13:30:03 +02:00
Dominik Sokal 4b2fb24d1d Update CHANGELOG.md 2022-09-01 13:24:46 +02:00
Dominik Sokal 1637573d72 fix typo in promptToConfigurePushNotifications (#1332)
* fix typo in promptToConfigurePushNotifications

* address PR feedback
2022-09-01 13:20:18 +02:00
Will Schurman 367477f75b [eas-cli] Fix dynamic config update warning for update:configure (#1322) 2022-08-31 14:24:40 -07:00
Expo CI f5d44a08ec update CHANGELOG.md 2022-08-29 09:58:55 +00:00
105 changed files with 1371 additions and 388 deletions

No files matched your search

+29
View File
@@ -8,6 +8,35 @@ This is the log of notable changes to EAS CLI and related packages.
### 🎉 New features
- Add tvOS credentials compatibility for Adhoc and App store builds. ([#1325](https://github.com/expo/eas-cli/pull/1325) by [@quinlanj](https://github.com/quinlanj))
- Add `eas open` command for opening project page in web browser. ([#1337](https://github.com/expo/eas-cli/pull/1337) by [@dsokal](https://github.com/dsokal))
- Add support for buildArtifactPaths. Rename artifactPath to applicationArchivePath. ([#1321](https://github.com/expo/eas-cli/pull/1321) by [@dsokal](https://github.com/dsokal))
### 🐛 Bug fixes
- Fix viewing branch list when a branch has no associated platforms. ([#1326](https://github.com/expo/eas-cli/pull/1326) by [@hbiede](https://github.com/hbiede))
- Fix description of `help` command in help prompt. ([#1341](https://github.com/expo/eas-cli/pull/1341) by [@Simek](https://github.com/Simek))
- Resolve paths from the root when checking for gitignored values. ([#1336](https://github.com/expo/eas-cli/pull/1336) by [@wkozyra95](https://github.com/wkozyra95))
### 🧹 Chores
- Add noImplicitOverride to tsconfigs. ([#1327](https://github.com/expo/eas-cli/pull/1327) by [@wschurman](https://github.com/wschurman))
- Fix typos. ([#1340](https://github.com/expo/eas-cli/pull/1340) by [@hbiede](https://github.com/hbiede))
## [2.0.0](https://github.com/expo/eas-cli/releases/tag/v2.0.0) - 2022-09-01
### 🛠 Breaking changes
- Fix typo in `cli.promptToConfigurePushNotifications` field in **eas.json**. EAS CLI will throw an error if the old field name is in **eas.json**. ([#1332](https://github.com/expo/eas-cli/pull/1332) by [@dsokal](https://github.com/dsokal))
### 🐛 Bug fixes
- Fix dynamic config update warning. ([#1322](https://github.com/expo/eas-cli/pull/1322) by [@wschurman](https://github.com/wschurman))
## [1.2.0](https://github.com/expo/eas-cli/releases/tag/v1.2.0) - 2022-08-29
### 🎉 New features
- Add 2022 Apple capabilities. ([#1307](https://github.com/expo/eas-cli/pull/1307) by [@EvanBacon](https://github.com/EvanBacon))
- Print warning when eas-cli is installed as project dependency. ([#1310](https://github.com/expo/eas-cli/pull/1310) by [@dsokal](https://github.com/dsokal))
- Add eas.json to skip push notifications credentials setup. ([#1315](https://github.com/expo/eas-cli/pull/1315) by [@dsokal](https://github.com/dsokal))
+1 -1
View File
@@ -1,5 +1,5 @@
{
"npmClient": "yarn",
"useWorkspaces": true,
"version": "1.2.0"
"version": "2.1.0"
}
+65 -50
View File
@@ -32,7 +32,7 @@ An example of **eas.json** that enforces `eas-cli` in version `1.0.0` or newer:
},
"build": {
// build profiles
}
},
"submit": {
// submit profiles
}
@@ -91,6 +91,7 @@ eas --help COMMAND
* [`eas logout`](#eas-logout)
* [`eas metadata:pull`](#eas-metadatapull)
* [`eas metadata:push`](#eas-metadatapush)
* [`eas open`](#eas-open)
* [`eas project:info`](#eas-projectinfo)
* [`eas project:init`](#eas-projectinit)
* [`eas secret:create`](#eas-secretcreate)
@@ -124,7 +125,7 @@ ALIASES
$ eas login
```
_See code: [src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/account/login.ts)_
_See code: [src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/account/login.ts)_
## `eas account:logout`
@@ -141,7 +142,7 @@ ALIASES
$ eas logout
```
_See code: [src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/account/logout.ts)_
_See code: [src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/account/logout.ts)_
## `eas account:view`
@@ -158,7 +159,7 @@ ALIASES
$ eas whoami
```
_See code: [src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/account/view.ts)_
_See code: [src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/account/view.ts)_
## `eas analytics [STATUS]`
@@ -172,7 +173,7 @@ DESCRIPTION
display or change analytics settings
```
_See code: [src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/analytics.ts)_
_See code: [src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/analytics.ts)_
## `eas autocomplete [SHELL]`
@@ -221,7 +222,7 @@ DESCRIPTION
create a branch
```
_See code: [src/commands/branch/create.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/branch/create.ts)_
_See code: [src/commands/branch/create.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/branch/create.ts)_
## `eas branch:delete [NAME]`
@@ -241,7 +242,7 @@ DESCRIPTION
delete a branch
```
_See code: [src/commands/branch/delete.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/branch/delete.ts)_
_See code: [src/commands/branch/delete.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/branch/delete.ts)_
## `eas branch:list`
@@ -262,7 +263,7 @@ DESCRIPTION
list all branches
```
_See code: [src/commands/branch/list.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/branch/list.ts)_
_See code: [src/commands/branch/list.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/branch/list.ts)_
## `eas branch:rename`
@@ -281,7 +282,7 @@ DESCRIPTION
rename a branch
```
_See code: [src/commands/branch/rename.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/branch/rename.ts)_
_See code: [src/commands/branch/rename.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/branch/rename.ts)_
## `eas branch:view [NAME]`
@@ -305,7 +306,7 @@ DESCRIPTION
view a branch
```
_See code: [src/commands/branch/view.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/branch/view.ts)_
_See code: [src/commands/branch/view.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/branch/view.ts)_
## `eas build`
@@ -335,7 +336,7 @@ DESCRIPTION
start a build
```
_See code: [src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/build/index.ts)_
_See code: [src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/build/index.ts)_
## `eas build:cancel [BUILD_ID]`
@@ -349,7 +350,7 @@ DESCRIPTION
cancel a build
```
_See code: [src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/build/cancel.ts)_
_See code: [src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/build/cancel.ts)_
## `eas build:configure`
@@ -366,7 +367,7 @@ DESCRIPTION
configure the project to support EAS Build
```
_See code: [src/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/build/configure.ts)_
_See code: [src/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/build/configure.ts)_
## `eas build:inspect`
@@ -401,7 +402,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/v1.2.0/packages/eas-cli/src/commands/build/inspect.ts)_
_See code: [src/commands/build/inspect.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/build/inspect.ts)_
## `eas build:list`
@@ -434,7 +435,7 @@ DESCRIPTION
list all builds for your project
```
_See code: [src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/build/list.ts)_
_See code: [src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/build/list.ts)_
## `eas build:submit`
@@ -481,7 +482,7 @@ DESCRIPTION
Update version of an app.
```
_See code: [src/commands/build/version/set.ts](https://github.com/expo/eas-cli/blob/v1.2.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.1.0/packages/eas-cli/src/commands/build/version/set.ts)_
## `eas build:version:sync`
@@ -500,7 +501,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/v1.2.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.1.0/packages/eas-cli/src/commands/build/version/sync.ts)_
## `eas build:view [BUILD_ID]`
@@ -517,7 +518,7 @@ DESCRIPTION
view a build for your project
```
_See code: [src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/build/view.ts)_
_See code: [src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/build/view.ts)_
## `eas channel:create [NAME]`
@@ -537,7 +538,7 @@ DESCRIPTION
create a channel
```
_See code: [src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/channel/create.ts)_
_See code: [src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/channel/create.ts)_
## `eas channel:edit [NAME]`
@@ -558,7 +559,7 @@ DESCRIPTION
point a channel at a new branch
```
_See code: [src/commands/channel/edit.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/channel/edit.ts)_
_See code: [src/commands/channel/edit.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/channel/edit.ts)_
## `eas channel:list`
@@ -575,7 +576,7 @@ DESCRIPTION
list all channels
```
_See code: [src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/channel/list.ts)_
_See code: [src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/channel/list.ts)_
## `eas channel:view [NAME]`
@@ -595,7 +596,7 @@ DESCRIPTION
view a channel
```
_See code: [src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/channel/view.ts)_
_See code: [src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/channel/view.ts)_
## `eas config`
@@ -613,7 +614,7 @@ DESCRIPTION
display project configuration (app.json + eas.json)
```
_See code: [src/commands/config.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/config.ts)_
_See code: [src/commands/config.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/config.ts)_
## `eas credentials`
@@ -630,7 +631,7 @@ DESCRIPTION
manage credentials
```
_See code: [src/commands/credentials.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/credentials.ts)_
_See code: [src/commands/credentials.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/credentials.ts)_
## `eas device:create`
@@ -644,7 +645,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/v1.2.0/packages/eas-cli/src/commands/device/create.ts)_
_See code: [src/commands/device/create.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/device/create.ts)_
## `eas device:delete`
@@ -662,7 +663,7 @@ DESCRIPTION
remove a registered device from your account
```
_See code: [src/commands/device/delete.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/device/delete.ts)_
_See code: [src/commands/device/delete.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/device/delete.ts)_
## `eas device:list`
@@ -679,7 +680,7 @@ DESCRIPTION
list all registered devices for your account
```
_See code: [src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/device/list.ts)_
_See code: [src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/device/list.ts)_
## `eas device:view [UDID]`
@@ -693,7 +694,7 @@ DESCRIPTION
view a device for your project
```
_See code: [src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/device/view.ts)_
_See code: [src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/device/view.ts)_
## `eas diagnostics`
@@ -707,11 +708,11 @@ DESCRIPTION
display environment info
```
_See code: [src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/diagnostics.ts)_
_See code: [src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/diagnostics.ts)_
## `eas help [COMMAND]`
Display help for eas.
display help for eas-cli
```
USAGE
@@ -724,10 +725,10 @@ FLAGS
-n, --nested-commands Include all nested commands in the output.
DESCRIPTION
Display help for eas.
display help for eas-cli
```
_See code: [@expo/plugin-help](https://github.com/expo/oclif-plugin-help/blob/v5.2.0/src/commands/help.ts)_
_See code: [@expo/plugin-help](https://github.com/expo/oclif-plugin-help/blob/v5.3.0/src/commands/help.ts)_
## `eas init`
@@ -789,7 +790,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/v1.2.0/packages/eas-cli/src/commands/metadata/pull.ts)_
_See code: [src/commands/metadata/pull.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/metadata/pull.ts)_
## `eas metadata:push`
@@ -806,7 +807,21 @@ DESCRIPTION
sync the local store configuration to the app stores
```
_See code: [src/commands/metadata/push.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/metadata/push.ts)_
_See code: [src/commands/metadata/push.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/metadata/push.ts)_
## `eas open`
open the project page in a web browser
```
USAGE
$ eas open
DESCRIPTION
open the project page in a web browser
```
_See code: [src/commands/open.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/open.ts)_
## `eas project:info`
@@ -820,7 +835,7 @@ DESCRIPTION
information about the current project
```
_See code: [src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/project/info.ts)_
_See code: [src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/project/info.ts)_
## `eas project:init`
@@ -837,7 +852,7 @@ ALIASES
$ eas init
```
_See code: [src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/project/init.ts)_
_See code: [src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/project/init.ts)_
## `eas secret:create`
@@ -857,7 +872,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/v1.2.0/packages/eas-cli/src/commands/secret/create.ts)_
_See code: [src/commands/secret/create.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/secret/create.ts)_
## `eas secret:delete`
@@ -874,7 +889,7 @@ DESCRIPTION
delete an environment secret by ID
```
_See code: [src/commands/secret/delete.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/secret/delete.ts)_
_See code: [src/commands/secret/delete.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/secret/delete.ts)_
## `eas secret:list`
@@ -888,7 +903,7 @@ DESCRIPTION
list environment secrets available for your current app
```
_See code: [src/commands/secret/list.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/secret/list.ts)_
_See code: [src/commands/secret/list.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/secret/list.ts)_
## `eas submit`
@@ -918,7 +933,7 @@ ALIASES
$ eas build:submit
```
_See code: [src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/submit.ts)_
_See code: [src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/submit.ts)_
## `eas update`
@@ -948,7 +963,7 @@ DESCRIPTION
publish an update group
```
_See code: [src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/update/index.ts)_
_See code: [src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/update/index.ts)_
## `eas update:configure`
@@ -965,7 +980,7 @@ DESCRIPTION
configure the project to support EAS Update
```
_See code: [src/commands/update/configure.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/update/configure.ts)_
_See code: [src/commands/update/configure.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/update/configure.ts)_
## `eas update:delete GROUPID`
@@ -985,7 +1000,7 @@ DESCRIPTION
delete all the updates in an update group
```
_See code: [src/commands/update/delete.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/update/delete.ts)_
_See code: [src/commands/update/delete.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/update/delete.ts)_
## `eas update:list`
@@ -1004,7 +1019,7 @@ DESCRIPTION
view the recent updates for a branch
```
_See code: [src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/update/list.ts)_
_See code: [src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/update/list.ts)_
## `eas update:view GROUPID`
@@ -1024,7 +1039,7 @@ DESCRIPTION
update group details
```
_See code: [src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/update/view.ts)_
_See code: [src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/update/view.ts)_
## `eas webhook:create`
@@ -1044,7 +1059,7 @@ DESCRIPTION
create a webhook
```
_See code: [src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/webhook/create.ts)_
_See code: [src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/webhook/create.ts)_
## `eas webhook:delete [ID]`
@@ -1061,7 +1076,7 @@ DESCRIPTION
delete a webhook
```
_See code: [src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/webhook/delete.ts)_
_See code: [src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/webhook/delete.ts)_
## `eas webhook:list`
@@ -1078,7 +1093,7 @@ DESCRIPTION
list webhooks
```
_See code: [src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/webhook/list.ts)_
_See code: [src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/webhook/list.ts)_
## `eas webhook:update`
@@ -1099,7 +1114,7 @@ DESCRIPTION
update a webhook
```
_See code: [src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/webhook/update.ts)_
_See code: [src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/webhook/update.ts)_
## `eas webhook:view ID`
@@ -1116,7 +1131,7 @@ DESCRIPTION
view a webhook
```
_See code: [src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v1.2.0/packages/eas-cli/src/commands/webhook/view.ts)_
_See code: [src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v2.1.0/packages/eas-cli/src/commands/webhook/view.ts)_
## `eas whoami`
+418 -4
View File
@@ -4995,7 +4995,7 @@
"fields": null,
"inputFields": [
{
"name": "artifactPath",
"name": "applicationArchivePath",
"description": "",
"type": {
"kind": "SCALAR",
@@ -5006,6 +5006,38 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "artifactPath",
"description": "@deprecated",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "buildArtifactPaths",
"description": "",
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "buildType",
"description": "",
@@ -5269,7 +5301,7 @@
"fields": null,
"inputFields": [
{
"name": "artifactPath",
"name": "applicationArchivePath",
"description": "",
"type": {
"kind": "SCALAR",
@@ -5280,6 +5312,38 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "artifactPath",
"description": "@deprecated",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "buildArtifactPaths",
"description": "",
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "buildType",
"description": "",
@@ -6062,6 +6126,26 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "filterChannels",
"description": "",
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "filterPlatforms",
"description": "",
@@ -7439,6 +7523,83 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "updateGroups",
"description": "EAS updates owned by an app grouped by update group",
"args": [
{
"name": "filter",
"description": "",
"type": {
"kind": "INPUT_OBJECT",
"name": "UpdatesFilter",
"ofType": null
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "limit",
"description": "",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
}
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "offset",
"description": "",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
}
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
}
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "Update",
"ofType": null
}
}
}
}
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "updated",
"description": "Time of last classic update publish",
@@ -12373,6 +12534,30 @@
"name": "BuildArtifacts",
"description": "",
"fields": [
{
"name": "applicationArchiveUrl",
"description": "",
"args": [],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "buildArtifactsUrl",
"description": "",
"args": [],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "buildUrl",
"description": "",
@@ -15834,6 +16019,33 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "DeployServerlessFunctionResult",
"description": "",
"fields": [
{
"name": "url",
"description": "",
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "Deployment",
@@ -18850,7 +19062,7 @@
"fields": null,
"inputFields": [
{
"name": "artifactPath",
"name": "applicationArchivePath",
"description": "",
"type": {
"kind": "SCALAR",
@@ -18861,6 +19073,38 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "artifactPath",
"description": "@deprecated",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "buildArtifactPaths",
"description": "",
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "buildConfiguration",
"description": "",
@@ -19089,7 +19333,7 @@
"fields": null,
"inputFields": [
{
"name": "artifactPath",
"name": "applicationArchivePath",
"description": "",
"type": {
"kind": "SCALAR",
@@ -19100,6 +19344,38 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "artifactPath",
"description": "@deprecated",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "buildArtifactPaths",
"description": "",
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
}
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "buildConfiguration",
"description": "",
@@ -21360,6 +21636,18 @@
"name": "PublicArtifacts",
"description": "",
"fields": [
{
"name": "applicationArchiveUrl",
"description": "",
"args": [],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "buildUrl",
"description": "",
@@ -23473,6 +23761,55 @@
"name": "ServerlessFunctionMutation",
"description": "",
"fields": [
{
"name": "createDeployment",
"description": "",
"args": [
{
"name": "appId",
"description": "",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "serverlessFunctionIdentifierInput",
"description": "",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "INPUT_OBJECT",
"name": "ServerlessFunctionIdentifierInput",
"ofType": null
}
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
}
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "DeployServerlessFunctionResult",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "createUploadPresignedUrl",
"description": "",
@@ -25760,6 +26097,83 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "updateGroups",
"description": "",
"args": [
{
"name": "filter",
"description": "",
"type": {
"kind": "INPUT_OBJECT",
"name": "UpdatesFilter",
"ofType": null
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "limit",
"description": "",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
}
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "offset",
"description": "",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
}
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
}
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "Update",
"ofType": null
}
}
}
}
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "updatedAt",
"description": "",
+5 -4
View File
@@ -1,7 +1,7 @@
{
"name": "eas-cli",
"description": "EAS command line tool",
"version": "1.2.0",
"version": "2.1.0",
"author": "Expo <[email protected]>",
"bin": {
"eas": "./bin/run"
@@ -13,15 +13,15 @@
"@expo/config": "7.0.1",
"@expo/config-plugins": "5.0.1",
"@expo/config-types": "46.0.2",
"@expo/eas-build-job": "0.2.85",
"@expo/eas-json": "1.2.0",
"@expo/eas-build-job": "0.2.90",
"@expo/eas-json": "2.1.0",
"@expo/json-file": "8.2.36",
"@expo/multipart-body-parser": "1.1.0",
"@expo/package-manager": "0.0.56",
"@expo/pkcs12": "0.0.8",
"@expo/plist": "0.0.18",
"@expo/plugin-autocomplete": "1.4.0",
"@expo/plugin-help": "5.2.0",
"@expo/plugin-help": "5.3.0",
"@expo/plugin-warn-if-update-available": "2.3.0",
"@expo/prebuild-config": "5.0.3",
"@expo/results": "1.0.0",
@@ -32,6 +32,7 @@
"@urql/core": "2.6.1",
"@urql/exchange-retry": "0.3.3",
"ajv": "^6.12.6",
"better-opn": "3.0.2",
"chalk": "4.1.2",
"cli-progress": "3.11.2",
"cli-table3": "0.6.2",
+1 -1
View File
@@ -4,7 +4,7 @@ import fetch, { RequestError, RequestInit } from './fetch';
import { getAccessToken, getSessionSecret } from './user/sessionStorage';
export class ApiV2Error extends Error {
readonly name = 'ApiV2Error';
override readonly name = 'ApiV2Error';
readonly expoApiV2ErrorCode: string;
readonly expoApiV2ErrorDetails?: JSONValue;
readonly expoApiV2ErrorServerStack?: string;
+15 -10
View File
@@ -89,16 +89,21 @@ function renderPageOfBranches(
});
table.push(
...currentPage.map(branch => [
branch.name,
formatUpdate(branch.updates[0]),
branch.updates[0]?.runtimeVersion ?? 'N/A',
branch.updates[0]?.group ?? 'N/A',
getPlatformsForGroup({
updates: branch.updates,
group: branch.updates[0]?.group,
}),
])
...currentPage.map(branch => {
const update: UpdateBranchFragment['updates'][0] | undefined = branch.updates[0];
return [
branch.name,
formatUpdate(update),
update?.runtimeVersion ?? 'N/A',
update?.group ?? 'N/A',
update?.group
? getPlatformsForGroup({
updates: branch.updates,
group: update.group,
})
: 'N/A',
];
})
);
Log.addNewLineIfNone();
@@ -73,17 +73,17 @@ describe(bumpVersionAsync, () => {
await bumpVersionAsync({
bumpStrategy: BumpStrategy.VERSION_CODE,
projectDir: '/repo',
projectDir: '/app',
exp: fakeExp,
});
const appJSON = await fs.readJSON('/repo/app.json');
const appJSON = await fs.readJSON('/app/app.json');
expect(fakeExp.version).toBe('3.0.0');
expect(fakeExp.android?.versionCode).toBe(124);
expect(appJSON.expo.version).toBe('3.0.0');
expect(appJSON.expo.android.versionCode).toBe(124);
const buildGradle = await getAppBuildGradleAsync('/repo');
const buildGradle = await getAppBuildGradleAsync('/app');
assert(buildGradle);
expect(resolveConfigValue(buildGradle, 'versionCode')).toBe('124');
expect(resolveConfigValue(buildGradle, 'versionName')).toBe('3.0.0');
@@ -95,17 +95,17 @@ describe(bumpVersionAsync, () => {
await bumpVersionAsync({
bumpStrategy: BumpStrategy.APP_VERSION,
projectDir: '/repo',
projectDir: '/app',
exp: fakeExp,
});
const appJSON = await fs.readJSON('/repo/app.json');
const appJSON = await fs.readJSON('/app/app.json');
expect(fakeExp.version).toBe('3.0.1');
expect(fakeExp.android?.versionCode).toBe(123);
expect(appJSON.expo.version).toBe('3.0.1');
expect(appJSON.expo.android.versionCode).toBe(123);
const buildGradle = await getAppBuildGradleAsync('/repo');
const buildGradle = await getAppBuildGradleAsync('/app');
assert(buildGradle);
expect(resolveConfigValue(buildGradle, 'versionCode')).toBe('123');
expect(resolveConfigValue(buildGradle, 'versionName')).toBe('3.0.1');
@@ -116,17 +116,17 @@ describe(bumpVersionAsync, () => {
await bumpVersionAsync({
bumpStrategy: BumpStrategy.NOOP,
projectDir: '/repo',
projectDir: '/app',
exp: fakeExp,
});
const appJSON = await fs.readJSON('/repo/app.json');
const appJSON = await fs.readJSON('/app/app.json');
expect(fakeExp.version).toBe('3.0.0');
expect(fakeExp.android?.versionCode).toBe(123);
expect(appJSON.expo.version).toBe('3.0.0');
expect(appJSON.expo.android.versionCode).toBe(123);
const buildGradle = await getAppBuildGradleAsync('/repo');
const buildGradle = await getAppBuildGradleAsync('/app');
assert(buildGradle);
expect(resolveConfigValue(buildGradle, 'versionCode')).toBe('123');
expect(resolveConfigValue(buildGradle, 'versionName')).toBe('3.0.0');
@@ -140,11 +140,11 @@ describe(bumpVersionInAppJsonAsync, () => {
await bumpVersionInAppJsonAsync({
bumpStrategy: BumpStrategy.VERSION_CODE,
projectDir: '/repo',
projectDir: '/app',
exp: fakeExp,
});
const appJSON = await fs.readJSON('/repo/app.json');
const appJSON = await fs.readJSON('/app/app.json');
expect(fakeExp.version).toBe('5.0.0');
expect(fakeExp.android?.versionCode).toBe(127);
expect(appJSON.expo.version).toBe('5.0.0');
@@ -156,11 +156,11 @@ describe(bumpVersionInAppJsonAsync, () => {
await bumpVersionInAppJsonAsync({
bumpStrategy: BumpStrategy.APP_VERSION,
projectDir: '/repo',
projectDir: '/app',
exp: fakeExp,
});
const appJSON = await fs.readJSON('/repo/app.json');
const appJSON = await fs.readJSON('/app/app.json');
expect(fakeExp.version).toBe('5.0.1');
expect(fakeExp.android?.versionCode).toBe(126);
expect(appJSON.expo.version).toBe('5.0.1');
@@ -172,11 +172,11 @@ describe(bumpVersionInAppJsonAsync, () => {
await bumpVersionInAppJsonAsync({
bumpStrategy: BumpStrategy.NOOP,
projectDir: '/repo',
projectDir: '/app',
exp: fakeExp,
});
const appJSON = await fs.readJSON('/repo/app.json');
const appJSON = await fs.readJSON('/app/app.json');
expect(fakeExp.version).toBe('5.0.0');
expect(fakeExp.android?.versionCode).toBe(126);
expect(appJSON.expo.version).toBe('5.0.0');
@@ -189,7 +189,7 @@ describe(maybeResolveVersionsAsync, () => {
it('reads the versions from native code', async () => {
const exp = initBareWorkflowProject();
const { appVersion, appBuildVersion } = await maybeResolveVersionsAsync(
'/repo',
'/app',
exp,
{} as BuildProfile<Platform.ANDROID>
);
@@ -201,7 +201,7 @@ describe(maybeResolveVersionsAsync, () => {
it('reads the versions from expo config', async () => {
const exp = initManagedProject();
const { appVersion, appBuildVersion } = await maybeResolveVersionsAsync(
'/repo',
'/app',
exp,
{} as BuildProfile<Platform.ANDROID>
);
@@ -240,7 +240,7 @@ function initBareWorkflowProject({
}`,
'./android/app/src/main/AndroidManifest.xml': 'fake',
},
'/repo'
'/app'
);
return fakeExp;
@@ -261,7 +261,7 @@ function initManagedProject(): ExpoConfig {
expo: fakeExp,
}),
},
'/repo'
'/app'
);
return fakeExp;
@@ -15,7 +15,8 @@ export function transformJob(job: Android.Job): AndroidJobInput {
cache: job.cache,
version: job.version?.versionCode ? { versionCode: job.version.versionCode } : undefined,
gradleCommand: job.gradleCommand,
artifactPath: job.artifactPath,
applicationArchivePath: job.applicationArchivePath,
buildArtifactPaths: job.buildArtifactPaths,
username: job.username,
buildType: job.buildType && transformBuildType(job.buildType),
developmentClient: job.developmentClient,
@@ -72,7 +72,8 @@ export async function prepareJobAsync(
updates: { channel: ctx.buildProfile.channel },
developmentClient: buildProfile.developmentClient,
gradleCommand: buildProfile.gradleCommand,
artifactPath: buildProfile.artifactPath,
applicationArchivePath: buildProfile.applicationArchivePath ?? buildProfile.artifactPath,
buildArtifactPaths: buildProfile.buildArtifactPaths,
buildType,
username,
...(ctx.android.versionCodeOverride && {
+2 -1
View File
@@ -17,7 +17,8 @@ export function transformJob(job: Ios.Job): IosJobInput {
version: job.version?.buildNumber ? { buildNumber: job.version.buildNumber } : undefined,
scheme: job.scheme,
buildConfiguration: job.buildConfiguration,
artifactPath: job.artifactPath,
applicationArchivePath: job.applicationArchivePath,
buildArtifactPaths: job.buildArtifactPaths,
username: job.username,
developmentClient: job.developmentClient,
simulator: job.simulator,
+3 -1
View File
@@ -64,7 +64,9 @@ export async function prepareJobAsync(
simulator: ctx.buildProfile.simulator,
scheme: jobData.buildScheme,
buildConfiguration: ctx.buildProfile.buildConfiguration,
artifactPath: ctx.buildProfile.artifactPath,
applicationArchivePath:
ctx.buildProfile.applicationArchivePath ?? ctx.buildProfile.artifactPath,
buildArtifactPaths: ctx.buildProfile.buildArtifactPaths,
username,
...(ctx.ios.buildNumberOverride && {
version: {
@@ -56,7 +56,7 @@ export default abstract class EasCommand extends Command {
}
// eslint-disable-next-line async-protect/async-suffix
async finally(err: Error): Promise<any> {
override async finally(err: Error): Promise<any> {
await flushAnalyticsAsync();
return super.finally(err);
}
@@ -43,7 +43,7 @@ beforeEach(() => {
const createTestEasCommand = (authValue: boolean): typeof EasCommand => {
class TestEasCommand extends EasCommand {
requiresAuthentication = authValue;
override requiresAuthentication = authValue;
async runAsync(): Promise<void> {}
}
@@ -3,11 +3,11 @@ import Log from '../../log';
import { showLoginPromptAsync } from '../../user/actions';
export default class AccountLogin extends EasCommand {
static description = 'log in with your Expo account';
static aliases = ['login'];
static override description = 'log in with your Expo account';
static override aliases = ['login'];
protected mustBeRunInsideProject = false;
protected requiresAuthentication = false;
protected override mustBeRunInsideProject = false;
protected override requiresAuthentication = false;
async runAsync(): Promise<void> {
await showLoginPromptAsync();
@@ -3,11 +3,11 @@ import Log from '../../log';
import { logoutAsync } from '../../user/User';
export default class AccountLogout extends EasCommand {
static description = 'log out';
static aliases = ['logout'];
static override description = 'log out';
static override aliases = ['logout'];
protected mustBeRunInsideProject = false;
protected requiresAuthentication = false;
protected override mustBeRunInsideProject = false;
protected override requiresAuthentication = false;
async runAsync(): Promise<void> {
await logoutAsync();
@@ -5,11 +5,11 @@ import Log from '../../log';
import { getActorDisplayName, getUserAsync } from '../../user/User';
export default class AccountView extends EasCommand {
static description = 'show the username you are logged in as';
static aliases = ['whoami'];
static override description = 'show the username you are logged in as';
static override aliases = ['whoami'];
protected mustBeRunInsideProject = false;
protected requiresAuthentication = false;
protected override mustBeRunInsideProject = false;
protected override requiresAuthentication = false;
async runAsync(): Promise<void> {
const user = await getUserAsync();
+3 -3
View File
@@ -3,11 +3,11 @@ import Log from '../log';
import UserSettings from '../user/UserSettings';
export default class AnalyticsView extends EasCommand {
static description = 'display or change analytics settings';
static override description = 'display or change analytics settings';
static args = [{ name: 'STATUS', options: ['on', 'off'] }];
static override args = [{ name: 'STATUS', options: ['on', 'off'] }];
protected requiresAuthentication = false;
protected override requiresAuthentication = false;
async runAsync(): Promise<void> {
const { STATUS: status } = (await this.parse(AnalyticsView)).args;
@@ -52,9 +52,9 @@ export async function createUpdateBranchOnAppAsync({
}
export default class BranchCreate extends EasCommand {
static description = 'create a branch';
static override description = 'create a branch';
static args = [
static override args = [
{
name: 'name',
required: false,
@@ -62,7 +62,7 @@ export default class BranchCreate extends EasCommand {
},
];
static flags = {
static override flags = {
json: Flags.boolean({
description: 'return a json with the new branch ID and name.',
default: false,
@@ -77,16 +77,16 @@ async function deleteBranchOnAppAsync({
}
export default class BranchDelete extends EasCommand {
static description = 'delete a branch';
static override description = 'delete a branch';
static args = [
static override args = [
{
name: 'name',
required: false,
description: 'Name of the branch to delete',
},
];
static flags = {
static override flags = {
json: Flags.boolean({
description: `return JSON with the edited branch's ID and name.`,
default: false,
@@ -129,7 +129,7 @@ export default class BranchDelete extends EasCommand {
if (!jsonFlag) {
Log.addNewLineIfNone();
Log.warn(
`You are about to permamently delete branch: "${name}" and all of the updates published on it.` +
`You are about to permanently delete branch: "${name}" and all of the updates published on it.` +
`\nThis action is irreversible.`
);
Log.newLine();
+2 -2
View File
@@ -6,9 +6,9 @@ import { findProjectRootAsync, getProjectIdAsync } from '../../project/projectUt
import { enableJsonOutput } from '../../utils/json';
export default class BranchList extends EasCommand {
static description = 'list all branches';
static override description = 'list all branches';
static flags = {
static override flags = {
...EasPaginatedQueryFlags,
};
@@ -1,8 +1,8 @@
import EasCommand from '../../commandUtils/EasCommand';
export default class BranchPublish extends EasCommand {
static description = 'deprecated, use "eas update"';
static hidden = true;
static override description = 'deprecated, use "eas update"';
static override hidden = true;
async runAsync(): Promise<void> {
throw new Error(BranchPublish.description);
@@ -52,9 +52,9 @@ async function renameUpdateBranchOnAppAsync({
}
export default class BranchRename extends EasCommand {
static description = 'rename a branch';
static override description = 'rename a branch';
static flags = {
static override flags = {
from: Flags.string({
description: 'current name of the branch.',
required: false,
+3 -3
View File
@@ -7,9 +7,9 @@ import { listAndRenderUpdatesOnBranchByNameAsync } from '../../update/queries';
import { enableJsonOutput } from '../../utils/json';
export default class BranchView extends EasCommand {
static description = 'view a branch';
static override description = 'view a branch';
static args = [
static override args = [
{
name: 'name',
required: false,
@@ -17,7 +17,7 @@ export default class BranchView extends EasCommand {
},
];
static flags = {
static override flags = {
...EasPaginatedQueryFlags,
};
@@ -110,9 +110,9 @@ async function ensureBuildExistsAsync(buildId: string): Promise<void> {
}
export default class BuildCancel extends EasCommand {
static description = 'cancel a build';
static override description = 'cancel a build';
static args = [{ name: 'BUILD_ID' }];
static override args = [{ name: 'BUILD_ID' }];
async runAsync(): Promise<void> {
const { BUILD_ID: buildIdFromArg } = (await this.parse(BuildCancel)).args;
@@ -16,9 +16,9 @@ import { syncUpdatesConfigurationAsync as syncIosUpdatesConfigurationAsync } fro
import { getVcsClient } from '../../vcs';
export default class BuildConfigure extends EasCommand {
static description = 'configure the project to support EAS Build';
static override description = 'configure the project to support EAS Build';
static flags = {
static override flags = {
platform: Flags.enum({
description: 'Platform to configure',
char: 'p',
+82 -3
View File
@@ -1,13 +1,20 @@
import { Platform } from '@expo/eas-build-job';
import { EasJsonReader } from '@expo/eas-json';
import { Errors, Flags } from '@oclif/core';
import chalk from 'chalk';
import figures from 'figures';
import fs from 'fs-extra';
import path from 'path';
import { BuildFlags, runBuildAndSubmitAsync } from '../../build/runBuildAndSubmit';
import { UserInputResourceClass } from '../../build/types';
import EasCommand from '../../commandUtils/EasCommand';
import { StatuspageServiceName } from '../../graphql/generated';
import Log from '../../log';
import Log, { link } from '../../log';
import { RequestedPlatform, selectRequestedPlatformAsync } from '../../platform';
import { findProjectRootAsync } from '../../project/projectUtils';
import { selectAsync } from '../../prompts';
import uniq from '../../utils/expodash/uniq';
import { enableJsonOutput } from '../../utils/json';
import { maybeWarnAboutEasOutagesAsync } from '../../utils/statuspageService';
@@ -29,9 +36,9 @@ interface RawBuildFlags {
}
export default class Build extends EasCommand {
static description = 'start a build';
static override description = 'start a build';
static flags = {
static override flags = {
platform: Flags.enum({
char: 'p',
options: ['android', 'ios', 'all'],
@@ -105,6 +112,8 @@ export default class Build extends EasCommand {
const projectDir = await findProjectRootAsync();
await handleDeprecatedEasJsonAsync(projectDir, flags.nonInteractive);
if (!flags.localBuildOptions.enable) {
await maybeWarnAboutEasOutagesAsync(
flags.autoSubmit
@@ -208,3 +217,73 @@ export default class Build extends EasCommand {
};
}
}
async function handleDeprecatedEasJsonAsync(
projectDir: string,
nonInteractive: boolean
): Promise<void> {
const reader = new EasJsonReader(projectDir);
const profileNames = await reader.getBuildProfileNamesAsync();
const platformAndProfileNames: [Platform, string][] = profileNames.flatMap(profileName => [
[Platform.ANDROID, profileName],
[Platform.IOS, profileName],
]);
const deprecatedProfiles: [Platform, string][] = [];
for (const [platform, profileName] of platformAndProfileNames) {
const buildProfile = await reader.getBuildProfileAsync(platform, profileName);
if (buildProfile.artifactPath) {
deprecatedProfiles.push([platform, profileName]);
}
}
if (deprecatedProfiles.length === 0) {
return;
}
const deprecatedProfileNames = uniq(deprecatedProfiles.map(([, profileName]) => profileName));
Log.warn(`Some of your build profiles use deprecated field ${chalk.bold('artifactPath')}:`);
for (const profileName of deprecatedProfileNames) {
Log.warn(`- ${profileName}`);
}
Log.newLine();
if (nonInteractive) {
Log.warn(
`${figures.warning} Action required: rename ${chalk.bold('artifactPath')} to ${chalk.bold(
'applicationArchivePath'
)} in all of the build profiles listed above.`
);
Log.warn(
`See ${link('https://docs.expo.dev/build-reference/eas-json/')} for more information.`
);
Log.warn(
`This warning will become an error in a future EAS CLI release. This build will continue to use the ${chalk.bold(
'artifactPath'
)} setting.`
);
return;
}
const rename = await selectAsync('Do you want us to handle renaming the field for you?', [
{ title: 'Yes', value: true },
{ title: 'No, I will edit eas.json manually (EAS CLI exits)', value: false },
]);
if (!rename) {
Errors.exit(1);
}
const easJsonPath = EasJsonReader.formatEasJsonPath(projectDir);
const easJson = await fs.readJSON(easJsonPath);
for (const [platform, profileName] of deprecatedProfiles) {
easJson.build[profileName][platform].applicationArchivePath =
easJson.build[profileName][platform].artifactPath;
delete easJson.build[profileName][platform].artifactPath;
}
await fs.writeFile(easJsonPath, `${JSON.stringify(easJson, null, 2)}\n`);
Log.withTick('Updated eas.json');
}
@@ -25,10 +25,10 @@ const STAGE_DESCRIPTION = `Stage of the build you want to inspect.
post-build - builds the native project and leaves the output directory for inspection`;
export default class BuildInspect extends EasCommand {
static description =
static override description =
'inspect the state of the project at specific build stages, useful for troubleshooting';
static flags = {
static override flags = {
platform: Flags.enum({
char: 'p',
options: [RequestedPlatform.Android, RequestedPlatform.Ios],
+2 -2
View File
@@ -22,9 +22,9 @@ import {
import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
export default class BuildList extends EasCommand {
static description = 'list all builds for your project';
static override description = 'list all builds for your project';
static flags = {
static override flags = {
platform: Flags.enum({
options: [RequestedPlatform.All, RequestedPlatform.Android, RequestedPlatform.Ios],
}),
@@ -27,9 +27,9 @@ import {
import { promptAsync } from '../../../prompts';
export default class BuildVersionSetView extends EasCommand {
static description = 'Update version of an app.';
static override description = 'Update version of an app.';
static flags = {
static override flags = {
platform: Flags.enum({
char: 'p',
options: ['android', 'ios'],
@@ -40,9 +40,10 @@ interface SyncContext<T extends Platform> {
}
export default class BuildVersionSyncView extends EasCommand {
public static description = 'Update a version in native code with a value stored on EAS servers';
public static override description =
'Update a version in native code with a value stored on EAS servers';
public static flags = {
public static override flags = {
platform: Flags.enum({
char: 'p',
options: ['android', 'ios', 'all'],
+3 -3
View File
@@ -15,11 +15,11 @@ import {
import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
export default class BuildView extends EasCommand {
static description = 'view a build for your project';
static override description = 'view a build for your project';
static args = [{ name: 'BUILD_ID' }];
static override args = [{ name: 'BUILD_ID' }];
static flags = {
static override flags = {
json: Flags.boolean({
description: 'Enable JSON output, non-JSON messages will be printed to stderr',
}),
@@ -60,9 +60,9 @@ export async function createUpdateChannelOnAppAsync({
}
export default class ChannelCreate extends EasCommand {
static description = 'create a channel';
static override description = 'create a channel';
static args = [
static override args = [
{
name: 'name',
required: false,
@@ -70,7 +70,7 @@ export default class ChannelCreate extends EasCommand {
},
];
static flags = {
static override flags = {
json: Flags.boolean({
description:
'print output as a JSON object with the new channel ID, name and branch mapping.',
@@ -21,17 +21,17 @@ import { promptAsync, toggleConfirmAsync } from '../../prompts';
import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
export default class ChannelDelete extends EasCommand {
static hidden = true;
static description = 'Delete a channel';
static override hidden = true;
static override description = 'Delete a channel';
static args = [
static override args = [
{
name: 'name',
required: false,
description: 'Name of the channel to delete',
},
];
static flags = {
static override flags = {
json: Flags.boolean({
description: 'print output as a JSON object',
default: false,
@@ -85,7 +85,7 @@ export default class ChannelDelete extends EasCommand {
if (!nonInteractiveFlag) {
Log.addNewLineIfNone();
Log.warn(
`You are about to permamently delete channel: "${name}".\nThis action is irreversible.`
`You are about to permanently delete channel: "${name}".\nThis action is irreversible.`
);
Log.newLine();
const confirmed = await toggleConfirmAsync({ message: 'Are you sure you wish to proceed?' });
@@ -93,9 +93,9 @@ export async function updateChannelBranchMappingAsync({
}
export default class ChannelEdit extends EasCommand {
static description = 'point a channel at a new branch';
static override description = 'point a channel at a new branch';
static args = [
static override args = [
{
name: 'name',
required: false,
@@ -103,7 +103,7 @@ export default class ChannelEdit extends EasCommand {
},
];
static flags = {
static override flags = {
branch: Flags.string({
description: 'Name of the branch to point to',
}),
@@ -67,9 +67,9 @@ async function getAllUpdateChannelForAppAsync({
}
export default class ChannelList extends EasCommand {
static description = 'list all channels';
static override description = 'list all channels';
static flags = {
static override flags = {
json: Flags.boolean({
description: 'print output as a JSON object with the channel ID, name and branch mapping.',
default: false,
@@ -304,10 +304,10 @@ async function endRolloutAsync({
}
export default class ChannelRollout extends EasCommand {
static hidden = true;
static description = 'Rollout a new branch out to a channel incrementally.';
static override hidden = true;
static override description = 'Rollout a new branch out to a channel incrementally.';
static args = [
static override args = [
{
name: 'channel',
required: true,
@@ -315,7 +315,7 @@ export default class ChannelRollout extends EasCommand {
},
];
static flags = {
static override flags = {
branch: Flags.string({
description: 'branch to rollout',
required: false,
@@ -138,9 +138,9 @@ export function logChannelDetails(channel: {
}
export default class ChannelView extends EasCommand {
static description = 'view a channel';
static override description = 'view a channel';
static args = [
static override args = [
{
name: 'name',
required: false,
@@ -148,7 +148,7 @@ export default class ChannelView extends EasCommand {
},
];
static flags = {
static override flags = {
json: Flags.boolean({
description: 'print output as a JSON object with the channel ID, name and branch mapping.',
default: false,
+3 -3
View File
@@ -13,14 +13,14 @@ import { findProjectRootAsync } from '../project/projectUtils';
import { selectAsync } from '../prompts';
export default class Config extends EasCommand {
static description = 'display project configuration (app.json + eas.json)';
static override description = 'display project configuration (app.json + eas.json)';
static flags = {
static override flags = {
platform: Flags.enum({ char: 'p', options: ['android', 'ios'] }),
profile: Flags.string(),
};
protected requiresAuthentication = false;
protected override requiresAuthentication = false;
async runAsync(): Promise<void> {
const { flags } = await this.parse(Config);
+2 -2
View File
@@ -4,9 +4,9 @@ import EasCommand from '../commandUtils/EasCommand';
import { SelectPlatform } from '../credentials/manager/SelectPlatform';
export default class Credentials extends EasCommand {
static description = 'manage credentials';
static override description = 'manage credentials';
static flags = {
static override flags = {
platform: Flags.enum({ char: 'p', options: ['android', 'ios'] }),
};
@@ -5,7 +5,7 @@ import DeviceManager from '../../devices/manager';
import { ensureLoggedInAsync } from '../../user/actions';
export default class DeviceCreate extends EasCommand {
static description = 'register new Apple Devices to use for internal distribution';
static override description = 'register new Apple Devices to use for internal distribution';
async runAsync(): Promise<void> {
const user = await ensureLoggedInAsync();
@@ -21,9 +21,9 @@ import { findProjectRootAsync, getProjectAccountNameAsync } from '../../project/
import { promptAsync, toggleConfirmAsync } from '../../prompts';
export default class DeviceDelete extends EasCommand {
static description = 'remove a registered device from your account';
static override description = 'remove a registered device from your account';
static flags = {
static override flags = {
'apple-team-id': Flags.string(),
udid: Flags.string({ multiple: true }),
};
@@ -89,9 +89,10 @@ export default class DeviceDelete extends EasCommand {
Log.addNewLineIfNone();
const removeAppleSpinner = ora('Disabling devices on Apple').start();
try {
let realDevices = await Device.getAllIOSProfileDevicesAsync(context);
realDevices = realDevices.filter(d =>
chosenDevices.map(cd => cd.identifier).includes(d.attributes.udid)
const chosenDeviceIdentifiers = chosenDevices.map(cd => cd.identifier);
const allDevices = await Device.getAsync(context);
const realDevices = allDevices.filter(d =>
chosenDeviceIdentifiers.includes(d.attributes.udid)
);
for (const device of realDevices) {
+2 -2
View File
@@ -13,9 +13,9 @@ import { findProjectRootAsync, getProjectAccountNameAsync } from '../../project/
import { promptAsync } from '../../prompts';
export default class BuildList extends EasCommand {
static description = 'list all registered devices for your account';
static override description = 'list all registered devices for your account';
static flags = {
static override flags = {
'apple-team-id': Flags.string(),
};
+2 -2
View File
@@ -7,9 +7,9 @@ import { getExpoConfig } from '../../project/expoConfig';
import { findProjectRootAsync, getProjectAccountNameAsync } from '../../project/projectUtils';
export default class DeviceView extends EasCommand {
static description = 'view a device for your project';
static override description = 'view a device for your project';
static args = [{ name: 'UDID' }];
static override args = [{ name: 'UDID' }];
async runAsync(): Promise<void> {
const { UDID } = (await this.parse(DeviceView)).args;
+2 -2
View File
@@ -8,9 +8,9 @@ import { resolveWorkflowAsync } from '../project/workflow';
import { easCliVersion } from '../utils/easCli';
export default class Diagnostics extends EasCommand {
static description = 'display environment info';
static override description = 'display environment info';
protected requiresAuthentication = false;
protected override requiresAuthentication = false;
async runAsync(): Promise<void> {
const info = await envinfo.run(
@@ -14,9 +14,9 @@ import { findProjectRootAsync, getProjectIdAsync } from '../../project/projectUt
import { ensureLoggedInAsync } from '../../user/actions';
export default class MetadataPull extends EasCommand {
static description = 'generate the local store configuration from the app stores';
static override description = 'generate the local store configuration from the app stores';
static flags = {
static override flags = {
profile: Flags.string({
description:
'Name of the submit profile from eas.json. Defaults to "production" if defined in eas.json.',
@@ -12,9 +12,9 @@ import { findProjectRootAsync, getProjectIdAsync } from '../../project/projectUt
import { ensureLoggedInAsync } from '../../user/actions';
export default class MetadataPush extends EasCommand {
static description = 'sync the local store configuration to the app stores';
static override description = 'sync the local store configuration to the app stores';
static flags = {
static override flags = {
profile: Flags.string({
description:
'Name of the submit profile from eas.json. Defaults to "production" if defined in eas.json.',
+45
View File
@@ -0,0 +1,45 @@
import openBrowserAsync from 'better-opn';
import { getProjectDashboardUrl } from '../build/utils/url';
import EasCommand from '../commandUtils/EasCommand';
import { ora } from '../ora';
import { getExpoConfig } from '../project/expoConfig';
import {
fetchProjectIdFromServerAsync,
findProjectRootAsync,
getProjectAccountName,
} from '../project/projectUtils';
import { ensureLoggedInAsync } from '../user/actions';
export default class Open extends EasCommand {
static override description = 'open the project page in a web browser';
async runAsync(): Promise<void> {
const projectDir = await findProjectRootAsync();
const exp = getExpoConfig(projectDir);
// this ensures the project exists
await fetchProjectIdFromServerAsync(exp);
const user = await ensureLoggedInAsync();
const accountName = getProjectAccountName(exp, user);
const projectName = exp.slug;
const projectDashboardUrl = getProjectDashboardUrl(accountName, projectName);
const failedMessage = `Unable to open a web browser. Project page is available at: ${projectDashboardUrl}`;
const spinner = ora(`Opening ${projectDashboardUrl}`).start();
try {
const opened = await openBrowserAsync(projectDashboardUrl);
if (opened) {
spinner.succeed(`Opened ${projectDashboardUrl}`);
} else {
spinner.fail(failedMessage);
}
return;
} catch (error) {
spinner.fail(failedMessage);
throw error;
}
}
}
@@ -32,7 +32,7 @@ async function projectInfoByIdAsync(appId: string): Promise<AppInfoQuery> {
}
export default class ProjectInfo extends EasCommand {
static description = 'information about the current project';
static override description = 'information about the current project';
async runAsync(): Promise<void> {
const projectDir = await findProjectRootAsync();
@@ -10,8 +10,8 @@ import {
} from '../../project/projectUtils';
export default class ProjectInit extends EasCommand {
static description = 'create or link an EAS project';
static aliases = ['init'];
static override description = 'create or link an EAS project';
static override aliases = ['init'];
async runAsync(): Promise<void> {
const projectDir = await findProjectRootAsync();
@@ -20,9 +20,10 @@ import { getActorDisplayName } from '../../user/User';
import { ensureLoggedInAsync } from '../../user/actions';
export default class EnvironmentSecretCreate extends EasCommand {
static description = 'create an environment secret on the current project or owner account';
static override description =
'create an environment secret on the current project or owner account';
static flags = {
static override flags = {
scope: Flags.enum({
description: 'Scope for the secret',
options: [EnvironmentSecretScope.ACCOUNT, EnvironmentSecretScope.PROJECT],
@@ -17,9 +17,9 @@ import {
import { promptAsync, toggleConfirmAsync } from '../../prompts';
export default class EnvironmentSecretDelete extends EasCommand {
static description = 'delete an environment secret by ID';
static override description = 'delete an environment secret by ID';
static flags = {
static override flags = {
id: Flags.string({
description: 'ID of the secret to delete',
}),
@@ -60,7 +60,7 @@ export default class EnvironmentSecretDelete extends EasCommand {
Log.addNewLineIfNone();
Log.warn(
`You are about to permamently delete secret${
`You are about to permanently delete secret${
secret?.name ? ` "${secret?.name}"` : ''
} with id: "${id}".\nThis action is irreversible.`
);
+1 -1
View File
@@ -13,7 +13,7 @@ import {
} from '../../project/projectUtils';
export default class EnvironmentSecretList extends EasCommand {
static description = 'list environment secrets available for your current app';
static override description = 'list environment secrets available for your current app';
async runAsync(): Promise<void> {
const projectDir = await findProjectRootAsync();
+3 -3
View File
@@ -47,10 +47,10 @@ interface CommandFlags {
}
export default class Submit extends EasCommand {
static description = 'submit app binary to App Store and/or Play Store';
static aliases = ['build:submit'];
static override description = 'submit app binary to App Store and/or Play Store';
static override aliases = ['build:submit'];
static flags = {
static override flags = {
platform: Flags.enum({
char: 'p',
options: ['android', 'ios', 'all'],
@@ -24,9 +24,9 @@ const DEFAULT_MANAGED_RUNTIME_VERSION = { policy: 'sdkVersion' } as const;
const DEFAULT_BARE_RUNTIME_VERSION = '1.0.0' as const;
export default class UpdateConfigure extends EasCommand {
static description = 'configure the project to support EAS Update';
static override description = 'configure the project to support EAS Update';
static flags = {
static override flags = {
platform: Flags.enum({
description: 'Platform to configure',
char: 'p',
@@ -117,6 +117,7 @@ async function configureAppJSONForEASUpdateAsync({
exp.ios?.runtimeVersion ?? exp.runtimeVersion ?? iosDefaultRuntimeVersion;
let newConfig: Partial<ExpoConfig>;
let newConfigOnlyAddedValues: Partial<ExpoConfig>;
switch (platform) {
case RequestedPlatform.All: {
if (isRuntimeEqual(newAndroidRuntimeVersion, newIosRuntimeVersion)) {
@@ -129,6 +130,26 @@ async function configureAppJSONForEASUpdateAsync({
ios: { ...exp.ios, runtimeVersion: undefined },
updates,
};
newConfigOnlyAddedValues = {
runtimeVersion: newAndroidRuntimeVersion,
...(exp.android && 'runtimeVersion' in exp.android
? {
android: {
runtimeVersion: '<remove this key>',
},
}
: {}),
...(exp.ios && 'runtimeVersion' in exp.ios
? {
ios: {
runtimeVersion: '<remove this key>',
},
}
: {}),
updates: {
url: easUpdateURL,
},
};
} else {
newConfig = {
runtimeVersion: undefined, // top level runtime is redundant if it is specified in both android and ios
@@ -142,6 +163,22 @@ async function configureAppJSONForEASUpdateAsync({
},
updates,
};
newConfigOnlyAddedValues = {
...('runtimeVersion' in exp
? {
runtimeVersion: '<remove this key>', // top level runtime is redundant if it is specified in both android and ios
}
: {}),
android: {
runtimeVersion: newAndroidRuntimeVersion,
},
ios: {
runtimeVersion: newIosRuntimeVersion,
},
updates: {
url: easUpdateURL,
},
};
}
break;
}
@@ -153,6 +190,14 @@ async function configureAppJSONForEASUpdateAsync({
},
updates,
};
newConfigOnlyAddedValues = {
android: {
runtimeVersion: newAndroidRuntimeVersion,
},
updates: {
url: easUpdateURL,
},
};
break;
}
case RequestedPlatform.Ios: {
@@ -163,6 +208,14 @@ async function configureAppJSONForEASUpdateAsync({
},
updates,
};
newConfigOnlyAddedValues = {
ios: {
runtimeVersion: newIosRuntimeVersion,
},
updates: {
url: easUpdateURL,
},
};
break;
}
default: {
@@ -172,8 +225,8 @@ async function configureAppJSONForEASUpdateAsync({
const result = await modifyConfigAsync(projectDir, newConfig);
const prexistingAndroidRuntimeVersion = exp.android?.runtimeVersion ?? exp.runtimeVersion;
const prexistingIosRuntimeVersion = exp.ios?.runtimeVersion ?? exp.runtimeVersion;
const preexistingAndroidRuntimeVersion = exp.android?.runtimeVersion ?? exp.runtimeVersion;
const preexistingIosRuntimeVersion = exp.ios?.runtimeVersion ?? exp.runtimeVersion;
switch (result.type) {
case 'success':
if (exp.updates?.url) {
@@ -187,7 +240,7 @@ async function configureAppJSONForEASUpdateAsync({
}
if (
!prexistingAndroidRuntimeVersion &&
!preexistingAndroidRuntimeVersion &&
[RequestedPlatform.Android, RequestedPlatform.All].includes(platform)
) {
Log.withTick(
@@ -197,7 +250,7 @@ async function configureAppJSONForEASUpdateAsync({
);
}
if (
!prexistingIosRuntimeVersion &&
!preexistingIosRuntimeVersion &&
[RequestedPlatform.Ios, RequestedPlatform.All].includes(platform)
) {
Log.withTick(
@@ -219,7 +272,7 @@ async function configureAppJSONForEASUpdateAsync({
'https://expo.fyi/eas-update-config.md'
)}\n`
);
Log.log(chalk.bold(JSON.stringify(newConfig, null, 2)));
Log.log(chalk.bold(JSON.stringify(newConfigOnlyAddedValues, null, 2)));
Log.addNewLineIfNone();
if (workflows['android'] === Workflow.GENERIC || workflows['ios'] === Workflow.GENERIC) {
Log.warn(
@@ -36,9 +36,9 @@ async function deleteUpdateGroupAsync({
}
export default class UpdateDelete extends EasCommand {
static description = 'delete all the updates in an update group';
static override description = 'delete all the updates in an update group';
static args = [
static override args = [
{
name: 'groupId',
required: true,
@@ -46,7 +46,7 @@ export default class UpdateDelete extends EasCommand {
},
];
static flags = {
static override flags = {
json: Flags.boolean({
description: `Return a json with the group ID of the deleted updates.`,
default: false,
@@ -69,7 +69,7 @@ export default class UpdateDelete extends EasCommand {
'This is a permanent operation.'
)}\n\n` +
`If you want to revert to a previous publish, you should use 'update --republish' targeted at the last working update group instead.\n\n` +
`An update group should only be deleted in an emergency like an accidental publish of a secret. In this case user 'update --republish' to revert to the last working update group first and then proceed with the deletion. Deleting an update group when it is the latest publish can lead to inconsistent cacheing behavior by clients.\n\n` +
`An update group should only be deleted in an emergency like an accidental publish of a secret. In this case user 'update --republish' to revert to the last working update group first and then proceed with the deletion. Deleting an update group when it is the latest publish can lead to inconsistent caching behavior by clients.\n\n` +
`Would you like to abort?`,
});
@@ -161,9 +161,9 @@ export async function ensureBranchExistsAsync({
}
export default class UpdatePublish extends EasCommand {
static description = 'publish an update group';
static override description = 'publish an update group';
static flags = {
static override flags = {
branch: Flags.string({
description: 'Branch to publish the update group on',
required: false,
+2 -2
View File
@@ -20,9 +20,9 @@ import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
import { getVcsClient } from '../../vcs';
export default class BranchView extends EasCommand {
static description = 'view the recent updates for a branch';
static override description = 'view the recent updates for a branch';
static flags = {
static override flags = {
branch: Flags.string({
description: 'List all updates on this branch',
exclusive: ['all'],
+3 -3
View File
@@ -51,9 +51,9 @@ export async function viewUpdateAsync({
return data;
}
export default class UpdateView extends EasCommand {
static description = 'update group details';
static override description = 'update group details';
static args = [
static override args = [
{
name: 'groupId',
required: true,
@@ -61,7 +61,7 @@ export default class UpdateView extends EasCommand {
},
];
static flags = {
static override flags = {
json: Flags.boolean({
description: `Return a json with the updates belonging to the group.`,
default: false,
@@ -9,9 +9,9 @@ import { findProjectRootAsync, getProjectIdAsync } from '../../project/projectUt
import { prepareInputParamsAsync } from '../../webhooks/input';
export default class WebhookCreate extends EasCommand {
static description = 'create a webhook';
static override description = 'create a webhook';
static flags = {
static override flags = {
event: Flags.enum({
description: 'Event type that triggers the webhook',
options: [WebhookType.Build, WebhookType.Submit],
@@ -14,9 +14,9 @@ import { promptAsync, toggleConfirmAsync } from '../../prompts';
import { formatWebhook } from '../../webhooks/formatWebhook';
export default class WebhookDelete extends EasCommand {
static description = 'delete a webhook';
static override description = 'delete a webhook';
static args = [
static override args = [
{
name: 'ID',
required: false,
@@ -57,7 +57,7 @@ export default class WebhookDelete extends EasCommand {
Log.addNewLineIfNone();
Log.log(formatWebhook(webhook));
Log.newLine();
Log.warn(`You are about to permamently delete this webhook.\nThis action is irreversible.`);
Log.warn(`You are about to permanently delete this webhook.\nThis action is irreversible.`);
Log.newLine();
const confirmed = await toggleConfirmAsync({
message: 'Are you sure you wish to proceed?',
@@ -15,9 +15,9 @@ import {
import { formatWebhook } from '../../webhooks/formatWebhook';
export default class WebhookList extends EasCommand {
static description = 'list webhooks';
static override description = 'list webhooks';
static flags = {
static override flags = {
event: Flags.enum({
description: 'Event type that triggers the webhook',
options: [WebhookType.Build, WebhookType.Submit],
@@ -9,9 +9,9 @@ import pick from '../../utils/expodash/pick';
import { prepareInputParamsAsync } from '../../webhooks/input';
export default class WebhookUpdate extends EasCommand {
static description = 'update a webhook';
static override description = 'update a webhook';
static flags = {
static override flags = {
id: Flags.string({
description: 'Webhook ID',
required: true,
@@ -5,9 +5,9 @@ import { ora } from '../../ora';
import { formatWebhook } from '../../webhooks/formatWebhook';
export default class WebhookView extends EasCommand {
static description = 'view a webhook';
static override description = 'view a webhook';
static args = [
static override args = [
{
name: 'ID',
required: true,
@@ -76,9 +76,13 @@ export const testPushKey: ApplePushKeyFragment = {
iosAppCredentialsList: [],
};
export const testTargets: Target[] = [
{ targetName: 'testapp', bundleIdentifier: 'foo.bar.com', entitlements: {} },
];
export const testTarget = {
targetName: 'testapp',
bundleIdentifier: 'foo.bar.com',
entitlements: {},
};
export const testTargets: Target[] = [testTarget];
export const testProvisioningProfileFragment: AppleProvisioningProfileFragment = {
id: 'test-prov-prof-id-1',
@@ -101,7 +101,7 @@ export default class IosCredentialsProvider {
return null;
}
if (ctx.easJsonCliConfig?.promptToConfigurePushNotfications === false) {
if (ctx.easJsonCliConfig?.promptToConfigurePushNotifications === false) {
return null;
}
@@ -131,7 +131,7 @@ export default class IosCredentialsProvider {
): Promise<void> {
const easJsonPath = EasJsonReader.formatEasJsonPath(ctx.projectDir);
const easJson = await fs.readJSON(easJsonPath);
easJson.cli = { ...easJson?.cli, promptToConfigurePushNotfications: false };
easJson.cli = { ...easJson?.cli, promptToConfigurePushNotifications: false };
await fs.writeFile(easJsonPath, `${JSON.stringify(easJson, null, 2)}\n`);
Log.withTick('Updated eas.json');
}
@@ -17,6 +17,7 @@ jest.mock('fs');
jest.mock('../validators/validateProvisioningProfile', () => ({
validateProvisioningProfileAsync: async (
_ctx: any,
_target: any,
_app: any,
buildCredentials: Partial<IosAppBuildCredentialsFragment> | null
): Promise<boolean> => {
@@ -7,16 +7,19 @@ import {
} from '../../../graphql/generated';
import Log from '../../../log';
import { ora } from '../../../ora';
import { getApplePlatformFromSdkRoot } from '../../../project/ios/target';
import { CredentialsContext } from '../../context';
import { MissingCredentialsNonInteractiveError } from '../../errors';
import { AppLookupParams } from '../api/GraphqlClient';
import { AppleProvisioningProfileMutationResult } from '../api/graphql/mutations/AppleProvisioningProfileMutation';
import { ProvisioningProfileStoreInfo } from '../appstore/Credentials.types';
import { AuthCtx } from '../appstore/authenticateTypes';
import { Target } from '../types';
export class ConfigureProvisioningProfile {
constructor(
private app: AppLookupParams,
private target: Target,
private distributionCertificate: AppleDistributionCertificateFragment,
private originalProvisioningProfile: AppleProvisioningProfileFragment
) {}
@@ -43,8 +46,10 @@ export class ConfigureProvisioningProfile {
return null;
}
const applePlatform = await getApplePlatformFromSdkRoot(this.target);
const profilesFromApple = await ctx.appStore.listProvisioningProfilesAsync(
this.app.bundleIdentifier
this.app.bundleIdentifier,
applePlatform
);
const [matchingProfile] = profilesFromApple.filter(appleInfo =>
developerPortalIdentifier
@@ -11,12 +11,14 @@ import { AppleProvisioningProfileMutationResult } from '../api/graphql/mutations
import { ProvisioningProfile } from '../appstore/Credentials.types';
import { AuthCtx } from '../appstore/authenticateTypes';
import { provisioningProfileSchema } from '../credentials';
import { Target } from '../types';
import { resolveAppleTeamIfAuthenticatedAsync } from './AppleTeamUtils';
import { generateProvisioningProfileAsync } from './ProvisioningProfileUtils';
export class CreateProvisioningProfile {
constructor(
private app: AppLookupParams,
private target: Target,
private distributionCertificate: AppleDistributionCertificateFragment
) {}
@@ -63,7 +65,7 @@ export class CreateProvisioningProfile {
this.distributionCertificate.certificatePassword,
'Distribution Certificate must have certificate password'
);
return await generateProvisioningProfileAsync(ctx, this.app.bundleIdentifier, {
return await generateProvisioningProfileAsync(ctx, this.target, this.app.bundleIdentifier, {
certId: this.distributionCertificate.developerPortalIdentifier ?? undefined,
certP12: this.distributionCertificate.certificateP12,
certPassword: this.distributionCertificate.certificatePassword,
@@ -1,11 +1,13 @@
import chalk from 'chalk';
import { getApplePlatformFromSdkRoot } from '../../../project/ios/target';
import { CredentialsContext } from '../../context';
import {
DistributionCertificate,
ProvisioningProfile,
ProvisioningProfileStoreInfo,
} from '../appstore/Credentials.types';
import { Target } from '../types';
export function formatProvisioningProfileFromApple(
appleInfo: ProvisioningProfileStoreInfo
@@ -20,11 +22,18 @@ export function formatProvisioningProfileFromApple(
export async function generateProvisioningProfileAsync(
ctx: CredentialsContext,
target: Target,
bundleIdentifier: string,
distCert: DistributionCertificate
): Promise<ProvisioningProfile> {
const appleAuthCtx = await ctx.appStore.ensureAuthenticatedAsync();
const type = appleAuthCtx.team.inHouse ? 'Enterprise ' : 'AppStore';
const profileName = `*[expo] ${bundleIdentifier} ${type} ${new Date().toISOString()}`; // Apple drops [ if its the first char (!!)
return await ctx.appStore.createProvisioningProfileAsync(bundleIdentifier, distCert, profileName);
const applePlatform = await getApplePlatformFromSdkRoot(target);
return await ctx.appStore.createProvisioningProfileAsync(
bundleIdentifier,
distCert,
profileName,
applePlatform
);
}
@@ -1,3 +1,4 @@
import { ProfileType } from '@expo/apple-utils';
import assert from 'assert';
import chalk from 'chalk';
import nullthrows from 'nullthrows';
@@ -12,11 +13,14 @@ import {
IosDistributionType,
} from '../../../graphql/generated';
import Log from '../../../log';
import { getApplePlatformFromSdkRoot } from '../../../project/ios/target';
import { confirmAsync, pressAnyKeyToContinueAsync, promptAsync } from '../../../prompts';
import differenceBy from '../../../utils/expodash/differenceBy';
import { CredentialsContext } from '../../context';
import { MissingCredentialsNonInteractiveError } from '../../errors';
import { AppLookupParams } from '../api/GraphqlClient';
import { ApplePlatform } from '../appstore/constants';
import { Target } from '../types';
import { validateProvisioningProfileAsync } from '../validators/validateProvisioningProfile';
import { resolveAppleTeamIfAuthenticatedAsync } from './AppleTeamUtils';
import { assignBuildCredentialsAsync, getBuildCredentialsAsync } from './BuildCredentialsUtils';
@@ -29,12 +33,18 @@ enum ReuseAction {
No,
}
interface Options {
app: AppLookupParams;
target: Target;
}
export class SetUpAdhocProvisioningProfile {
constructor(private app: AppLookupParams) {}
constructor(private options: Options) {}
async runAsync(ctx: CredentialsContext): Promise<IosAppBuildCredentialsFragment> {
const { app } = this.options;
const distCert = await new SetUpDistributionCertificate(
this.app,
app,
IosDistributionType.AdHoc
).runAsync(ctx);
@@ -42,7 +52,7 @@ export class SetUpAdhocProvisioningProfile {
if (ctx.nonInteractive) {
if (areBuildCredentialsSetup) {
return nullthrows(await getBuildCredentialsAsync(ctx, this.app, IosDistributionType.AdHoc));
return nullthrows(await getBuildCredentialsAsync(ctx, app, IosDistributionType.AdHoc));
} else {
throw new MissingCredentialsNonInteractiveError(
'Provisioning profile is not configured correctly. Run this command again in interactive mode.'
@@ -52,7 +62,7 @@ export class SetUpAdhocProvisioningProfile {
const currentBuildCredentials = await getBuildCredentialsAsync(
ctx,
this.app,
app,
IosDistributionType.AdHoc
);
if (areBuildCredentialsSetup) {
@@ -69,9 +79,11 @@ export class SetUpAdhocProvisioningProfile {
ctx: CredentialsContext,
distCert: AppleDistributionCertificateFragment
): Promise<IosAppBuildCredentialsFragment> {
const { app, target } = this.options;
const currentBuildCredentials = await getBuildCredentialsAsync(
ctx,
this.app,
app,
IosDistributionType.AdHoc
);
@@ -80,12 +92,12 @@ export class SetUpAdhocProvisioningProfile {
distCert.appleTeam ?? currentBuildCredentials?.provisioningProfile?.appleTeam ?? null;
if (!appleTeam) {
await ctx.appStore.ensureAuthenticatedAsync();
appleTeam = await resolveAppleTeamIfAuthenticatedAsync(ctx, this.app);
appleTeam = await resolveAppleTeamIfAuthenticatedAsync(ctx, app);
}
assert(appleTeam, 'Apple Team must be defined here');
// 2. Fetch devices registered on EAS servers
let registeredAppleDevices = await ctx.ios.getDevicesForAppleTeamAsync(this.app, appleTeam);
let registeredAppleDevices = await ctx.ios.getDevicesForAppleTeamAsync(app, appleTeam);
if (registeredAppleDevices.length === 0) {
const shouldRegisterDevices = await confirmAsync({
message: `You don't have any registered devices yet. Would you like to register them now?`,
@@ -109,16 +121,22 @@ export class SetUpAdhocProvisioningProfile {
);
// 4. Reuse or create the profile on Apple Developer Portal
const applePlatform = await getApplePlatformFromSdkRoot(target);
const profileType =
applePlatform === ApplePlatform.TV_OS
? ProfileType.TVOS_APP_ADHOC
: ProfileType.IOS_APP_ADHOC;
const provisioningProfileStoreInfo =
await ctx.appStore.createOrReuseAdhocProvisioningProfileAsync(
chosenDevices.map(({ identifier }) => identifier),
this.app.bundleIdentifier,
distCert.serialNumber
app.bundleIdentifier,
distCert.serialNumber,
profileType
);
// 5. Create or update the profile on servers
const appleAppIdentifier = await ctx.ios.createOrGetExistingAppleAppIdentifierAsync(
this.app,
app,
appleTeam
);
let appleProvisioningProfile: AppleProvisioningProfileFragment | null = null;
@@ -131,7 +149,7 @@ export class SetUpAdhocProvisioningProfile {
currentBuildCredentials.provisioningProfile.id,
]);
appleProvisioningProfile = await ctx.ios.createProvisioningProfileAsync(
this.app,
app,
appleAppIdentifier,
{
appleProvisioningProfile: provisioningProfileStoreInfo.provisioningProfile,
@@ -143,7 +161,7 @@ export class SetUpAdhocProvisioningProfile {
}
} else {
appleProvisioningProfile = await ctx.ios.createProvisioningProfileAsync(
this.app,
app,
appleAppIdentifier,
{
appleProvisioningProfile: provisioningProfileStoreInfo.provisioningProfile,
@@ -156,7 +174,7 @@ export class SetUpAdhocProvisioningProfile {
assert(appleProvisioningProfile);
return await assignBuildCredentialsAsync(
ctx,
this.app,
app,
IosDistributionType.AdHoc,
distCert,
appleProvisioningProfile,
@@ -165,22 +183,20 @@ export class SetUpAdhocProvisioningProfile {
}
private async areBuildCredentialsSetupAsync(ctx: CredentialsContext): Promise<boolean> {
const buildCredentials = await getBuildCredentialsAsync(
ctx,
this.app,
IosDistributionType.AdHoc
);
return await validateProvisioningProfileAsync(ctx, this.app, buildCredentials);
const { app, target } = this.options;
const buildCredentials = await getBuildCredentialsAsync(ctx, app, IosDistributionType.AdHoc);
return await validateProvisioningProfileAsync(ctx, target, app, buildCredentials);
}
private async shouldUseExistingProfileAsync(
ctx: CredentialsContext,
buildCredentials: IosAppBuildCredentialsFragment
): Promise<boolean> {
const { app } = this.options;
const provisioningProfile = nullthrows(buildCredentials.provisioningProfile);
const appleTeam = nullthrows(provisioningProfile.appleTeam);
const registeredAppleDevices = await ctx.ios.getDevicesForAppleTeamAsync(this.app, appleTeam);
const registeredAppleDevices = await ctx.ios.getDevicesForAppleTeamAsync(app, appleTeam);
const provisionedDevices = provisioningProfile.appleDevices;
@@ -254,7 +270,8 @@ export class SetUpAdhocProvisioningProfile {
ctx: CredentialsContext,
appleTeam: AppleTeamFragment
): Promise<AppleDeviceFragment[]> {
const action = new DeviceCreateAction(ctx.appStore, this.app.account, appleTeam);
const { app } = this.options;
const action = new DeviceCreateAction(ctx.appStore, app.account, appleTeam);
const method = await action.runAsync();
while (true) {
@@ -265,7 +282,7 @@ export class SetUpAdhocProvisioningProfile {
}
Log.newLine();
const devices = await ctx.ios.getDevicesForAppleTeamAsync(this.app, appleTeam, {
const devices = await ctx.ios.getDevicesForAppleTeamAsync(app, appleTeam, {
useCache: false,
});
if (devices.length === 0) {
@@ -51,6 +51,7 @@ export class SetUpBuildCredentials {
enterpriseProvisioning: this.options.enterpriseProvisioning,
distribution: this.options.distribution,
entitlements: target.entitlements,
target,
app: {
...this.options.app,
bundleIdentifier: target.bundleIdentifier,
@@ -3,6 +3,7 @@ import Log, { learnMore } from '../../../log';
import { promptAsync } from '../../../prompts';
import { CredentialsContext } from '../../context';
import { AppLookupParams } from '../api/GraphqlClient';
import { Target } from '../types';
import { getAllBuildCredentialsAsync } from './BuildCredentialsUtils';
import { SetUpAdhocProvisioningProfile } from './SetUpAdhocProvisioningProfile';
import { SetUpProvisioningProfile } from './SetUpProvisioningProfile';
@@ -14,11 +15,17 @@ import { SetUpProvisioningProfile } from './SetUpProvisioningProfile';
* to choose if they want to set up an adhoc or universal distribution provisioning profile. Otherwise, always
* set up an adhoc provisioning profile.
*/
interface Options {
app: AppLookupParams;
target: Target;
}
export class SetUpInternalProvisioningProfile {
constructor(private app: AppLookupParams) {}
constructor(private options: Options) {}
async runAsync(ctx: CredentialsContext): Promise<IosAppBuildCredentialsFragment> {
const buildCredentials = await getAllBuildCredentialsAsync(ctx, this.app);
const buildCredentials = await getAllBuildCredentialsAsync(ctx, this.options.app);
const adhocBuildCredentialsExist =
buildCredentials.filter(
@@ -87,15 +94,18 @@ export class SetUpInternalProvisioningProfile {
private async setupAdhocProvisioningProfileAsync(
ctx: CredentialsContext
): Promise<IosAppBuildCredentialsFragment> {
return await new SetUpAdhocProvisioningProfile(this.app).runAsync(ctx);
const { app, target } = this.options;
return await new SetUpAdhocProvisioningProfile({ app, target }).runAsync(ctx);
}
private async setupUniversalProvisioningProfileAsync(
ctx: CredentialsContext
): Promise<IosAppBuildCredentialsFragment> {
return await new SetUpProvisioningProfile(this.app, IosDistributionType.Enterprise).runAsync(
ctx
);
return await new SetUpProvisioningProfile(
this.options.app,
this.options.target,
IosDistributionType.Enterprise
).runAsync(ctx);
}
private async askForDistributionTypeAndSetupAsync(
@@ -6,11 +6,13 @@ import {
IosAppBuildCredentialsFragment,
IosDistributionType,
} from '../../../graphql/generated';
import { getApplePlatformFromSdkRoot } from '../../../project/ios/target';
import { confirmAsync } from '../../../prompts';
import { CredentialsContext } from '../../context';
import { MissingCredentialsNonInteractiveError } from '../../errors';
import { AppLookupParams } from '../api/GraphqlClient';
import { ProvisioningProfileStoreInfo } from '../appstore/Credentials.types';
import { Target } from '../types';
import { validateProvisioningProfileAsync } from '../validators/validateProvisioningProfile';
import {
assignBuildCredentialsAsync,
@@ -26,11 +28,15 @@ import { SetUpDistributionCertificate } from './SetUpDistributionCertificate';
* Sets up either APP_STORE or ENTERPRISE provisioning profiles
*/
export class SetUpProvisioningProfile {
constructor(private app: AppLookupParams, private distributionType: IosDistributionType) {}
constructor(
private app: AppLookupParams,
private target: Target,
private distributionType: IosDistributionType
) {}
async areBuildCredentialsSetupAsync(ctx: CredentialsContext): Promise<boolean> {
const buildCredentials = await getBuildCredentialsAsync(ctx, this.app, this.distributionType);
return await validateProvisioningProfileAsync(ctx, this.app, buildCredentials);
return await validateProvisioningProfileAsync(ctx, this.target, this.app, buildCredentials);
}
async assignNewAndDeleteOldProfileAsync(
@@ -48,9 +54,11 @@ export class SetUpProvisioningProfile {
ctx: CredentialsContext,
distCert: AppleDistributionCertificateFragment
): Promise<IosAppBuildCredentialsFragment> {
const provisioningProfile = await new CreateProvisioningProfile(this.app, distCert).runAsync(
ctx
);
const provisioningProfile = await new CreateProvisioningProfile(
this.app,
this.target,
distCert
).runAsync(ctx);
return await assignBuildCredentialsAsync(
ctx,
this.app,
@@ -67,6 +75,7 @@ export class SetUpProvisioningProfile {
): Promise<IosAppBuildCredentialsFragment | null> {
const profileConfigurator = new ConfigureProvisioningProfile(
this.app,
this.target,
distCert,
originalProvisioningProfile
);
@@ -105,8 +114,10 @@ export class SetUpProvisioningProfile {
}
// See if the profile we have exists on the Apple Servers
const applePlatform = await getApplePlatformFromSdkRoot(this.target);
const existingProfiles = await ctx.appStore.listProvisioningProfilesAsync(
this.app.bundleIdentifier
this.app.bundleIdentifier,
applePlatform
);
const currentProfileFromServer = this.getCurrentProfileStoreInfo(
existingProfiles,
@@ -8,6 +8,7 @@ import {
import Log from '../../../log';
import { CredentialsContext } from '../../context';
import { AppLookupParams as GraphQLAppLookupParams } from '../api/GraphqlClient';
import { Target } from '../types';
import { SetUpAdhocProvisioningProfile } from './SetUpAdhocProvisioningProfile';
import { SetUpInternalProvisioningProfile } from './SetUpInternalProvisioningProfile';
import { SetUpProvisioningProfile } from './SetUpProvisioningProfile';
@@ -17,6 +18,7 @@ interface Options {
distribution: DistributionType;
enterpriseProvisioning?: IosEnterpriseProvisioning;
entitlements: JSONObject;
target: Target;
}
export class SetUpTargetBuildCredentials {
constructor(private options: Options) {}
@@ -47,22 +49,25 @@ export class SetUpTargetBuildCredentials {
async setupBuildCredentialsAsync(
ctx: CredentialsContext
): Promise<IosAppBuildCredentialsFragment> {
const { app, distribution, enterpriseProvisioning } = this.options;
const { app, distribution, enterpriseProvisioning, target } = this.options;
if (distribution === 'internal') {
if (enterpriseProvisioning === 'adhoc') {
return await new SetUpAdhocProvisioningProfile(app).runAsync(ctx);
return await new SetUpAdhocProvisioningProfile({ app, target }).runAsync(ctx);
} else if (enterpriseProvisioning === 'universal') {
return await new SetUpProvisioningProfile(
app,
target,
GraphQLIosDistributionType.Enterprise
).runAsync(ctx);
} else {
return await new SetUpInternalProvisioningProfile(app).runAsync(ctx);
return await new SetUpInternalProvisioningProfile({ app, target }).runAsync(ctx);
}
} else {
return await new SetUpProvisioningProfile(app, GraphQLIosDistributionType.AppStore).runAsync(
ctx
);
return await new SetUpProvisioningProfile(
app,
target,
GraphQLIosDistributionType.AppStore
).runAsync(ctx);
}
}
}
@@ -6,6 +6,7 @@ import {
testDistCertFragmentNoDependencies,
testProvisioningProfile,
testProvisioningProfileFragment,
testTarget,
testTargets,
} from '../../../__tests__/fixtures-ios';
import { MissingCredentialsNonInteractiveError } from '../../../errors';
@@ -36,6 +37,7 @@ describe('ConfigureProvisioningProfile', () => {
const appLookupParams = getAppLookupParamsFromContext(ctx, findApplicationTarget(testTargets));
const provProfConfigurator = new ConfigureProvisioningProfile(
appLookupParams,
testTarget,
testDistCertFragmentNoDependencies,
testProvisioningProfileFragment
);
@@ -53,6 +55,7 @@ describe('ConfigureProvisioningProfile', () => {
const appLookupParams = getAppLookupParamsFromContext(ctx, findApplicationTarget(testTargets));
const provProfConfigurator = new ConfigureProvisioningProfile(
appLookupParams,
testTarget,
testDistCertFragmentNoDependencies,
testProvisioningProfileFragment
);
@@ -5,6 +5,7 @@ import { createCtxMock } from '../../../__tests__/fixtures-context';
import {
testDistCertFragmentNoDependencies,
testProvisioningProfile,
testTarget,
testTargets,
} from '../../../__tests__/fixtures-ios';
import { MissingCredentialsNonInteractiveError } from '../../../errors';
@@ -28,6 +29,7 @@ describe('CreateProvisioningProfile', () => {
const appLookupParams = getAppLookupParamsFromContext(ctx, findApplicationTarget(testTargets));
const createProvProfAction = new CreateProvisioningProfile(
appLookupParams,
testTarget,
testDistCertFragmentNoDependencies
);
await createProvProfAction.runAsync(ctx);
@@ -44,6 +46,7 @@ describe('CreateProvisioningProfile', () => {
const appLookupParams = getAppLookupParamsFromContext(ctx, findApplicationTarget(testTargets));
const createProvProfAction = new CreateProvisioningProfile(
appLookupParams,
testTarget,
testDistCertFragmentNoDependencies
);
await expect(createProvProfAction.runAsync(ctx)).rejects.toThrowError(
@@ -2,6 +2,7 @@ import { IosAppBuildCredentialsFragment, IosDistributionType } from '../../../..
import { promptAsync } from '../../../../prompts';
import { getAppstoreMock, testAuthCtx } from '../../../__tests__/fixtures-appstore';
import { createCtxMock } from '../../../__tests__/fixtures-context';
import { testTarget } from '../../../__tests__/fixtures-ios';
import { getAllBuildCredentialsAsync } from '../BuildCredentialsUtils';
import { SetUpAdhocProvisioningProfile } from '../SetUpAdhocProvisioningProfile';
import { SetUpInternalProvisioningProfile } from '../SetUpInternalProvisioningProfile';
@@ -41,9 +42,12 @@ describe(SetUpInternalProvisioningProfile, () => {
return buildCredentials;
});
const action = new SetUpInternalProvisioningProfile({
account: { id: 'account-id', name: 'account-name' },
bundleIdentifier: 'com.expo.test',
projectName: 'testproject',
app: {
account: { id: 'account-id', name: 'account-name' },
bundleIdentifier: 'com.expo.test',
projectName: 'testproject',
},
target: testTarget,
});
const ctx = createCtxMock({
nonInteractive: false,
@@ -72,9 +76,12 @@ describe(SetUpInternalProvisioningProfile, () => {
});
const action = new SetUpInternalProvisioningProfile({
account: { id: 'account-id', name: 'account-name' },
bundleIdentifier: 'com.expo.test',
projectName: 'testproject',
app: {
account: { id: 'account-id', name: 'account-name' },
bundleIdentifier: 'com.expo.test',
projectName: 'testproject',
},
target: testTarget,
});
const ctx = createCtxMock({
nonInteractive: false,
@@ -110,9 +117,12 @@ describe(SetUpInternalProvisioningProfile, () => {
});
const action = new SetUpInternalProvisioningProfile({
account: { id: 'account-id', name: 'account-name' },
bundleIdentifier: 'com.expo.test',
projectName: 'testproject',
app: {
account: { id: 'account-id', name: 'account-name' },
bundleIdentifier: 'com.expo.test',
projectName: 'testproject',
},
target: testTarget,
});
const ctx = createCtxMock({
nonInteractive: false,
@@ -141,9 +151,12 @@ describe(SetUpInternalProvisioningProfile, () => {
});
const action = new SetUpInternalProvisioningProfile({
account: { id: 'account-id', name: 'account-name' },
bundleIdentifier: 'com.expo.test',
projectName: 'testproject',
app: {
account: { id: 'account-id', name: 'account-name' },
bundleIdentifier: 'com.expo.test',
projectName: 'testproject',
},
target: testTarget,
});
const ctx = createCtxMock({
nonInteractive: false,
@@ -174,9 +187,12 @@ describe(SetUpInternalProvisioningProfile, () => {
});
const action = new SetUpInternalProvisioningProfile({
account: { id: 'account-id', name: 'account-name' },
bundleIdentifier: 'com.expo.test',
projectName: 'testproject',
app: {
account: { id: 'account-id', name: 'account-name' },
bundleIdentifier: 'com.expo.test',
projectName: 'testproject',
},
target: testTarget,
});
const ctx = createCtxMock({
nonInteractive: false,
@@ -205,9 +221,12 @@ describe(SetUpInternalProvisioningProfile, () => {
});
const action = new SetUpInternalProvisioningProfile({
account: { id: 'account-id', name: 'account-name' },
bundleIdentifier: 'com.expo.test',
projectName: 'testproject',
app: {
account: { id: 'account-id', name: 'account-name' },
bundleIdentifier: 'com.expo.test',
projectName: 'testproject',
},
target: testTarget,
});
const ctx = createCtxMock({
nonInteractive: false,
@@ -235,9 +254,12 @@ describe(SetUpInternalProvisioningProfile, () => {
return buildCredentials;
});
const action = new SetUpInternalProvisioningProfile({
account: { id: 'account-id', name: 'account-name' },
bundleIdentifier: 'com.expo.test',
projectName: 'testproject',
app: {
account: { id: 'account-id', name: 'account-name' },
bundleIdentifier: 'com.expo.test',
projectName: 'testproject',
},
target: testTarget,
});
const ctx = createCtxMock({
nonInteractive: true,
@@ -253,9 +275,12 @@ describe(SetUpInternalProvisioningProfile, () => {
return buildCredentials;
});
const action = new SetUpInternalProvisioningProfile({
account: { id: 'account-id', name: 'account-name' },
bundleIdentifier: 'com.expo.test',
projectName: 'testproject',
app: {
account: { id: 'account-id', name: 'account-name' },
bundleIdentifier: 'com.expo.test',
projectName: 'testproject',
},
target: testTarget,
});
const ctx = createCtxMock({
nonInteractive: true,
@@ -269,9 +294,12 @@ describe(SetUpInternalProvisioningProfile, () => {
return buildCredentials;
});
const action = new SetUpInternalProvisioningProfile({
account: { id: 'account-id', name: 'account-name' },
bundleIdentifier: 'com.expo.test',
projectName: 'testproject',
app: {
account: { id: 'account-id', name: 'account-name' },
bundleIdentifier: 'com.expo.test',
projectName: 'testproject',
},
target: testTarget,
});
const ctx = createCtxMock({
nonInteractive: true,
@@ -291,9 +319,12 @@ describe(SetUpInternalProvisioningProfile, () => {
return buildCredentials;
});
const action = new SetUpInternalProvisioningProfile({
account: { id: 'account-id', name: 'account-name' },
bundleIdentifier: 'com.expo.test',
projectName: 'testproject',
app: {
account: { id: 'account-id', name: 'account-name' },
bundleIdentifier: 'com.expo.test',
projectName: 'testproject',
},
target: testTarget,
});
const ctx = createCtxMock({
nonInteractive: true,
@@ -10,6 +10,7 @@ import {
testAppleAppIdentifierFragment,
testCommonIosAppCredentialsFragment,
testIosAppBuildCredentialsFragment,
testTarget,
testTargets,
} from '../../../__tests__/fixtures-ios';
import { MissingCredentialsNonInteractiveError } from '../../../errors';
@@ -55,6 +56,7 @@ describe('SetUpProvisioningProfile', () => {
const appLookupParams = getAppLookupParamsFromContext(ctx, findApplicationTarget(testTargets));
const setupProvisioningProfileAction = new SetUpProvisioningProfile(
appLookupParams,
testTarget,
IosDistributionType.AppStore
);
await setupProvisioningProfileAction.runAsync(ctx);
@@ -87,6 +89,7 @@ describe('SetUpProvisioningProfile', () => {
const appLookupParams = getAppLookupParamsFromContext(ctx, findApplicationTarget(testTargets));
const setupProvisioningProfileAction = new SetUpProvisioningProfile(
appLookupParams,
testTarget,
IosDistributionType.AppStore
);
await setupProvisioningProfileAction.runAsync(ctx);
@@ -119,6 +122,7 @@ describe('SetUpProvisioningProfile', () => {
const appLookupParams = getAppLookupParamsFromContext(ctx, findApplicationTarget(testTargets));
const setupProvisioningProfileAction = new SetUpProvisioningProfile(
appLookupParams,
testTarget,
IosDistributionType.AppStore
);
await setupProvisioningProfileAction.runAsync(ctx);
@@ -147,6 +151,7 @@ describe('SetUpProvisioningProfile', () => {
const appLookupParams = getAppLookupParamsFromContext(ctx, findApplicationTarget(testTargets));
const setupProvisioningProfileAction = new SetUpProvisioningProfile(
appLookupParams,
testTarget,
IosDistributionType.AppStore
);
await setupProvisioningProfileAction.runAsync(ctx);
@@ -166,6 +171,7 @@ describe('SetUpProvisioningProfile', () => {
const appLookupParams = getAppLookupParamsFromContext(ctx, findApplicationTarget(testTargets));
const setupProvisioningProfileAction = new SetUpProvisioningProfile(
appLookupParams,
testTarget,
IosDistributionType.AppStore
);
await expect(setupProvisioningProfileAction.runAsync(ctx)).rejects.toThrowError(
@@ -1,3 +1,5 @@
import { ProfileType } from '@expo/app-store';
import Log from '../../../log';
import {
AscApiKey,
@@ -22,6 +24,7 @@ import {
isUserAuthCtx,
} from './authenticate';
import { AuthCtx, AuthenticationMode, UserAuthCtx } from './authenticateTypes';
import { ApplePlatform } from './constants';
import {
createDistributionCertificateAsync,
listDistributionCertificatesAsync,
@@ -129,16 +132,18 @@ export default class AppStoreApi {
public async listProvisioningProfilesAsync(
bundleIdentifier: string,
applePlatform: ApplePlatform,
profileClass?: ProfileClass
): Promise<ProvisioningProfileStoreInfo[]> {
const ctx = await this.ensureAuthenticatedAsync();
return await listProvisioningProfilesAsync(ctx, bundleIdentifier, profileClass);
return await listProvisioningProfilesAsync(ctx, bundleIdentifier, applePlatform, profileClass);
}
public async createProvisioningProfileAsync(
bundleIdentifier: string,
distCert: DistributionCertificate,
profileName: string,
applePlatform: ApplePlatform,
profileClass?: ProfileClass
): Promise<ProvisioningProfile> {
const ctx = await this.ensureAuthenticatedAsync();
@@ -147,29 +152,33 @@ export default class AppStoreApi {
bundleIdentifier,
distCert,
profileName,
applePlatform,
profileClass
);
}
public async revokeProvisioningProfileAsync(
bundleIdentifier: string,
applePlatform: ApplePlatform,
profileClass?: ProfileClass
): Promise<void> {
const ctx = await this.ensureAuthenticatedAsync();
return await revokeProvisioningProfileAsync(ctx, bundleIdentifier, profileClass);
return await revokeProvisioningProfileAsync(ctx, bundleIdentifier, applePlatform, profileClass);
}
public async createOrReuseAdhocProvisioningProfileAsync(
udids: string[],
bundleIdentifier: string,
distCertSerialNumber: string
distCertSerialNumber: string,
profileType: ProfileType
): Promise<ProvisioningProfile> {
const ctx = await this.ensureAuthenticatedAsync();
return await createOrReuseAdhocProvisioningProfileAsync(
ctx,
udids,
bundleIdentifier,
distCertSerialNumber
distCertSerialNumber,
profileType
);
}
@@ -1,21 +1,5 @@
import { UserRole } from '@expo/apple-utils';
export interface Device {
id: string;
teamId: string;
identifier: string;
name?: string;
model?: string;
deviceClass?: DeviceClass;
softwareVersion?: string;
enabled: boolean;
}
export enum DeviceClass {
IPHONE = 'iphone',
IPAD = 'ipad',
}
export interface DistributionCertificateStoreInfo {
id: string;
name: string;
@@ -0,0 +1,2 @@
// Renamed to avoid conflation with Android/iOS/Web Platform constants
export { Platform as ApplePlatform } from '@expo/apple-utils';
@@ -33,7 +33,7 @@ export async function getDistributionCertificateAsync(
const certificates = await Certificate.getAsync(context, {
query: {
filter: {
certificateType: CertificateType.IOS_DISTRIBUTION,
certificateType: [CertificateType.IOS_DISTRIBUTION, CertificateType.DISTRIBUTION],
},
},
});
@@ -11,6 +11,7 @@ import {
import { getRequestContext } from './authenticate';
import { AuthCtx } from './authenticateTypes';
import { getBundleIdForIdentifierAsync, getProfilesForBundleIdAsync } from './bundleId';
import { ApplePlatform } from './constants';
import { getCertificateBySerialNumberAsync, transformCertificate } from './distributionCertificate';
export enum ProfileClass {
@@ -18,7 +19,37 @@ export enum ProfileClass {
General = 'general',
}
function resolveProfileType(profileClass: ProfileClass, isEnterprise?: boolean): ProfileType {
function resolveProfileType(
applePlatform: ApplePlatform,
profileClass: ProfileClass,
isEnterprise?: boolean
): ProfileType {
switch (applePlatform) {
case ApplePlatform.IOS:
return resolveProfileTypeIos(profileClass, isEnterprise);
case ApplePlatform.TV_OS:
return resolveProfileTypeAppleTv(profileClass, isEnterprise);
case ApplePlatform.MAC_OS:
throw new Error(`${applePlatform} profiles are not supported`);
}
}
function resolveProfileTypeAppleTv(
profileClass: ProfileClass,
isEnterprise?: boolean
): ProfileType {
if (isEnterprise) {
return profileClass === ProfileClass.Adhoc
? ProfileType.TVOS_APP_ADHOC
: ProfileType.TVOS_APP_INHOUSE;
} else {
return profileClass === ProfileClass.Adhoc
? ProfileType.TVOS_APP_ADHOC
: ProfileType.TVOS_APP_STORE;
}
}
function resolveProfileTypeIos(profileClass: ProfileClass, isEnterprise?: boolean): ProfileType {
if (isEnterprise) {
return profileClass === ProfileClass.Adhoc
? ProfileType.IOS_APP_ADHOC
@@ -141,12 +172,13 @@ export async function useExistingProvisioningProfileAsync(
export async function listProvisioningProfilesAsync(
authCtx: AuthCtx,
bundleIdentifier: string,
applePlatform: ApplePlatform,
profileClass: ProfileClass = ProfileClass.General
): Promise<ProvisioningProfileStoreInfo[]> {
const spinner = ora(`Fetching Apple provisioning profiles`).start();
try {
const context = getRequestContext(authCtx);
const profileType = resolveProfileType(profileClass, authCtx.team.inHouse);
const profileType = resolveProfileType(applePlatform, profileClass, authCtx.team.inHouse);
const profiles = (await getProfilesForBundleIdAsync(context, bundleIdentifier)).filter(
profile => profile.attributes.profileType === profileType
);
@@ -168,6 +200,7 @@ export async function createProvisioningProfileAsync(
bundleIdentifier: string,
distCert: DistributionCertificate,
profileName: string,
applePlatform: ApplePlatform,
profileClass: ProfileClass = ProfileClass.General
): Promise<ProvisioningProfile> {
const spinner = ora(`Creating Apple provisioning profile`).start();
@@ -180,7 +213,7 @@ export async function createProvisioningProfileAsync(
}
const context = getRequestContext(authCtx);
const profileType = resolveProfileType(profileClass, authCtx.team.inHouse);
const profileType = resolveProfileType(applePlatform, profileClass, authCtx.team.inHouse);
const certificate = await getCertificateBySerialNumberAsync(
context,
@@ -210,6 +243,7 @@ export async function createProvisioningProfileAsync(
export async function revokeProvisioningProfileAsync(
authCtx: AuthCtx,
bundleIdentifier: string,
applePlatform: ApplePlatform,
profileClass: ProfileClass = ProfileClass.General
): Promise<void> {
const spinner = ora(`Revoking Apple provisioning profile`).start();
@@ -217,7 +251,7 @@ export async function revokeProvisioningProfileAsync(
const context = getRequestContext(authCtx);
const profiles = await getProfilesForBundleIdAsync(context, bundleIdentifier);
const profileType = resolveProfileType(profileClass, authCtx.team.inHouse);
const profileType = resolveProfileType(applePlatform, profileClass, authCtx.team.inHouse);
await Promise.all(
profiles
.filter(profile => profile.attributes.profileType === profileType)
@@ -25,10 +25,8 @@ async function registerMissingDevicesAsync(
context: RequestContext,
udids: string[]
): Promise<Device[]> {
const allIosProfileDevices = await Device.getAllIOSProfileDevicesAsync(context);
const alreadyAdded = allIosProfileDevices.filter(device =>
udids.includes(device.attributes.udid)
);
const allDevices = await Device.getAsync(context);
const alreadyAdded = allDevices.filter(device => udids.includes(device.attributes.udid));
const alreadyAddedUdids = alreadyAdded.map(i => i.attributes.udid);
await Promise.all(
@@ -46,17 +44,20 @@ async function registerMissingDevicesAsync(
return alreadyAdded;
}
async function findProfileByBundleIdAsync(
async function findProfileAsync(
context: RequestContext,
bundleId: string,
certSerialNumber: string
{
bundleId,
certSerialNumber,
profileType,
}: { bundleId: string; certSerialNumber: string; profileType: ProfileType }
): Promise<{
profile: Profile | null;
didUpdate: boolean;
}> {
const expoProfiles = (await getProfilesForBundleIdAsync(context, bundleId)).filter(profile => {
return (
profile.attributes.profileType === ProfileType.IOS_APP_ADHOC &&
profile.attributes.profileType === profileType &&
profile.attributes.name.startsWith('*[expo]') &&
profile.attributes.profileState !== ProfileState.EXPIRED
);
@@ -132,11 +133,13 @@ async function manageAdHocProfilesAsync(
bundleId,
certSerialNumber,
profileId,
profileType,
}: {
udids: string[];
bundleId: string;
certSerialNumber: string;
profileId?: string;
profileType: ProfileType;
}
): Promise<ProfileResults> {
// We register all missing devices on the Apple Developer Portal. They are identified by UDIDs.
@@ -155,7 +158,7 @@ async function manageAdHocProfilesAsync(
}
} else {
// If no profile id is passed, try to find a suitable provisioning profile for the App ID.
const results = await findProfileByBundleIdAsync(context, bundleId, certSerialNumber);
const results = await findProfileAsync(context, { bundleId, certSerialNumber, profileType });
existingProfile = results.profile;
didUpdate = results.didUpdate;
}
@@ -192,8 +195,9 @@ async function manageAdHocProfilesAsync(
await existingProfile.regenerateAsync();
}
const updatedProfile = (await findProfileByBundleIdAsync(context, bundleId, certSerialNumber))
.profile;
const updatedProfile = (
await findProfileAsync(context, { bundleId, certSerialNumber, profileType })
).profile;
if (!updatedProfile) {
throw new Error(
`Failed to locate updated profile for bundle identifier "${bundleId}" and serial number "${certSerialNumber}"`
@@ -226,7 +230,7 @@ async function manageAdHocProfilesAsync(
name: `*[expo] ${bundleId} AdHoc ${Date.now()}`,
certificates: [distributionCertificate.id],
devices: devices.map(device => device.id),
profileType: ProfileType.IOS_APP_ADHOC,
profileType,
});
return {
@@ -242,7 +246,8 @@ export async function createOrReuseAdhocProvisioningProfileAsync(
authCtx: AuthCtx,
udids: string[],
bundleIdentifier: string,
distCertSerialNumber: string
distCertSerialNumber: string,
profileType: ProfileType
): Promise<ProvisioningProfile> {
const spinner = ora(`Handling Apple ad hoc provisioning profiles`).start();
try {
@@ -252,6 +257,7 @@ export async function createOrReuseAdhocProvisioningProfileAsync(
udids,
bundleId: bundleIdentifier,
certSerialNumber: distCertSerialNumber,
profileType,
});
if (didCreate) {
@@ -6,14 +6,17 @@ import nullthrows from 'nullthrows';
import { IosAppBuildCredentialsFragment, IosDistributionType } from '../../../graphql/generated';
import Log from '../../../log';
import { getApplePlatformFromSdkRoot } from '../../../project/ios/target';
import { CredentialsContext } from '../../context';
import { AppLookupParams } from '../api/GraphqlClient';
import { ProfileClass } from '../appstore/provisioningProfile';
import { Target } from '../types';
import { getP12CertFingerprint } from '../utils/p12Certificate';
import { parse as parseProvisioningProfile } from '../utils/provisioningProfile';
export async function validateProvisioningProfileAsync(
ctx: CredentialsContext,
target: Target,
app: AppLookupParams,
buildCredentials: Partial<IosAppBuildCredentialsFragment> | null
): Promise<boolean> {
@@ -37,7 +40,7 @@ export async function validateProvisioningProfileAsync(
return true;
}
return await validateProvisioningProfileWithAppleAsync(ctx, app, buildCredentials);
return await validateProvisioningProfileWithAppleAsync(ctx, target, app, buildCredentials);
}
function validateProvisioningProfileWithoutApple(
@@ -84,14 +87,17 @@ function validateProvisioningProfileWithoutApple(
async function validateProvisioningProfileWithAppleAsync(
ctx: CredentialsContext,
target: Target,
app: AppLookupParams,
buildCredentials: Partial<IosAppBuildCredentialsFragment>
): Promise<boolean> {
assert(buildCredentials.provisioningProfile, 'Provisioning Profile must be defined');
const { developerPortalIdentifier, provisioningProfile } = buildCredentials.provisioningProfile;
const applePlatform = await getApplePlatformFromSdkRoot(target);
const profilesFromApple = await ctx.appStore.listProvisioningProfilesAsync(
app.bundleIdentifier,
applePlatform,
buildCredentials.iosDistributionType === IosDistributionType.AdHoc
? ProfileClass.Adhoc
: ProfileClass.General
@@ -258,6 +258,7 @@ export class ManageIos {
}
await this.setupProvisioningProfileWithSpecificDistCertAsync(
ctx,
target,
appLookupParams,
distCert,
distributionType
@@ -274,6 +275,7 @@ export class ManageIos {
if (confirm) {
await this.setupProvisioningProfileWithSpecificDistCertAsync(
ctx,
target,
appLookupParams,
distCert,
distributionType
@@ -377,6 +379,7 @@ export class ManageIos {
private async setupProvisioningProfileWithSpecificDistCertAsync(
ctx: CredentialsContext,
target: Target,
appLookupParams: AppLookupParams,
distCert: AppleDistributionCertificateFragment,
distributionType: IosDistributionTypeGraphql
@@ -384,12 +387,14 @@ export class ManageIos {
Log.log(`Setting up ${appLookupParams.projectName} to use Distribution Certificate`);
Log.log(`Creating provisioning profile...`);
if (distributionType === IosDistributionTypeGraphql.AdHoc) {
return await new SetUpAdhocProvisioningProfile(
appLookupParams
).runWithDistributionCertificateAsync(ctx, distCert);
return await new SetUpAdhocProvisioningProfile({
app: appLookupParams,
target,
}).runWithDistributionCertificateAsync(ctx, distCert);
} else {
return await new SetUpProvisioningProfile(
appLookupParams,
target,
distributionType
).createAndAssignProfileAsync(ctx, distCert);
}
@@ -93,11 +93,13 @@ async function findUnregisteredPortalDevicesAsync(
return acc;
}, {} as Record<string, AppleDeviceFragmentWithAppleTeam>);
const portalDevices = await Device.getAllIOSProfileDevicesAsync(getRequestContext(appleAuthCtx));
const portalDevices = await Device.getAsync(getRequestContext(appleAuthCtx));
return portalDevices.filter(
portalDevice =>
!(portalDevice.attributes.udid in expoRegisteredDevicesByUdid) &&
[DeviceClass.IPAD, DeviceClass.IPHONE].includes(portalDevice.attributes.deviceClass)
[DeviceClass.IPAD, DeviceClass.IPHONE, DeviceClass.APPLE_TV].includes(
portalDevice.attributes.deviceClass
)
);
}
+46
View File
@@ -779,7 +779,10 @@ export type AndroidJobBuildCredentialsInput = {
};
export type AndroidJobInput = {
applicationArchivePath?: InputMaybe<Scalars['String']>;
/** @deprecated */
artifactPath?: InputMaybe<Scalars['String']>;
buildArtifactPaths?: InputMaybe<Array<Scalars['String']>>;
buildType?: InputMaybe<AndroidBuildType>;
builderEnvironment?: InputMaybe<AndroidBuilderEnvironmentInput>;
cache?: InputMaybe<BuildCacheInput>;
@@ -804,7 +807,10 @@ export type AndroidJobKeystoreInput = {
};
export type AndroidJobOverridesInput = {
applicationArchivePath?: InputMaybe<Scalars['String']>;
/** @deprecated */
artifactPath?: InputMaybe<Scalars['String']>;
buildArtifactPaths?: InputMaybe<Array<Scalars['String']>>;
buildType?: InputMaybe<AndroidBuildType>;
builderEnvironment?: InputMaybe<AndroidBuilderEnvironmentInput>;
cache?: InputMaybe<BuildCacheInput>;
@@ -980,6 +986,8 @@ export type App = Project & {
updateChannelByName?: Maybe<UpdateChannel>;
/** EAS channels owned by an app */
updateChannels: Array<UpdateChannel>;
/** EAS updates owned by an app grouped by update group */
updateGroups: Array<Array<Update>>;
/** Time of last classic update publish */
updated: Scalars['DateTime'];
/** EAS updates owned by an app */
@@ -996,6 +1004,7 @@ export type App = Project & {
/** Represents an Exponent App (or Experience in legacy terms) */
export type AppActivityTimelineProjectActivitiesArgs = {
createdBefore?: InputMaybe<Scalars['DateTime']>;
filterChannels?: InputMaybe<Array<Scalars['String']>>;
filterPlatforms?: InputMaybe<Array<AppPlatform>>;
filterReleaseChannels?: InputMaybe<Array<Scalars['String']>>;
filterTypes?: InputMaybe<Array<ActivityTimelineProjectActivityType>>;
@@ -1117,6 +1126,14 @@ export type AppUpdateChannelsArgs = {
};
/** Represents an Exponent App (or Experience in legacy terms) */
export type AppUpdateGroupsArgs = {
filter?: InputMaybe<UpdatesFilter>;
limit: Scalars['Int'];
offset: Scalars['Int'];
};
/** Represents an Exponent App (or Experience in legacy terms) */
export type AppUpdatesArgs = {
limit: Scalars['Int'];
@@ -1781,6 +1798,8 @@ export type BuildArtifact = {
export type BuildArtifacts = {
__typename?: 'BuildArtifacts';
applicationArchiveUrl?: Maybe<Scalars['String']>;
buildArtifactsUrl?: Maybe<Scalars['String']>;
buildUrl?: Maybe<Scalars['String']>;
xcodeBuildLogsUrl?: Maybe<Scalars['String']>;
};
@@ -2293,6 +2312,11 @@ export type DeleteWebhookResult = {
id: Scalars['ID'];
};
export type DeployServerlessFunctionResult = {
__typename?: 'DeployServerlessFunctionResult';
url: Scalars['String'];
};
/** Represents a Deployment - a set of Builds with the same Runtime Version and Channel */
export type Deployment = {
__typename?: 'Deployment';
@@ -2722,7 +2746,10 @@ export type IosJobDistributionCertificateInput = {
};
export type IosJobInput = {
applicationArchivePath?: InputMaybe<Scalars['String']>;
/** @deprecated */
artifactPath?: InputMaybe<Scalars['String']>;
buildArtifactPaths?: InputMaybe<Array<Scalars['String']>>;
buildConfiguration?: InputMaybe<Scalars['String']>;
/** @deprecated */
buildType?: InputMaybe<IosBuildType>;
@@ -2745,7 +2772,10 @@ export type IosJobInput = {
};
export type IosJobOverridesInput = {
applicationArchivePath?: InputMaybe<Scalars['String']>;
/** @deprecated */
artifactPath?: InputMaybe<Scalars['String']>;
buildArtifactPaths?: InputMaybe<Array<Scalars['String']>>;
buildConfiguration?: InputMaybe<Scalars['String']>;
/** @deprecated */
buildType?: InputMaybe<IosBuildType>;
@@ -3086,6 +3116,7 @@ export type ProjectQueryByUsernameAndSlugArgs = {
export type PublicArtifacts = {
__typename?: 'PublicArtifacts';
applicationArchiveUrl?: Maybe<Scalars['String']>;
buildUrl?: Maybe<Scalars['String']>;
};
@@ -3410,10 +3441,17 @@ export type ServerlessFunctionIdentifierInput = {
export type ServerlessFunctionMutation = {
__typename?: 'ServerlessFunctionMutation';
createDeployment: DeployServerlessFunctionResult;
createUploadPresignedUrl: CreateServerlessFunctionUploadUrlResult;
};
export type ServerlessFunctionMutationCreateDeploymentArgs = {
appId: Scalars['ID'];
serverlessFunctionIdentifierInput: ServerlessFunctionIdentifierInput;
};
export type ServerlessFunctionMutationCreateUploadPresignedUrlArgs = {
appId: Scalars['ID'];
serverlessFunctionIdentifierInput: ServerlessFunctionIdentifierInput;
@@ -3736,11 +3774,19 @@ export type UpdateBranch = {
createdAt: Scalars['DateTime'];
id: Scalars['ID'];
name: Scalars['String'];
updateGroups: Array<Array<Update>>;
updatedAt: Scalars['DateTime'];
updates: Array<Update>;
};
export type UpdateBranchUpdateGroupsArgs = {
filter?: InputMaybe<UpdatesFilter>;
limit: Scalars['Int'];
offset: Scalars['Int'];
};
export type UpdateBranchUpdatesArgs = {
filter?: InputMaybe<UpdatesFilter>;
limit: Scalars['Int'];
@@ -0,0 +1,33 @@
import { testTarget } from '../../../credentials/__tests__/fixtures-ios';
import { ApplePlatform } from '../../../credentials/ios/appstore/constants';
import { getApplePlatformFromSdkRoot } from '../target';
function getApplePlatform(sdkRoot: string): ApplePlatform {
const target = {
...testTarget,
buildSettings: {
SDKROOT: sdkRoot,
},
};
return getApplePlatformFromSdkRoot(target);
}
describe(getApplePlatformFromSdkRoot, () => {
// Update `getApplePlatformFromSdkRoot` to be compatible with new Apple Platforms
test('all enumerations work with the function', () => {
expect(Object.values(ApplePlatform).sort()).toEqual(
[ApplePlatform.IOS, ApplePlatform.TV_OS, ApplePlatform.MAC_OS].sort()
);
});
test('existing SDKs work with the function', () => {
// sdks from `xcodebuild -showsdks`
expect(getApplePlatform('iphoneos14.4')).toBe(ApplePlatform.IOS);
expect(getApplePlatform('iphonesimulator14.4')).toBe(ApplePlatform.IOS);
expect(getApplePlatform('driverkit.macosx20.2 ')).toBe(ApplePlatform.MAC_OS);
expect(getApplePlatform('macosx11.1')).toBe(ApplePlatform.MAC_OS);
expect(getApplePlatform('appletvos14.3')).toBe(ApplePlatform.TV_OS);
expect(getApplePlatform('appletvsimulator14.3')).toBe(ApplePlatform.IOS);
expect(getApplePlatform('watchos7.2')).toBe(ApplePlatform.IOS);
expect(getApplePlatform('watchsimulator7.2')).toBe(ApplePlatform.IOS);
});
});
@@ -5,6 +5,7 @@ import { JSONObject } from '@expo/json-file';
import Joi from 'joi';
import type { XCBuildConfiguration } from 'xcode';
import { ApplePlatform } from '../../credentials/ios/appstore/constants';
import { Target } from '../../credentials/ios/types';
import { resolveWorkflowAsync } from '../workflow';
import { getBundleIdentifierAsync } from './bundleIdentifier';
@@ -226,3 +227,23 @@ function resolveBareProjectBuildSettings(
});
return xcBuildConfiguration?.buildSettings ?? {};
}
/**
* Get Apple Platform from the Xcode SDKROOT where possible.
* @returns - Apple Platform when known, defaults to IOS when unknown
*/
export function getApplePlatformFromSdkRoot(target: Target): ApplePlatform {
const sdkRoot = target.buildSettings?.SDKROOT;
if (!sdkRoot) {
return ApplePlatform.IOS;
}
if (sdkRoot.includes('iphoneos')) {
return ApplePlatform.IOS;
} else if (sdkRoot.includes('tvos')) {
return ApplePlatform.TV_OS;
} else if (sdkRoot.includes('macosx')) {
return ApplePlatform.MAC_OS;
} else {
return ApplePlatform.IOS;
}
}
+3 -1
View File
@@ -22,10 +22,12 @@ export async function resolveWorkflowAsync(
return Workflow.MANAGED;
}
const vcsClient = getVcsClient();
const vcsRootPath = path.normalize(await vcsClient.getRootPathAsync());
for (const marker of platformWorkflowMarkers) {
if (
(await fs.pathExists(marker)) &&
!(await getVcsClient().isFileIgnoredAsync(path.relative(projectDir, marker)))
!(await vcsClient.isFileIgnoredAsync(path.relative(vcsRootPath, marker)))
) {
return Workflow.GENERIC;
}
+14 -11
View File
@@ -2,6 +2,7 @@ import * as PackageManagerUtils from '@expo/package-manager';
import spawnAsync from '@expo/spawn-async';
import { Errors } from '@oclif/core';
import chalk from 'chalk';
import path from 'path';
import Log, { learnMore } from '../../log';
import { ora } from '../../ora';
@@ -16,7 +17,7 @@ import {
import { Client } from '../vcs';
export default class GitClient extends Client {
public async ensureRepoExistsAsync(): Promise<void> {
public override async ensureRepoExistsAsync(): Promise<void> {
if (!(await isGitInstalledAsync())) {
Log.error(
`${chalk.bold('git')} command not found. Install it before proceeding or set ${chalk.bold(
@@ -58,7 +59,7 @@ export default class GitClient extends Client {
await this.commitAsync({ commitAllFiles: true, commitMessage: message });
}
public async commitAsync({
public override async commitAsync({
commitMessage,
commitAllFiles,
nonInteractive = false,
@@ -86,11 +87,11 @@ export default class GitClient extends Client {
}
}
public async isCommitRequiredAsync(): Promise<boolean> {
public override async isCommitRequiredAsync(): Promise<boolean> {
return await this.hasUncommittedChangesAsync();
}
public async hasUncommittedChangesAsync(): Promise<boolean> {
public override async hasUncommittedChangesAsync(): Promise<boolean> {
const changes = await gitStatusAsync({ showUntracked: true });
return changes.length > 0;
}
@@ -143,7 +144,7 @@ export default class GitClient extends Client {
}
}
public async getCommitHashAsync(): Promise<string | undefined> {
public override async getCommitHashAsync(): Promise<string | undefined> {
try {
return (await spawnAsync('git', ['rev-parse', 'HEAD'])).stdout.trim();
} catch {
@@ -151,11 +152,11 @@ export default class GitClient extends Client {
}
}
public async trackFileAsync(file: string): Promise<void> {
public override async trackFileAsync(file: string): Promise<void> {
await spawnAsync('git', ['add', '--intent-to-add', file]);
}
public async getBranchNameAsync(): Promise<string | null> {
public override async getBranchNameAsync(): Promise<string | null> {
try {
return (await spawnAsync('git', ['rev-parse', '--abbrev-ref', 'HEAD'])).stdout.trim();
} catch {
@@ -163,7 +164,7 @@ export default class GitClient extends Client {
}
}
public async getLastCommitMessageAsync(): Promise<string | null> {
public override async getLastCommitMessageAsync(): Promise<string | null> {
try {
return (await spawnAsync('git', ['--no-pager', 'log', '-1', '--pretty=%B'])).stdout.trim();
} catch {
@@ -171,7 +172,7 @@ export default class GitClient extends Client {
}
}
public async showDiffAsync(): Promise<void> {
public override async showDiffAsync(): Promise<void> {
const outputTooLarge = (await getGitDiffOutputAsync()).split(/\r\n|\r|\n/).length > 100;
await gitDiffAsync({ withPager: outputTooLarge });
}
@@ -186,9 +187,11 @@ export default class GitClient extends Client {
);
}
public async isFileIgnoredAsync(filePath: string): Promise<boolean> {
public override async isFileIgnoredAsync(filePath: string): Promise<boolean> {
try {
await spawnAsync('git', ['check-ignore', '-q', filePath]);
await spawnAsync('git', ['check-ignore', '-q', filePath], {
cwd: path.normalize(await this.getRootPathAsync()),
});
return true;
} catch {
return false;
@@ -7,28 +7,29 @@ import { Ignore, makeShallowCopyAsync } from '../local';
import GitClient from './git';
export default class GitNoCommitClient extends GitClient {
public async isCommitRequiredAsync(): Promise<boolean> {
public override async isCommitRequiredAsync(): Promise<boolean> {
return false;
}
public async getRootPathAsync(): Promise<string> {
public override async getRootPathAsync(): Promise<string> {
return (await spawnAsync('git', ['rev-parse', '--show-toplevel'])).stdout.trim();
}
public async makeShallowCopyAsync(destinationPath: string): Promise<void> {
public override async makeShallowCopyAsync(destinationPath: string): Promise<void> {
// normalize converts C:/some/path to C:\some\path on windows
const srcPath = path.normalize(await this.getRootPathAsync());
await makeShallowCopyAsync(srcPath, destinationPath);
}
public async isFileIgnoredAsync(filePath: string): Promise<boolean> {
public override async isFileIgnoredAsync(filePath: string): Promise<boolean> {
// normalize converts C:/some/path to C:\some\path on windows
const ignore = new Ignore(await this.getRootPathAsync());
const rootPath = path.normalize(await this.getRootPathAsync());
const ignore = new Ignore(rootPath);
await ignore.initIgnoreAsync();
return ignore.ignores(filePath);
}
public async trackFileAsync(file: string): Promise<void> {
public override async trackFileAsync(file: string): Promise<void> {
try {
await super.trackFileAsync(file);
} catch {
+1 -1
View File
@@ -11,7 +11,7 @@ export default class NoVcsClient extends Client {
await makeShallowCopyAsync(srcPath, destinationPath);
}
public async isFileIgnoredAsync(filePath: string): Promise<boolean> {
public override async isFileIgnoredAsync(filePath: string): Promise<boolean> {
const ignore = new Ignore(getRootPath());
await ignore.initIgnoreAsync();
return ignore.ignores(filePath);
+4 -2
View File
@@ -4,9 +4,11 @@
"importHelpers": true,
"module": "commonjs",
"esModuleInterop": true,
"noFallthroughCasesInSwitch": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noUnusedParameters":true,
"noUnusedLocals":true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"strict": true,
"target": "ES2019",
"outDir": "build",
+2 -2
View File
@@ -1,11 +1,11 @@
{
"name": "@expo/eas-json",
"description": "A library for interacting with eas.json",
"version": "1.2.0",
"version": "2.1.0",
"author": "Expo <[email protected]>",
"bugs": "https://github.com/expo/eas-cli/issues",
"dependencies": {
"@expo/eas-build-job": "0.2.85",
"@expo/eas-build-job": "0.2.90",
"@expo/json-file": "8.2.36",
"chalk": "4.1.2",
"env-string": "1.0.1",
+24 -5
View File
@@ -38,7 +38,7 @@
"When using remote, the `autoIncrement` is based on the values stored on EAS servers."
]
},
"promptToConfigurePushNotfications" : {
"promptToConfigurePushNotifications" : {
"type": "boolean",
"description": "Specifies where EAS CLI should prompt to configure Push Notifications credentials. Defaults to true.",
"default": true
@@ -168,6 +168,14 @@
"markdownDescription": "When enabled, for iOS, bumps the last component of `expo.ios.buildNumber` (e.g. `1.2.3.39` -> `1.2.3.40`) and for Android, bumps `expo.android.versionCode` (e.g. `3` -> `4`).",
"default": false
},
"buildArtifactPaths": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of paths (or patterns) where EAS Build is going to look for the build artifacts. Use `applicationArchivePath` to specify the path for uploading the application archive. Build artifacts are uploaded even if the build fails. See: https://github.com/mrmlnc/fast-glob#pattern-syntax",
"markdownDescription": "List of paths (or patterns) where EAS Build is going to look for the build artifacts. Use `applicationArchivePath` to specify the path for uploading the application archive. Build artifacts are uploaded even if the build fails. EAS Build uses the `fast-glob` npm package for pattern matching ([see their README to learn more about the syntax you can use](https://github.com/mrmlnc/fast-glob#pattern-syntax))."
},
"android": {
"$ref": "#/definitions/BuildProfileAndroid"
},
@@ -244,10 +252,16 @@
"description": "Gradle task that will be used to build your project, e.g. `:app:assembleDebug` to build a debug binary.",
"markdownDescription": "Gradle task that will be used to build your project, e.g. `:app:assembleDebug` to build a debug binary.\n\nIt's not recommended unless you need to run a task that `buildType` does not support, it takes priority over `buildType` and `developmentClient`."
},
"applicationArchivePath": {
"type": "string",
"description": "Path (or pattern) where EAS Build is going to look for the application archive. See: https://github.com/mrmlnc/fast-glob#pattern-syntax",
"markdownDescription": "Path (or pattern) where EAS Build is going to look for the application archive. EAS Build uses the `fast-glob` npm package for pattern matching ([see their README to learn more about the syntax you can use](https://github.com/mrmlnc/fast-glob#pattern-syntax)).",
"default": "android/app/build/outputs/**/*.{apk,aab}"
},
"artifactPath": {
"type": "string",
"description": "Path (or pattern) where EAS Build is going to look for the build artifacts. See: https://github.com/mrmlnc/fast-glob#pattern-syntax",
"markdownDescription": "Path (or pattern) where EAS Build is going to look for the build artifacts. EAS Build uses the `fast-glob` npm package for pattern matching ([see their README to learn more about the syntax you can use](https://github.com/mrmlnc/fast-glob#pattern-syntax)).",
"description": "[DEPRECATED] Use `applicationArchivePath` instead. Path (or pattern) where EAS Build is going to look for the build artifacts. See: https://github.com/mrmlnc/fast-glob#pattern-syntax",
"markdownDescription": "[DEPRECATED] Use `applicationArchivePath` instead. Path (or pattern) where EAS Build is going to look for the build artifacts. EAS Build uses the `fast-glob` npm package for pattern matching ([see their README to learn more about the syntax you can use](https://github.com/mrmlnc/fast-glob#pattern-syntax)).",
"default": "android/app/build/outputs/**/*.{apk,aab}"
}
}
@@ -332,10 +346,15 @@
"description": "Xcode project's Build Configuration.",
"markdownDescription": "Xcode project's Build Configuration.\n- managed project: \"Release\" or \"Debug\", defaults to \"Release\"\n- bare project: defaults to the value specified in the scheme\n\nIt takes priority over `developmentClient` field."
},
"applicationArchivePath": {
"type": "string",
"description": "Path (or pattern) where EAS Build is going to look for the application archive. See: https://github.com/mrmlnc/fast-glob#pattern-syntax",
"markdownDescription": "Path (or pattern) where EAS Build is going to look for the application archive.\n\nEAS Build uses the `fast-glob` npm package for pattern matching, ([See their README to learn more about the syntax you can use](https://github.com/mrmlnc/fast-glob#pattern-syntax)).\n\nYou should modify that path only if you are using a custom `Gymfile`.\n\nThe default is `ios/build/Build/Products/*-iphonesimulator/*.app` when building for simulator and `ios/build/*.ipa` in other cases."
},
"artifactPath": {
"type": "string",
"description": "Path (or pattern) where EAS Build is going to look for the build artifacts. See: https://github.com/mrmlnc/fast-glob#pattern-syntax",
"markdownDescription": "Path (or pattern) where EAS Build is going to look for the build artifacts.\n\nEAS Build uses the `fast-glob` npm package for pattern matching, ([See their README to learn more about the syntax you can use](https://github.com/mrmlnc/fast-glob#pattern-syntax)).\n\nYou should modify that path only if you are using a custom `Gymfile`.\n\nThe default is `ios/build/Build/Products/*-iphonesimulator/*.app` when building for simulator and `ios/build/*.ipa` in other cases."
"description": "[DEPRECATED] Use `applicationArchivePath` instead. Path (or pattern) where EAS Build is going to look for the build artifacts. See: https://github.com/mrmlnc/fast-glob#pattern-syntax",
"markdownDescription": "[DEPRECATED] Use `applicationArchivePath` instead. Path (or pattern) where EAS Build is going to look for the build artifacts.\n\nEAS Build uses the `fast-glob` npm package for pattern matching, ([See their README to learn more about the syntax you can use](https://github.com/mrmlnc/fast-glob#pattern-syntax)).\n\nYou should modify that path only if you are using a custom `Gymfile`.\n\nThe default is `ios/build/Build/Products/*-iphonesimulator/*.app` when building for simulator and `ios/build/*.ipa` in other cases."
}
}
},
+7 -2
View File
@@ -17,6 +17,7 @@ const CommonBuildProfileSchema = Joi.object({
channel: Joi.string().regex(/^[a-z\d][a-z\d._-]*$/),
developmentClient: Joi.boolean(),
prebuildCommand: Joi.string(),
buildArtifactPaths: Joi.array().items(Joi.string()),
node: Joi.string().empty(null).custom(semverCheck),
yarn: Joi.string().empty(null).custom(semverCheck),
@@ -39,10 +40,12 @@ const AndroidBuildProfileSchema = CommonBuildProfileSchema.concat(
),
artifactPath: Joi.string(),
applicationArchivePath: Joi.string(),
buildArtifactPaths: Joi.array().items(Joi.string()),
gradleCommand: Joi.string(),
buildType: Joi.string().valid('apk', 'app-bundle'),
})
}).oxor('artifactPath', 'applicationArchivePath')
);
const IosBuildProfileSchema = CommonBuildProfileSchema.concat(
@@ -62,9 +65,11 @@ const IosBuildProfileSchema = CommonBuildProfileSchema.concat(
cocoapods: Joi.string().empty(null).custom(semverCheck),
artifactPath: Joi.string(),
applicationArchivePath: Joi.string(),
buildArtifactPaths: Joi.array().items(Joi.string()),
scheme: Joi.string(),
buildConfiguration: Joi.string(),
})
}).oxor('artifactPath', 'applicationArchivePath')
);
export const BuildProfileSchema = CommonBuildProfileSchema.concat(
+9
View File
@@ -22,6 +22,7 @@ export interface CommonBuildProfile {
developmentClient?: boolean;
prebuildCommand?: string;
autoIncrement?: boolean;
buildArtifactPaths?: string[];
node?: string;
yarn?: string;
@@ -38,7 +39,11 @@ export interface AndroidBuildProfile extends Omit<CommonBuildProfile, 'autoIncre
buildType?: Android.BuildType.APK | Android.BuildType.APP_BUNDLE;
gradleCommand?: string;
/**
* @deprecated use applicationArchivePath
*/
artifactPath?: string;
applicationArchivePath?: string;
}
export interface IosBuildProfile extends Omit<CommonBuildProfile, 'autoIncrement'> {
@@ -50,7 +55,11 @@ export interface IosBuildProfile extends Omit<CommonBuildProfile, 'autoIncrement
fastlane?: string;
cocoapods?: string;
/**
* @deprecated use applicationArchivePath
*/
artifactPath?: string;
applicationArchivePath?: string;
scheme?: string;
buildConfiguration?: string;
}
Loaded 100 of 105 files, more files were not shown because too many files have changed in this diff. Show more