mirror of
https://github.com/expo/eas-cli.git
synced 2026-11-14 10:08:06 -10:00
Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc320de954 | ||
|
|
d24c686133 | ||
|
|
118c008917 | ||
|
|
3b24d37f3c | ||
|
|
df425201b3 | ||
|
|
9636507130 | ||
|
|
2dd50ad21a | ||
|
|
30441b3db4 | ||
|
|
789c314a8d | ||
|
|
4760314ddf | ||
|
|
c8e57f000c | ||
|
|
3c82a2f8a8 |
No files matched your search
@@ -10,6 +10,32 @@ This is the log of notable changes to EAS CLI and related packages.
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
- Load iOS entitlements from prebuild config when `./ios` is gitignored. ([#1852](https://github.com/expo/eas-cli/pull/1852) by [@byCedric](https://github.com/byCedric))
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Short format for selecting devices prompt. ([#1840](https://github.com/expo/eas-cli/pull/1840) by [@khamilowicz](https://github.com/khamilowicz))
|
||||
|
||||
## [3.13.0](https://github.com/expo/eas-cli/releases/tag/v3.13.0) - 2023-05-17
|
||||
|
||||
### 🎉 New features
|
||||
|
||||
- Add clear cache flag to eas update. ([#1839](https://github.com/expo/eas-cli/pull/1839) by [@quinlanj](https://github.com/quinlanj))
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
- Fix building iOS projects with framework targets. ([#1835](https://github.com/expo/eas-cli/pull/1835) by [@dsokal](https://github.com/dsokal))
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Ignore dirty workingdir when building from GitHub. ([#1842](https://github.com/expo/eas-cli/pull/1842) by [@wkozyra95](https://github.com/wkozyra95))
|
||||
- Remove App Specific Password prompt. ([#1843](https://github.com/expo/eas-cli/pull/1843) by [@quinlanj](https://github.com/quinlanj))
|
||||
- Validate `CFBundleShortVersionString`. ([#1846](https://github.com/expo/eas-cli/pull/1846) by [@khamilowicz](https://github.com/khamilowicz))
|
||||
|
||||
## [3.12.1](https://github.com/expo/eas-cli/releases/tag/v3.12.1) - 2023-05-15
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
- Don't submit expired builds. ([#1837](https://github.com/expo/eas-cli/pull/1837) by [@dsokal](https://github.com/dsokal))
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true,
|
||||
"version": "3.12.1",
|
||||
"version": "3.13.0",
|
||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json"
|
||||
}
|
||||
+58
-57
@@ -133,7 +133,7 @@ ALIASES
|
||||
$ eas login
|
||||
```
|
||||
|
||||
_See code: [src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/account/login.ts)_
|
||||
_See code: [src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/account/login.ts)_
|
||||
|
||||
## `eas account:logout`
|
||||
|
||||
@@ -150,7 +150,7 @@ ALIASES
|
||||
$ eas logout
|
||||
```
|
||||
|
||||
_See code: [src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/account/logout.ts)_
|
||||
_See code: [src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/account/logout.ts)_
|
||||
|
||||
## `eas account:view`
|
||||
|
||||
@@ -167,7 +167,7 @@ ALIASES
|
||||
$ eas whoami
|
||||
```
|
||||
|
||||
_See code: [src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/account/view.ts)_
|
||||
_See code: [src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/account/view.ts)_
|
||||
|
||||
## `eas analytics [STATUS]`
|
||||
|
||||
@@ -181,7 +181,7 @@ DESCRIPTION
|
||||
display or change analytics settings
|
||||
```
|
||||
|
||||
_See code: [src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/analytics.ts)_
|
||||
_See code: [src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/analytics.ts)_
|
||||
|
||||
## `eas autocomplete [SHELL]`
|
||||
|
||||
@@ -231,7 +231,7 @@ DESCRIPTION
|
||||
create a branch
|
||||
```
|
||||
|
||||
_See code: [src/commands/branch/create.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/branch/create.ts)_
|
||||
_See code: [src/commands/branch/create.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/branch/create.ts)_
|
||||
|
||||
## `eas branch:delete [NAME]`
|
||||
|
||||
@@ -252,7 +252,7 @@ DESCRIPTION
|
||||
delete a branch
|
||||
```
|
||||
|
||||
_See code: [src/commands/branch/delete.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/branch/delete.ts)_
|
||||
_See code: [src/commands/branch/delete.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/branch/delete.ts)_
|
||||
|
||||
## `eas branch:list`
|
||||
|
||||
@@ -272,7 +272,7 @@ DESCRIPTION
|
||||
list all branches
|
||||
```
|
||||
|
||||
_See code: [src/commands/branch/list.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/branch/list.ts)_
|
||||
_See code: [src/commands/branch/list.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/branch/list.ts)_
|
||||
|
||||
## `eas branch:rename`
|
||||
|
||||
@@ -292,7 +292,7 @@ DESCRIPTION
|
||||
rename a branch
|
||||
```
|
||||
|
||||
_See code: [src/commands/branch/rename.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/branch/rename.ts)_
|
||||
_See code: [src/commands/branch/rename.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/branch/rename.ts)_
|
||||
|
||||
## `eas branch:view [NAME]`
|
||||
|
||||
@@ -315,7 +315,7 @@ DESCRIPTION
|
||||
view a branch
|
||||
```
|
||||
|
||||
_See code: [src/commands/branch/view.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/branch/view.ts)_
|
||||
_See code: [src/commands/branch/view.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/branch/view.ts)_
|
||||
|
||||
## `eas build`
|
||||
|
||||
@@ -345,7 +345,7 @@ DESCRIPTION
|
||||
start a build
|
||||
```
|
||||
|
||||
_See code: [src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/build/index.ts)_
|
||||
_See code: [src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/build/index.ts)_
|
||||
|
||||
## `eas build:cancel [BUILD_ID]`
|
||||
|
||||
@@ -362,7 +362,7 @@ DESCRIPTION
|
||||
cancel a build
|
||||
```
|
||||
|
||||
_See code: [src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/build/cancel.ts)_
|
||||
_See code: [src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/build/cancel.ts)_
|
||||
|
||||
## `eas build:configure`
|
||||
|
||||
@@ -379,7 +379,7 @@ DESCRIPTION
|
||||
configure the project to support EAS Build
|
||||
```
|
||||
|
||||
_See code: [src/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/build/configure.ts)_
|
||||
_See code: [src/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/build/configure.ts)_
|
||||
|
||||
## `eas build:inspect`
|
||||
|
||||
@@ -414,7 +414,7 @@ DESCRIPTION
|
||||
inspect the state of the project at specific build stages, useful for troubleshooting
|
||||
```
|
||||
|
||||
_See code: [src/commands/build/inspect.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/build/inspect.ts)_
|
||||
_See code: [src/commands/build/inspect.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/build/inspect.ts)_
|
||||
|
||||
## `eas build:list`
|
||||
|
||||
@@ -451,7 +451,7 @@ DESCRIPTION
|
||||
list all builds for your project
|
||||
```
|
||||
|
||||
_See code: [src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/build/list.ts)_
|
||||
_See code: [src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/build/list.ts)_
|
||||
|
||||
## `eas build:resign`
|
||||
|
||||
@@ -477,7 +477,7 @@ DESCRIPTION
|
||||
re-sign a build archive
|
||||
```
|
||||
|
||||
_See code: [src/commands/build/resign.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/build/resign.ts)_
|
||||
_See code: [src/commands/build/resign.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/build/resign.ts)_
|
||||
|
||||
## `eas build:run`
|
||||
|
||||
@@ -501,7 +501,7 @@ DESCRIPTION
|
||||
run simulator/emulator builds from eas-cli
|
||||
```
|
||||
|
||||
_See code: [src/commands/build/run.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/build/run.ts)_
|
||||
_See code: [src/commands/build/run.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/build/run.ts)_
|
||||
|
||||
## `eas build:submit`
|
||||
|
||||
@@ -550,7 +550,7 @@ DESCRIPTION
|
||||
get the latest version from EAS servers
|
||||
```
|
||||
|
||||
_See code: [src/commands/build/version/get.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/build/version/get.ts)_
|
||||
_See code: [src/commands/build/version/get.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/build/version/get.ts)_
|
||||
|
||||
## `eas build:version:set`
|
||||
|
||||
@@ -569,7 +569,7 @@ DESCRIPTION
|
||||
update version of an app
|
||||
```
|
||||
|
||||
_See code: [src/commands/build/version/set.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/build/version/set.ts)_
|
||||
_See code: [src/commands/build/version/set.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/build/version/set.ts)_
|
||||
|
||||
## `eas build:version:sync`
|
||||
|
||||
@@ -588,7 +588,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/v3.12.1/packages/eas-cli/src/commands/build/version/sync.ts)_
|
||||
_See code: [src/commands/build/version/sync.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/build/version/sync.ts)_
|
||||
|
||||
## `eas build:view [BUILD_ID]`
|
||||
|
||||
@@ -605,7 +605,7 @@ DESCRIPTION
|
||||
view a build for your project
|
||||
```
|
||||
|
||||
_See code: [src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/build/view.ts)_
|
||||
_See code: [src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/build/view.ts)_
|
||||
|
||||
## `eas channel:create [NAME]`
|
||||
|
||||
@@ -626,7 +626,7 @@ DESCRIPTION
|
||||
create a channel
|
||||
```
|
||||
|
||||
_See code: [src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/channel/create.ts)_
|
||||
_See code: [src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/channel/create.ts)_
|
||||
|
||||
## `eas channel:edit [NAME]`
|
||||
|
||||
@@ -648,7 +648,7 @@ DESCRIPTION
|
||||
point a channel at a new branch
|
||||
```
|
||||
|
||||
_See code: [src/commands/channel/edit.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/channel/edit.ts)_
|
||||
_See code: [src/commands/channel/edit.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/channel/edit.ts)_
|
||||
|
||||
## `eas channel:list`
|
||||
|
||||
@@ -668,7 +668,7 @@ DESCRIPTION
|
||||
list all channels
|
||||
```
|
||||
|
||||
_See code: [src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/channel/list.ts)_
|
||||
_See code: [src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/channel/list.ts)_
|
||||
|
||||
## `eas channel:rollout [CHANNEL]`
|
||||
|
||||
@@ -692,7 +692,7 @@ DESCRIPTION
|
||||
Roll a new branch out on a channel incrementally.
|
||||
```
|
||||
|
||||
_See code: [src/commands/channel/rollout.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/channel/rollout.ts)_
|
||||
_See code: [src/commands/channel/rollout.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/channel/rollout.ts)_
|
||||
|
||||
## `eas channel:view [NAME]`
|
||||
|
||||
@@ -715,7 +715,7 @@ DESCRIPTION
|
||||
view a channel
|
||||
```
|
||||
|
||||
_See code: [src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/channel/view.ts)_
|
||||
_See code: [src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/channel/view.ts)_
|
||||
|
||||
## `eas config`
|
||||
|
||||
@@ -736,7 +736,7 @@ DESCRIPTION
|
||||
display project configuration (app.json + eas.json)
|
||||
```
|
||||
|
||||
_See code: [src/commands/config.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/config.ts)_
|
||||
_See code: [src/commands/config.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/config.ts)_
|
||||
|
||||
## `eas credentials`
|
||||
|
||||
@@ -753,7 +753,7 @@ DESCRIPTION
|
||||
manage credentials
|
||||
```
|
||||
|
||||
_See code: [src/commands/credentials.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/credentials.ts)_
|
||||
_See code: [src/commands/credentials.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/credentials.ts)_
|
||||
|
||||
## `eas device:create`
|
||||
|
||||
@@ -767,7 +767,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/v3.12.1/packages/eas-cli/src/commands/device/create.ts)_
|
||||
_See code: [src/commands/device/create.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/device/create.ts)_
|
||||
|
||||
## `eas device:delete`
|
||||
|
||||
@@ -787,7 +787,7 @@ DESCRIPTION
|
||||
remove a registered device from your account
|
||||
```
|
||||
|
||||
_See code: [src/commands/device/delete.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/device/delete.ts)_
|
||||
_See code: [src/commands/device/delete.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/device/delete.ts)_
|
||||
|
||||
## `eas device:list`
|
||||
|
||||
@@ -808,7 +808,7 @@ DESCRIPTION
|
||||
list all registered devices for your account
|
||||
```
|
||||
|
||||
_See code: [src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/device/list.ts)_
|
||||
_See code: [src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/device/list.ts)_
|
||||
|
||||
## `eas device:rename`
|
||||
|
||||
@@ -829,7 +829,7 @@ DESCRIPTION
|
||||
rename a registered device
|
||||
```
|
||||
|
||||
_See code: [src/commands/device/rename.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/device/rename.ts)_
|
||||
_See code: [src/commands/device/rename.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/device/rename.ts)_
|
||||
|
||||
## `eas device:view [UDID]`
|
||||
|
||||
@@ -843,7 +843,7 @@ DESCRIPTION
|
||||
view a device for your project
|
||||
```
|
||||
|
||||
_See code: [src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/device/view.ts)_
|
||||
_See code: [src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/device/view.ts)_
|
||||
|
||||
## `eas diagnostics`
|
||||
|
||||
@@ -857,7 +857,7 @@ DESCRIPTION
|
||||
display environment info
|
||||
```
|
||||
|
||||
_See code: [src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/diagnostics.ts)_
|
||||
_See code: [src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/diagnostics.ts)_
|
||||
|
||||
## `eas help [COMMAND]`
|
||||
|
||||
@@ -945,7 +945,7 @@ DESCRIPTION
|
||||
validate the local store configuration
|
||||
```
|
||||
|
||||
_See code: [src/commands/metadata/lint.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/metadata/lint.ts)_
|
||||
_See code: [src/commands/metadata/lint.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/metadata/lint.ts)_
|
||||
|
||||
## `eas metadata:pull`
|
||||
|
||||
@@ -962,7 +962,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/v3.12.1/packages/eas-cli/src/commands/metadata/pull.ts)_
|
||||
_See code: [src/commands/metadata/pull.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/metadata/pull.ts)_
|
||||
|
||||
## `eas metadata:push`
|
||||
|
||||
@@ -979,7 +979,7 @@ DESCRIPTION
|
||||
sync the local store configuration to the app stores
|
||||
```
|
||||
|
||||
_See code: [src/commands/metadata/push.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/metadata/push.ts)_
|
||||
_See code: [src/commands/metadata/push.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/metadata/push.ts)_
|
||||
|
||||
## `eas open`
|
||||
|
||||
@@ -993,7 +993,7 @@ DESCRIPTION
|
||||
open the project page in a web browser
|
||||
```
|
||||
|
||||
_See code: [src/commands/open.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/open.ts)_
|
||||
_See code: [src/commands/open.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/open.ts)_
|
||||
|
||||
## `eas project:info`
|
||||
|
||||
@@ -1007,7 +1007,7 @@ DESCRIPTION
|
||||
information about the current project
|
||||
```
|
||||
|
||||
_See code: [src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/project/info.ts)_
|
||||
_See code: [src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/project/info.ts)_
|
||||
|
||||
## `eas project:init`
|
||||
|
||||
@@ -1029,7 +1029,7 @@ ALIASES
|
||||
$ eas init
|
||||
```
|
||||
|
||||
_See code: [src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/project/init.ts)_
|
||||
_See code: [src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/project/init.ts)_
|
||||
|
||||
## `eas secret:create`
|
||||
|
||||
@@ -1052,7 +1052,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/v3.12.1/packages/eas-cli/src/commands/secret/create.ts)_
|
||||
_See code: [src/commands/secret/create.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/secret/create.ts)_
|
||||
|
||||
## `eas secret:delete`
|
||||
|
||||
@@ -1070,7 +1070,7 @@ DESCRIPTION
|
||||
delete an environment secret by ID
|
||||
```
|
||||
|
||||
_See code: [src/commands/secret/delete.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/secret/delete.ts)_
|
||||
_See code: [src/commands/secret/delete.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/secret/delete.ts)_
|
||||
|
||||
## `eas secret:list`
|
||||
|
||||
@@ -1084,7 +1084,7 @@ DESCRIPTION
|
||||
list environment secrets available for your current app
|
||||
```
|
||||
|
||||
_See code: [src/commands/secret/list.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/secret/list.ts)_
|
||||
_See code: [src/commands/secret/list.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/secret/list.ts)_
|
||||
|
||||
## `eas secret:push`
|
||||
|
||||
@@ -1104,7 +1104,7 @@ DESCRIPTION
|
||||
read environment secrets from env file and store on the server
|
||||
```
|
||||
|
||||
_See code: [src/commands/secret/push.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/secret/push.ts)_
|
||||
_See code: [src/commands/secret/push.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/secret/push.ts)_
|
||||
|
||||
## `eas submit`
|
||||
|
||||
@@ -1134,7 +1134,7 @@ ALIASES
|
||||
$ eas build:submit
|
||||
```
|
||||
|
||||
_See code: [src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/submit.ts)_
|
||||
_See code: [src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/submit.ts)_
|
||||
|
||||
## `eas update`
|
||||
|
||||
@@ -1143,14 +1143,15 @@ publish an update group
|
||||
```
|
||||
USAGE
|
||||
$ eas update [--branch <value>] [--channel <value>] [--message <value>] [--republish | --input-dir <value>
|
||||
| --skip-bundler] [--group <value> | | ] [-p android|ios|all] [--auto] [--private-key-path <value>] [--json
|
||||
--non-interactive]
|
||||
| --skip-bundler] [--group <value> | | ] [--clear-cache] [-p android|ios|all] [--auto] [--private-key-path <value>]
|
||||
[--json --non-interactive]
|
||||
|
||||
FLAGS
|
||||
-p, --platform=(android|ios|all) [default: all]
|
||||
--auto Use the current git branch and commit message for the EAS branch and update message
|
||||
--branch=<value> Branch to publish the update group on
|
||||
--channel=<value> Channel that the published update should affect
|
||||
--clear-cache Clear the bundler cache before publishing
|
||||
--group=<value> Update group to republish (deprecated, see republish command)
|
||||
--input-dir=<value> [default: dist] Location of the bundle
|
||||
--json Enable JSON output, non-JSON messages will be printed to stderr.
|
||||
@@ -1166,7 +1167,7 @@ DESCRIPTION
|
||||
publish an update group
|
||||
```
|
||||
|
||||
_See code: [src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/update/index.ts)_
|
||||
_See code: [src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/update/index.ts)_
|
||||
|
||||
## `eas update:configure`
|
||||
|
||||
@@ -1184,7 +1185,7 @@ DESCRIPTION
|
||||
configure the project to support EAS Update
|
||||
```
|
||||
|
||||
_See code: [src/commands/update/configure.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/update/configure.ts)_
|
||||
_See code: [src/commands/update/configure.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/update/configure.ts)_
|
||||
|
||||
## `eas update:delete GROUPID`
|
||||
|
||||
@@ -1205,7 +1206,7 @@ DESCRIPTION
|
||||
delete all the updates in an update group
|
||||
```
|
||||
|
||||
_See code: [src/commands/update/delete.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/update/delete.ts)_
|
||||
_See code: [src/commands/update/delete.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/update/delete.ts)_
|
||||
|
||||
## `eas update:list`
|
||||
|
||||
@@ -1227,7 +1228,7 @@ DESCRIPTION
|
||||
view the recent updates
|
||||
```
|
||||
|
||||
_See code: [src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/update/list.ts)_
|
||||
_See code: [src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/update/list.ts)_
|
||||
|
||||
## `eas update:republish`
|
||||
|
||||
@@ -1251,7 +1252,7 @@ DESCRIPTION
|
||||
roll back to an existing update
|
||||
```
|
||||
|
||||
_See code: [src/commands/update/republish.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/update/republish.ts)_
|
||||
_See code: [src/commands/update/republish.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/update/republish.ts)_
|
||||
|
||||
## `eas update:view GROUPID`
|
||||
|
||||
@@ -1271,7 +1272,7 @@ DESCRIPTION
|
||||
update group details
|
||||
```
|
||||
|
||||
_See code: [src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/update/view.ts)_
|
||||
_See code: [src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/update/view.ts)_
|
||||
|
||||
## `eas webhook:create`
|
||||
|
||||
@@ -1292,7 +1293,7 @@ DESCRIPTION
|
||||
create a webhook
|
||||
```
|
||||
|
||||
_See code: [src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/webhook/create.ts)_
|
||||
_See code: [src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/webhook/create.ts)_
|
||||
|
||||
## `eas webhook:delete [ID]`
|
||||
|
||||
@@ -1312,7 +1313,7 @@ DESCRIPTION
|
||||
delete a webhook
|
||||
```
|
||||
|
||||
_See code: [src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/webhook/delete.ts)_
|
||||
_See code: [src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/webhook/delete.ts)_
|
||||
|
||||
## `eas webhook:list`
|
||||
|
||||
@@ -1330,7 +1331,7 @@ DESCRIPTION
|
||||
list webhooks
|
||||
```
|
||||
|
||||
_See code: [src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/webhook/list.ts)_
|
||||
_See code: [src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/webhook/list.ts)_
|
||||
|
||||
## `eas webhook:update`
|
||||
|
||||
@@ -1352,7 +1353,7 @@ DESCRIPTION
|
||||
update a webhook
|
||||
```
|
||||
|
||||
_See code: [src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/webhook/update.ts)_
|
||||
_See code: [src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/webhook/update.ts)_
|
||||
|
||||
## `eas webhook:view ID`
|
||||
|
||||
@@ -1369,7 +1370,7 @@ DESCRIPTION
|
||||
view a webhook
|
||||
```
|
||||
|
||||
_See code: [src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v3.12.1/packages/eas-cli/src/commands/webhook/view.ts)_
|
||||
_See code: [src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v3.13.0/packages/eas-cli/src/commands/webhook/view.ts)_
|
||||
|
||||
## `eas whoami`
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "eas-cli",
|
||||
"description": "EAS command line tool",
|
||||
"version": "3.12.1",
|
||||
"version": "3.13.0",
|
||||
"author": "Expo <[email protected]>",
|
||||
"bin": {
|
||||
"eas": "./bin/run"
|
||||
@@ -11,10 +11,10 @@
|
||||
"@expo/apple-utils": "1.2.0",
|
||||
"@expo/code-signing-certificates": "0.0.5",
|
||||
"@expo/config": "7.0.3",
|
||||
"@expo/config-plugins": "5.0.4",
|
||||
"@expo/config-plugins": "6.0.2",
|
||||
"@expo/config-types": "47.0.0",
|
||||
"@expo/eas-build-job": "1.0.12",
|
||||
"@expo/eas-json": "3.12.1",
|
||||
"@expo/eas-build-job": "1.0.13",
|
||||
"@expo/eas-json": "3.13.0",
|
||||
"@expo/json-file": "8.2.37",
|
||||
"@expo/multipart-body-parser": "1.1.0",
|
||||
"@expo/osascript": "2.0.33",
|
||||
@@ -27,7 +27,7 @@
|
||||
"@expo/results": "1.0.0",
|
||||
"@expo/rudder-sdk-node": "1.1.1",
|
||||
"@expo/spawn-async": "1.7.0",
|
||||
"@expo/steps": "1.0.11",
|
||||
"@expo/steps": "1.0.13",
|
||||
"@expo/timeago.js": "1.0.0",
|
||||
"@oclif/core": "1.23.2",
|
||||
"@oclif/plugin-autocomplete": "1.3.10",
|
||||
|
||||
@@ -77,7 +77,7 @@ describe(bumpVersionAsync, () => {
|
||||
);
|
||||
await bumpVersionAsync({
|
||||
bumpStrategy: BumpStrategy.BUILD_NUMBER,
|
||||
projectDir: '/repo',
|
||||
projectDir: '/app',
|
||||
exp: fakeExp,
|
||||
targets: [
|
||||
{
|
||||
@@ -88,9 +88,9 @@ describe(bumpVersionAsync, () => {
|
||||
],
|
||||
});
|
||||
|
||||
const appJSON = await fs.readJSON('/repo/app.json');
|
||||
const appJSON = await fs.readJSON('/app/app.json');
|
||||
const infoPlist = (await readPlistAsync(
|
||||
'/repo/ios/myproject/Info.plist'
|
||||
'/app/ios/myproject/Info.plist'
|
||||
)) as IOSConfig.InfoPlist;
|
||||
expect(fakeExp.version).toBe('1.0.0');
|
||||
expect(fakeExp.ios?.buildNumber).toBe('2');
|
||||
@@ -113,7 +113,7 @@ describe(bumpVersionAsync, () => {
|
||||
);
|
||||
await bumpVersionAsync({
|
||||
bumpStrategy: BumpStrategy.BUILD_NUMBER,
|
||||
projectDir: '/repo',
|
||||
projectDir: '/app',
|
||||
exp: fakeExp,
|
||||
targets: [
|
||||
{
|
||||
@@ -124,9 +124,9 @@ describe(bumpVersionAsync, () => {
|
||||
],
|
||||
});
|
||||
|
||||
const appJSON = await fs.readJSON('/repo/app.json');
|
||||
const appJSON = await fs.readJSON('/app/app.json');
|
||||
const infoPlist = (await readPlistAsync(
|
||||
'/repo/ios/myproject/Info2.plist'
|
||||
'/app/ios/myproject/Info2.plist'
|
||||
)) as IOSConfig.InfoPlist;
|
||||
expect(fakeExp.version).toBe('1.0.0');
|
||||
expect(fakeExp.ios?.buildNumber).toBe('2');
|
||||
@@ -148,7 +148,7 @@ describe(bumpVersionAsync, () => {
|
||||
);
|
||||
await bumpVersionAsync({
|
||||
bumpStrategy: BumpStrategy.APP_VERSION,
|
||||
projectDir: '/repo',
|
||||
projectDir: '/app',
|
||||
exp: fakeExp,
|
||||
targets: [
|
||||
{
|
||||
@@ -159,9 +159,9 @@ describe(bumpVersionAsync, () => {
|
||||
],
|
||||
});
|
||||
|
||||
const appJSON = await fs.readJSON('/repo/app.json');
|
||||
const appJSON = await fs.readJSON('/app/app.json');
|
||||
const infoPlist = (await readPlistAsync(
|
||||
'/repo/ios/myproject/Info.plist'
|
||||
'/app/ios/myproject/Info.plist'
|
||||
)) as IOSConfig.InfoPlist;
|
||||
expect(fakeExp.version).toBe('1.0.1');
|
||||
expect(fakeExp.ios?.buildNumber).toBe('1');
|
||||
@@ -183,7 +183,7 @@ describe(bumpVersionAsync, () => {
|
||||
);
|
||||
await bumpVersionAsync({
|
||||
bumpStrategy: BumpStrategy.NOOP,
|
||||
projectDir: '/repo',
|
||||
projectDir: '/app',
|
||||
exp: fakeExp,
|
||||
targets: [
|
||||
{
|
||||
@@ -194,9 +194,9 @@ describe(bumpVersionAsync, () => {
|
||||
],
|
||||
});
|
||||
|
||||
const appJSON = await fs.readJSON('/repo/app.json');
|
||||
const appJSON = await fs.readJSON('/app/app.json');
|
||||
const infoPlist = (await readPlistAsync(
|
||||
'/repo/ios/myproject/Info.plist'
|
||||
'/app/ios/myproject/Info.plist'
|
||||
)) as IOSConfig.InfoPlist;
|
||||
expect(fakeExp.version).toBe('1.0.0');
|
||||
expect(fakeExp.ios?.buildNumber).toBe('1');
|
||||
@@ -214,11 +214,11 @@ describe(bumpVersionInAppJsonAsync, () => {
|
||||
|
||||
await bumpVersionInAppJsonAsync({
|
||||
bumpStrategy: BumpStrategy.BUILD_NUMBER,
|
||||
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('1.0.0');
|
||||
expect(fakeExp.ios?.buildNumber).toBe('2');
|
||||
expect(appJSON.expo.version).toBe('1.0.0');
|
||||
@@ -230,11 +230,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('1.0.1');
|
||||
expect(fakeExp.ios?.buildNumber).toBe('1');
|
||||
expect(appJSON.expo.version).toBe('1.0.1');
|
||||
@@ -246,11 +246,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('1.0.0');
|
||||
expect(fakeExp.ios?.buildNumber).toBe('1');
|
||||
expect(appJSON.expo.version).toBe('1.0.0');
|
||||
@@ -262,7 +262,7 @@ describe(readBuildNumberAsync, () => {
|
||||
describe('bare project', () => {
|
||||
it('reads the build number from native code', async () => {
|
||||
const exp = initBareWorkflowProject();
|
||||
const buildNumber = await readBuildNumberAsync('/repo', exp, {});
|
||||
const buildNumber = await readBuildNumberAsync('/app', exp, {});
|
||||
expect(buildNumber).toBe('1');
|
||||
});
|
||||
});
|
||||
@@ -270,7 +270,7 @@ describe(readBuildNumberAsync, () => {
|
||||
describe('managed project', () => {
|
||||
it('reads the build number from expo config', async () => {
|
||||
const exp = initManagedProject();
|
||||
const buildNumber = await readBuildNumberAsync('/repo', exp, {});
|
||||
const buildNumber = await readBuildNumberAsync('/app', exp, {});
|
||||
expect(buildNumber).toBe('1');
|
||||
});
|
||||
});
|
||||
@@ -280,24 +280,38 @@ describe(readShortVersionAsync, () => {
|
||||
describe('bare project', () => {
|
||||
it('reads the short version from native code', async () => {
|
||||
const exp = initBareWorkflowProject();
|
||||
const appVersion = await readShortVersionAsync('/repo', exp, {});
|
||||
const appVersion = await readShortVersionAsync('/app', exp, {});
|
||||
expect(appVersion).toBe('1.0.0');
|
||||
});
|
||||
it('evaluates interpolated build number', async () => {
|
||||
const exp = initBareWorkflowProject({
|
||||
appVersion: '$(CURRENT_PROJECT_VERSION)',
|
||||
});
|
||||
const buildNumber = await readShortVersionAsync('/repo', exp, {
|
||||
const buildNumber = await readShortVersionAsync('/app', exp, {
|
||||
CURRENT_PROJECT_VERSION: '1.0.0',
|
||||
});
|
||||
expect(buildNumber).toBe('1.0.0');
|
||||
});
|
||||
|
||||
it('fails when build number is invalid', async () => {
|
||||
const exp = initBareWorkflowProject({
|
||||
appVersion: '$(CURRENT_PROJECT_VERSION)',
|
||||
});
|
||||
|
||||
await expect(
|
||||
readShortVersionAsync('/app', exp, {
|
||||
CURRENT_PROJECT_VERSION: '0.0.7.1.028',
|
||||
})
|
||||
).rejects.toThrowError(
|
||||
'CFBundleShortVersionString (version field in app.json/app.config.js) must be a period-separated list of three non-negative integers. Current value: 0.0.7.1.028'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('managed project', () => {
|
||||
it('reads the version from app config', async () => {
|
||||
const exp = initBareWorkflowProject();
|
||||
const appVersion = await readShortVersionAsync('/repo', exp, {});
|
||||
const appVersion = await readShortVersionAsync('/app', exp, {});
|
||||
expect(appVersion).toBe('1.0.0');
|
||||
});
|
||||
});
|
||||
@@ -309,66 +323,75 @@ describe(getInfoPlistPath, () => {
|
||||
{
|
||||
'./ios/testapp/Info.plist': '',
|
||||
},
|
||||
'/repo'
|
||||
'/app'
|
||||
);
|
||||
const plistPath = getInfoPlistPath('/repo', {});
|
||||
expect(plistPath).toBe('/repo/ios/testapp/Info.plist');
|
||||
const plistPath = getInfoPlistPath('/app', {});
|
||||
expect(plistPath).toBe('/app/ios/testapp/Info.plist');
|
||||
});
|
||||
it('returns INFOPLIST_FILE if specified', () => {
|
||||
vol.fromJSON(
|
||||
{
|
||||
'./ios/testapp/Info.plist': '',
|
||||
},
|
||||
'/repo'
|
||||
'/app'
|
||||
);
|
||||
const plistPath = getInfoPlistPath('/repo', { INFOPLIST_FILE: './qwert/NotInfo.plist' });
|
||||
expect(plistPath).toBe('/repo/ios/qwert/NotInfo.plist');
|
||||
const plistPath = getInfoPlistPath('/app', { INFOPLIST_FILE: './qwert/NotInfo.plist' });
|
||||
expect(plistPath).toBe('/app/ios/qwert/NotInfo.plist');
|
||||
});
|
||||
it('evaluates SRCROOT in Info.plist', () => {
|
||||
vol.fromJSON(
|
||||
{
|
||||
'./ios/testapp/Info.plist': '',
|
||||
},
|
||||
'/repo'
|
||||
'/app'
|
||||
);
|
||||
const plistPath = getInfoPlistPath('/repo', {
|
||||
const plistPath = getInfoPlistPath('/app', {
|
||||
INFOPLIST_FILE: '$(SRCROOT)/qwert/NotInfo.plist',
|
||||
});
|
||||
expect(plistPath).toBe('/repo/ios/qwert/NotInfo.plist');
|
||||
expect(plistPath).toBe('/app/ios/qwert/NotInfo.plist');
|
||||
});
|
||||
it('evaluates BuildSettings in Info.plist', () => {
|
||||
vol.fromJSON(
|
||||
{
|
||||
'./ios/testapp/Info.plist': '',
|
||||
},
|
||||
'/repo'
|
||||
'/app'
|
||||
);
|
||||
const plistPath = getInfoPlistPath('/repo', {
|
||||
const plistPath = getInfoPlistPath('/app', {
|
||||
INFOPLIST_FILE: '$(SRCROOT)/qwert/$(TARGET_NAME).plist',
|
||||
TARGET_NAME: 'NotInfo',
|
||||
});
|
||||
expect(plistPath).toBe('/repo/ios/qwert/NotInfo.plist');
|
||||
expect(plistPath).toBe('/app/ios/qwert/NotInfo.plist');
|
||||
});
|
||||
});
|
||||
|
||||
function initBareWorkflowProject({
|
||||
appVersion = '1.0.0',
|
||||
buildNumber = '1',
|
||||
expoConfig = {},
|
||||
infoPlistName = 'Info.plist',
|
||||
}: { appVersion?: string; buildNumber?: string; infoPlistName?: string } = {}): ExpoConfig {
|
||||
}: {
|
||||
appVersion?: string;
|
||||
buildNumber?: string;
|
||||
infoPlistName?: string;
|
||||
expoConfig?: { version?: string; ios?: object };
|
||||
} = {}): ExpoConfig {
|
||||
const fakeExp: ExpoConfig = {
|
||||
name: 'myproject',
|
||||
slug: 'myproject',
|
||||
version: '1.0.0',
|
||||
ios: {
|
||||
buildNumber: '1',
|
||||
...expoConfig.ios,
|
||||
},
|
||||
...expoConfig,
|
||||
};
|
||||
vol.fromJSON(
|
||||
{
|
||||
'./app.json': JSON.stringify({
|
||||
expo: fakeExp,
|
||||
}),
|
||||
'./ios/myproject.xcodeproj/project.pbxproj': '',
|
||||
[`./ios/myproject/${infoPlistName}`]: `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
@@ -380,7 +403,7 @@ function initBareWorkflowProject({
|
||||
</dict>
|
||||
</plist>`,
|
||||
},
|
||||
'/repo'
|
||||
'/app'
|
||||
);
|
||||
|
||||
return fakeExp;
|
||||
@@ -402,7 +425,7 @@ function initManagedProject(): ExpoConfig {
|
||||
expo: fakeExp,
|
||||
}),
|
||||
},
|
||||
'/repo'
|
||||
'/app'
|
||||
);
|
||||
|
||||
return fakeExp;
|
||||
|
||||
@@ -22,6 +22,8 @@ import { readPlistAsync, writePlistAsync } from '../../utils/plist';
|
||||
import { updateAppJsonConfigAsync } from '../utils/appJson';
|
||||
import { bumpAppVersionAsync, ensureStaticConfigExists } from '../utils/version';
|
||||
|
||||
const SHORT_VERSION_REGEX = /^\d+.\d+.\d+$/;
|
||||
|
||||
export enum BumpStrategy {
|
||||
APP_VERSION,
|
||||
BUILD_NUMBER,
|
||||
@@ -97,6 +99,14 @@ export async function bumpVersionInAppJsonAsync({
|
||||
}
|
||||
}
|
||||
|
||||
function validateShortVersion(shortVersion: string | undefined): void {
|
||||
if (shortVersion && !SHORT_VERSION_REGEX.test(shortVersion)) {
|
||||
throw new Error(
|
||||
`CFBundleShortVersionString (version field in app.json/app.config.js) must be a period-separated list of three non-negative integers. Current value: ${shortVersion}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function readShortVersionAsync(
|
||||
projectDir: string,
|
||||
exp: ExpoConfig,
|
||||
@@ -105,11 +115,15 @@ export async function readShortVersionAsync(
|
||||
const workflow = await resolveWorkflowAsync(projectDir, Platform.IOS);
|
||||
if (workflow === Workflow.GENERIC) {
|
||||
const infoPlist = await readInfoPlistAsync(projectDir, buildSettings);
|
||||
return (
|
||||
|
||||
const shortVersion =
|
||||
infoPlist.CFBundleShortVersionString &&
|
||||
evaluateTemplateString(infoPlist.CFBundleShortVersionString, buildSettings)
|
||||
);
|
||||
evaluateTemplateString(infoPlist.CFBundleShortVersionString, buildSettings);
|
||||
|
||||
validateShortVersion(shortVersion);
|
||||
return shortVersion;
|
||||
} else {
|
||||
validateShortVersion(exp.version);
|
||||
return exp.version;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import { getVcsClient } from '../vcs';
|
||||
import { maybeResolveVersionsAsync as maybeResolveAndroidVersionsAsync } from './android/version';
|
||||
import { BuildContext } from './context';
|
||||
import { maybeResolveVersionsAsync as maybeResolveIosVersionsAsync } from './ios/version';
|
||||
import { LocalBuildMode } from './local';
|
||||
|
||||
export async function collectMetadataAsync<T extends Platform>(
|
||||
ctx: BuildContext<T>
|
||||
@@ -47,7 +48,10 @@ export async function collectMetadataAsync<T extends Platform>(
|
||||
gitCommitMessage: truncateGitCommitMessage(
|
||||
(await vcsClient.getLastCommitMessageAsync()) ?? undefined
|
||||
),
|
||||
isGitWorkingTreeDirty: await vcsClient.hasUncommittedChangesAsync(),
|
||||
isGitWorkingTreeDirty:
|
||||
ctx.localBuildOptions.localBuildMode === LocalBuildMode.INTERNAL
|
||||
? false
|
||||
: await vcsClient.hasUncommittedChangesAsync(),
|
||||
username: getUsername(ctx.exp, ctx.user),
|
||||
message: ctx.message,
|
||||
...(ctx.platform === Platform.IOS && {
|
||||
|
||||
@@ -59,6 +59,7 @@ type RawUpdateFlags = {
|
||||
platform: string;
|
||||
'input-dir': string;
|
||||
'skip-bundler': boolean;
|
||||
'clear-cache': boolean;
|
||||
'private-key-path'?: string;
|
||||
'non-interactive': boolean;
|
||||
json: boolean;
|
||||
@@ -76,6 +77,7 @@ type UpdateFlags = {
|
||||
updateMessage?: string;
|
||||
inputDir: string;
|
||||
skipBundler: boolean;
|
||||
clearCache: boolean;
|
||||
privateKeyPath?: string;
|
||||
json: boolean;
|
||||
nonInteractive: boolean;
|
||||
@@ -114,6 +116,10 @@ export default class UpdatePublish extends EasCommand {
|
||||
description: `Skip running Expo CLI to bundle the app before publishing`,
|
||||
default: false,
|
||||
}),
|
||||
'clear-cache': Flags.boolean({
|
||||
description: `Clear the bundler cache before publishing`,
|
||||
default: false,
|
||||
}),
|
||||
platform: Flags.enum({
|
||||
char: 'p',
|
||||
options: [
|
||||
@@ -151,6 +157,7 @@ export default class UpdatePublish extends EasCommand {
|
||||
updateMessage: updateMessageArg,
|
||||
inputDir,
|
||||
skipBundler,
|
||||
clearCache,
|
||||
privateKeyPath,
|
||||
json: jsonFlag,
|
||||
nonInteractive,
|
||||
@@ -212,7 +219,7 @@ export default class UpdatePublish extends EasCommand {
|
||||
if (!skipBundler) {
|
||||
const bundleSpinner = ora().start('Exporting...');
|
||||
try {
|
||||
await buildBundlesAsync({ projectDir, inputDir, exp, platformFlag });
|
||||
await buildBundlesAsync({ projectDir, inputDir, exp, platformFlag, clearCache });
|
||||
bundleSpinner.succeed('Exported bundle(s)');
|
||||
} catch (e) {
|
||||
bundleSpinner.fail('Export failed');
|
||||
@@ -488,6 +495,7 @@ export default class UpdatePublish extends EasCommand {
|
||||
updateMessage,
|
||||
inputDir: flags['input-dir'],
|
||||
skipBundler: flags['skip-bundler'],
|
||||
clearCache: flags['clear-cache'],
|
||||
platform: flags.platform as RequestedPlatform,
|
||||
privateKeyPath: flags['private-key-path'],
|
||||
nonInteractive,
|
||||
|
||||
@@ -13,6 +13,7 @@ export async function chooseDevicesAsync(
|
||||
const { devices } = await promptAsync({
|
||||
type: 'multiselect',
|
||||
name: 'devices',
|
||||
selectionFormat: '<num> devices selected',
|
||||
message: 'Select devices for the ad hoc build:',
|
||||
hint: '- Space to select. Return to submit',
|
||||
choices: allDevices.map(device => ({
|
||||
|
||||
@@ -31,10 +31,10 @@ export enum SetupAscApiKeyChoice {
|
||||
export class SetUpAscApiKey {
|
||||
public choices: { title: string; value: string }[] = [
|
||||
{
|
||||
title: '[Choose an existing ASC API Key]',
|
||||
title: '[Choose an existing key]',
|
||||
value: SetupAscApiKeyChoice.USE_EXISTING,
|
||||
},
|
||||
{ title: '[Add a new ASC API Key]', value: SetupAscApiKeyChoice.GENERATE },
|
||||
{ title: '[Add a new key]', value: SetupAscApiKeyChoice.GENERATE },
|
||||
];
|
||||
|
||||
constructor(private app: AppLookupParams, private purpose: AppStoreApiKeyPurpose) {}
|
||||
@@ -126,7 +126,7 @@ export class SetUpAscApiKey {
|
||||
const result = await promptAsync({
|
||||
type: 'select',
|
||||
name: 'choice',
|
||||
message: 'Select what to use for your project:',
|
||||
message: 'Select the App Store Connect Api Key to use for your project:',
|
||||
choices,
|
||||
});
|
||||
choice = result.choice;
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
import chalk from 'chalk';
|
||||
import nullthrows from 'nullthrows';
|
||||
import wrapAnsi from 'wrap-ansi';
|
||||
|
||||
import { CommonIosAppCredentialsFragment } from '../../../graphql/generated';
|
||||
import Log, { learnMore } from '../../../log';
|
||||
import { promptAsync } from '../../../prompts';
|
||||
import { CredentialsContext } from '../../context';
|
||||
import { UnsupportedCredentialsChoiceError } from '../../errors';
|
||||
import { AppLookupParams } from '../api/graphql/types/AppLookupParams';
|
||||
import { AppStoreApiKeyPurpose } from './AscApiKeyUtils';
|
||||
import { SetUpAscApiKey } from './SetUpAscApiKey';
|
||||
|
||||
export const PROMPT_FOR_APP_SPECIFIC_PASSWORD = 'PROMPT_FOR_APP_SPECIFIC_PASSWORD';
|
||||
|
||||
export class SetUpSubmissionCredentials {
|
||||
private setupAscApiKeyAction;
|
||||
|
||||
constructor(app: AppLookupParams) {
|
||||
this.setupAscApiKeyAction = new SetUpAscApiKey(app, AppStoreApiKeyPurpose.SUBMISSION_SERVICE);
|
||||
// Add this unrelated choice to ASC API Key setup for legacy purposes -- we will deprecate it soon
|
||||
this.setupAscApiKeyAction.choices = this.setupAscApiKeyAction.choices.concat({
|
||||
title: '[Enter an App Specific Password]',
|
||||
value: PROMPT_FOR_APP_SPECIFIC_PASSWORD,
|
||||
});
|
||||
}
|
||||
|
||||
public async runAsync(
|
||||
ctx: CredentialsContext
|
||||
): Promise<CommonIosAppCredentialsFragment | string> {
|
||||
try {
|
||||
const iosAppCredentials = await this.setupAscApiKeyAction.runAsync(ctx);
|
||||
const { keyIdentifier, name } = nullthrows(
|
||||
iosAppCredentials.appStoreConnectApiKeyForSubmissions,
|
||||
'ASC API Key must be defined for EAS Submit'
|
||||
);
|
||||
Log.log(`Using API Key ID: ${keyIdentifier}${name ? ` (${name})` : ''}`);
|
||||
return iosAppCredentials;
|
||||
} catch (e) {
|
||||
if (e instanceof UnsupportedCredentialsChoiceError) {
|
||||
if (e.choice === PROMPT_FOR_APP_SPECIFIC_PASSWORD) {
|
||||
return await this.promptForAppSpecificPasswordAsync();
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
async promptForAppSpecificPasswordAsync(): Promise<string> {
|
||||
Log.addNewLineIfNone();
|
||||
Log.log(`Enter your Apple app-specific password.`);
|
||||
Log.log(learnMore('https://expo.fyi/apple-app-specific-password'));
|
||||
Log.warn(
|
||||
wrapAnsi(
|
||||
`This option will be deprecated soon. You will still be able to provide your password with the ${chalk.bold(
|
||||
'EXPO_APPLE_APP_SPECIFIC_PASSWORD'
|
||||
)} environment variable.`,
|
||||
process.stdout.columns || 80
|
||||
)
|
||||
);
|
||||
|
||||
const { appSpecificPassword } = await promptAsync({
|
||||
name: 'appSpecificPassword',
|
||||
message: 'Your Apple app-specific password:',
|
||||
type: 'password',
|
||||
validate: (val: string) => val !== '' || 'Apple app-specific password cannot be empty!',
|
||||
});
|
||||
return appSpecificPassword;
|
||||
}
|
||||
}
|
||||
-70
@@ -1,70 +0,0 @@
|
||||
import { AppQuery } from '../../../../graphql/queries/AppQuery';
|
||||
import { findApplicationTarget } from '../../../../project/ios/target';
|
||||
import { confirmAsync, promptAsync } from '../../../../prompts';
|
||||
import { testAppQueryByIdResponse } from '../../../__tests__/fixtures-constants';
|
||||
import { createCtxMock } from '../../../__tests__/fixtures-context';
|
||||
import {
|
||||
getNewIosApiMock,
|
||||
testCommonIosAppCredentialsFragment,
|
||||
testTargets,
|
||||
} from '../../../__tests__/fixtures-ios';
|
||||
import { getAppLookupParamsFromContextAsync } from '../BuildCredentialsUtils';
|
||||
import { SetUpAscApiKey } from '../SetUpAscApiKey';
|
||||
import {
|
||||
PROMPT_FOR_APP_SPECIFIC_PASSWORD,
|
||||
SetUpSubmissionCredentials,
|
||||
} from '../SetUpSubmissionCredentials';
|
||||
|
||||
jest.mock('../../../../prompts');
|
||||
jest.mocked(confirmAsync).mockImplementation(async () => true);
|
||||
jest.mock('../../../../graphql/queries/AppQuery');
|
||||
|
||||
describe(SetUpSubmissionCredentials, () => {
|
||||
beforeEach(() => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue(testAppQueryByIdResponse);
|
||||
});
|
||||
it('allows user to enter an App Specific Password', async () => {
|
||||
jest
|
||||
.mocked(promptAsync)
|
||||
.mockImplementationOnce(async () => ({
|
||||
choice: PROMPT_FOR_APP_SPECIFIC_PASSWORD,
|
||||
}))
|
||||
.mockImplementationOnce(async () => ({
|
||||
appSpecificPassword: 'super secret',
|
||||
}));
|
||||
const ctx = createCtxMock({
|
||||
nonInteractive: false,
|
||||
ios: {
|
||||
...getNewIosApiMock(),
|
||||
},
|
||||
});
|
||||
const appLookupParams = await getAppLookupParamsFromContextAsync(
|
||||
ctx,
|
||||
findApplicationTarget(testTargets)
|
||||
);
|
||||
const setupAscApiKeyAction = new SetUpSubmissionCredentials(appLookupParams);
|
||||
const asp = await setupAscApiKeyAction.runAsync(ctx);
|
||||
|
||||
// prompt to choose ASP, then prompt to input ASP
|
||||
expect(jest.mocked(promptAsync).mock.calls.length).toBe(2);
|
||||
expect(asp).toBe('super secret');
|
||||
});
|
||||
it('returns an ASC API key', async () => {
|
||||
try {
|
||||
jest
|
||||
.spyOn(SetUpAscApiKey.prototype, 'runAsync')
|
||||
.mockImplementation(async _ctx => testCommonIosAppCredentialsFragment);
|
||||
const ctx = createCtxMock();
|
||||
const appLookupParams = await getAppLookupParamsFromContextAsync(
|
||||
ctx,
|
||||
findApplicationTarget(testTargets)
|
||||
);
|
||||
const setupAscApiKeyAction = new SetUpSubmissionCredentials(appLookupParams);
|
||||
const asc = await setupAscApiKeyAction.runAsync(ctx);
|
||||
|
||||
expect(asc).toEqual(testCommonIosAppCredentialsFragment);
|
||||
} finally {
|
||||
jest.restoreAllMocks();
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -169,4 +169,8 @@ describe(syncCapabilityIdentifiersForEntitlementsAsync, () => {
|
||||
})
|
||||
).rejects.toThrow(/is not available. Enter a different string/);
|
||||
});
|
||||
|
||||
it(`ignores capabilities from "/ios" folder when gitignored`, async () => {
|
||||
//
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,53 @@
|
||||
import { Choice, PromptObject } from 'prompts';
|
||||
import { MultiselectPrompt } from 'prompts/lib/elements';
|
||||
|
||||
const noop = (): void => {};
|
||||
|
||||
export type Question<T extends string = string> = PromptObject<T> & {
|
||||
selectionFormat?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Customized multiselect prompt.
|
||||
*
|
||||
* Additional parameters:
|
||||
*
|
||||
* @param selectionFormat
|
||||
* String indicating number of selected options. Should contain `<num>` substring.
|
||||
*
|
||||
* Example:
|
||||
* 'Selected <num> devices'
|
||||
*
|
||||
* Short format is used when more than one option is selected.
|
||||
*
|
||||
**/
|
||||
|
||||
export default class EasMultiselect extends MultiselectPrompt {
|
||||
constructor(opts: Question) {
|
||||
super(opts);
|
||||
this.selectionFormat = opts.selectionFormat;
|
||||
}
|
||||
override renderDoneOrInstructions(): string {
|
||||
if (this.done && this.selectionFormat && this.value) {
|
||||
const selectedOptionsCount = this.value.filter(e => e.selected).length;
|
||||
|
||||
if (selectedOptionsCount > 1) {
|
||||
return this.selectionFormat.replace('<num>', selectedOptionsCount.toString());
|
||||
}
|
||||
}
|
||||
return super.renderDoneOrInstructions();
|
||||
}
|
||||
}
|
||||
|
||||
export const easMultiselect = (args: Question): Promise<Choice[]> => {
|
||||
const toSelected = (items: Choice[]): Choice[] =>
|
||||
items.filter(item => item.selected).map(item => item.value);
|
||||
|
||||
return new Promise((res, rej) => {
|
||||
const p = new EasMultiselect(args);
|
||||
const onAbort = toSelected || noop;
|
||||
const onSubmit = toSelected || noop;
|
||||
p.on('submit', x => res(onSubmit(x)));
|
||||
p.on('abort', x => rej(onAbort(x)));
|
||||
});
|
||||
};
|
||||
@@ -2,12 +2,15 @@ import { IOSConfig, compileModsAsync } from '@expo/config-plugins';
|
||||
import { JSONObject } from '@expo/json-file';
|
||||
import { getPrebuildConfigAsync } from '@expo/prebuild-config';
|
||||
|
||||
import Log from '../../log';
|
||||
import { readPlistAsync } from '../../utils/plist';
|
||||
import { getVcsClient } from '../../vcs';
|
||||
|
||||
interface Target {
|
||||
buildConfiguration?: string;
|
||||
targetName: string;
|
||||
}
|
||||
|
||||
export async function getManagedApplicationTargetEntitlementsAsync(
|
||||
projectDir: string,
|
||||
env: Record<string, string>
|
||||
@@ -43,3 +46,37 @@ export async function getNativeTargetEntitlementsAsync(
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When users have the `./ios` folder ignored through gitignore,
|
||||
* we should load the app entitlements as managed instead of native/bare workflow.
|
||||
* Without this, the user's configuration through config plugins will be ignored.
|
||||
* The gitignore check can be disabled by setting the `EAS_SYNC_NATIVE_CAPABILITIES=1` env variable.
|
||||
*/
|
||||
export async function getNativeTargetEntitlementsUnlessGitIgnoredAsync(
|
||||
projectDir: string,
|
||||
{
|
||||
target,
|
||||
env,
|
||||
}: {
|
||||
target: Target;
|
||||
env: Record<string, string>;
|
||||
}
|
||||
): Promise<JSONObject | null> {
|
||||
// Escape hatch to force syncing native capabilities from `/ios` folder
|
||||
const useNativeCapabilities = process.env.EAS_SYNC_NATIVE_CAPABILITIES;
|
||||
if (useNativeCapabilities) {
|
||||
Log.log(
|
||||
'Syncing native ios capabilities from `./ios` folder, EAS_SYNC_NATIVE_CAPABILITIES is defined.'
|
||||
);
|
||||
return getNativeTargetEntitlementsAsync(projectDir, target);
|
||||
}
|
||||
|
||||
// Load the capabilities from the prebuild config, instead of the native project when gitignored
|
||||
if (await getVcsClient().isFileIgnoredAsync('ios')) {
|
||||
return getManagedApplicationTargetEntitlementsAsync(projectDir, env);
|
||||
}
|
||||
|
||||
// Load the capabilities from the `./ios` native project
|
||||
return getNativeTargetEntitlementsAsync(projectDir, target);
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import { resolveWorkflowAsync } from '../workflow';
|
||||
import { getBundleIdentifierAsync } from './bundleIdentifier';
|
||||
import {
|
||||
getManagedApplicationTargetEntitlementsAsync,
|
||||
getNativeTargetEntitlementsAsync,
|
||||
getNativeTargetEntitlementsUnlessGitIgnoredAsync,
|
||||
} from './entitlements';
|
||||
import { XcodeBuildContext } from './scheme';
|
||||
|
||||
@@ -89,6 +89,7 @@ export async function resolveBareProjectTargetsAsync({
|
||||
exp,
|
||||
projectDir,
|
||||
xcodeBuildContext,
|
||||
env,
|
||||
}: ResolveTargetOptions): Promise<Target[]> {
|
||||
const { buildScheme, buildConfiguration } = xcodeBuildContext;
|
||||
const result: Target[] = [];
|
||||
@@ -102,9 +103,12 @@ export async function resolveBareProjectTargetsAsync({
|
||||
targetName: applicationTarget.name,
|
||||
buildConfiguration,
|
||||
});
|
||||
const entitlements = await getNativeTargetEntitlementsAsync(projectDir, {
|
||||
targetName: applicationTarget.name,
|
||||
buildConfiguration,
|
||||
const entitlements = await getNativeTargetEntitlementsUnlessGitIgnoredAsync(projectDir, {
|
||||
env: env ?? {},
|
||||
target: {
|
||||
targetName: applicationTarget.name,
|
||||
buildConfiguration,
|
||||
},
|
||||
});
|
||||
result.push({
|
||||
targetName: applicationTarget.name,
|
||||
@@ -151,6 +155,7 @@ async function resolveBareProjectDependenciesAsync({
|
||||
target,
|
||||
bundleIdentifier,
|
||||
pbxProject,
|
||||
env,
|
||||
}: {
|
||||
exp: ExpoConfig;
|
||||
projectDir: string;
|
||||
@@ -158,18 +163,25 @@ async function resolveBareProjectDependenciesAsync({
|
||||
target: IOSConfig.Target.Target;
|
||||
bundleIdentifier: string;
|
||||
pbxProject: XcodeProject;
|
||||
env?: ResolveTargetOptions['env'];
|
||||
}): Promise<Target[]> {
|
||||
const result: Target[] = [];
|
||||
|
||||
if (target.dependencies && target.dependencies.length > 0) {
|
||||
for (const dependency of target.dependencies) {
|
||||
if (!dependency.signable) {
|
||||
continue;
|
||||
}
|
||||
const dependencyBundleIdentifier = await getBundleIdentifierAsync(projectDir, exp, {
|
||||
targetName: dependency.name,
|
||||
buildConfiguration,
|
||||
});
|
||||
const entitlements = await getNativeTargetEntitlementsAsync(projectDir, {
|
||||
targetName: target.name,
|
||||
buildConfiguration,
|
||||
const entitlements = await getNativeTargetEntitlementsUnlessGitIgnoredAsync(projectDir, {
|
||||
env: env ?? {},
|
||||
target: {
|
||||
targetName: target.name,
|
||||
buildConfiguration,
|
||||
},
|
||||
});
|
||||
result.push({
|
||||
targetName: dependency.name,
|
||||
@@ -190,6 +202,7 @@ async function resolveBareProjectDependenciesAsync({
|
||||
target: dependency,
|
||||
bundleIdentifier: dependencyBundleIdentifier,
|
||||
pbxProject,
|
||||
env,
|
||||
});
|
||||
if (dependencyDependencies.length > 0) {
|
||||
result.push(...dependencyDependencies);
|
||||
|
||||
@@ -180,11 +180,13 @@ export async function buildBundlesAsync({
|
||||
inputDir,
|
||||
exp,
|
||||
platformFlag,
|
||||
clearCache,
|
||||
}: {
|
||||
projectDir: string;
|
||||
inputDir: string;
|
||||
exp: Pick<ExpoConfig, 'sdkVersion'>;
|
||||
platformFlag: ExpoCLIExportPlatformFlag;
|
||||
clearCache?: boolean;
|
||||
}): Promise<void> {
|
||||
const packageJSON = JsonFile.read(path.resolve(projectDir, 'package.json'));
|
||||
if (!packageJSON) {
|
||||
@@ -200,6 +202,7 @@ export async function buildBundlesAsync({
|
||||
'--dump-assetmap',
|
||||
'--platform',
|
||||
platformFlag,
|
||||
...(clearCache ? ['--clear'] : []),
|
||||
]);
|
||||
} else {
|
||||
// Legacy global Expo CLI
|
||||
@@ -213,6 +216,7 @@ export async function buildBundlesAsync({
|
||||
'--dump-assetmap',
|
||||
'--platform',
|
||||
platformFlag,
|
||||
...(clearCache ? ['--clear'] : []),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import { constants } from 'os';
|
||||
import prompts, { Answers, Choice, Options, PromptType, PromptObject as Question } from 'prompts';
|
||||
import prompts, { Answers, Choice, Options, prompts as PromptElements, PromptType } from 'prompts';
|
||||
|
||||
import { Question, easMultiselect } from './easMultiselect';
|
||||
export { PromptType, Question, Choice };
|
||||
|
||||
if (PromptElements) {
|
||||
PromptElements.multiselect = easMultiselect;
|
||||
}
|
||||
|
||||
export interface ExpoChoice<T> extends Choice {
|
||||
value: T;
|
||||
}
|
||||
|
||||
@@ -1,21 +1,38 @@
|
||||
import { Platform } from '@expo/eas-build-job';
|
||||
import fs from 'fs-extra';
|
||||
import nullthrows from 'nullthrows';
|
||||
|
||||
import { promptForAscApiKeyPathAsync } from '../../credentials/ios/actions/AscApiKeyUtils';
|
||||
import {
|
||||
AppStoreApiKeyPurpose,
|
||||
promptForAscApiKeyPathAsync,
|
||||
} from '../../credentials/ios/actions/AscApiKeyUtils';
|
||||
import { SetUpAscApiKey } from '../../credentials/ios/actions/SetUpAscApiKey';
|
||||
import { AscApiKeyPath, MinimalAscApiKey } from '../../credentials/ios/credentials';
|
||||
import Log from '../../log';
|
||||
import {
|
||||
AmbiguousBundleIdentifierError,
|
||||
INVALID_BUNDLE_IDENTIFIER_MESSAGE,
|
||||
getBundleIdentifierAsync,
|
||||
isBundleIdentifierValid,
|
||||
} from '../../project/ios/bundleIdentifier';
|
||||
import { promptAsync } from '../../prompts';
|
||||
import { SubmissionContext } from '../context';
|
||||
import { isExistingFileAsync } from '../utils/files';
|
||||
|
||||
export enum AscApiKeySourceType {
|
||||
path,
|
||||
prompt,
|
||||
credentialsService,
|
||||
}
|
||||
|
||||
interface AscApiKeySourceBase {
|
||||
sourceType: AscApiKeySourceType;
|
||||
}
|
||||
|
||||
interface AscApiKeyCredentialsServiceSource extends AscApiKeySourceBase {
|
||||
sourceType: AscApiKeySourceType.credentialsService;
|
||||
}
|
||||
|
||||
interface AscApiKeyPromptSource extends AscApiKeySourceBase {
|
||||
sourceType: AscApiKeySourceType.prompt;
|
||||
}
|
||||
@@ -25,7 +42,10 @@ interface AscApiKeyEnvVarSource extends AscApiKeySourceBase {
|
||||
path: AscApiKeyPath;
|
||||
}
|
||||
|
||||
export type AscApiKeySource = AscApiKeyEnvVarSource | AscApiKeyPromptSource;
|
||||
export type AscApiKeySource =
|
||||
| AscApiKeyEnvVarSource
|
||||
| AscApiKeyPromptSource
|
||||
| AscApiKeyCredentialsServiceSource;
|
||||
|
||||
type AscApiKeySummary = {
|
||||
source: 'local' | 'EAS servers';
|
||||
@@ -43,6 +63,84 @@ export type AscApiKeyResult = {
|
||||
summary: AscApiKeySummary;
|
||||
};
|
||||
|
||||
export async function getAscApiKeyResultAsync(
|
||||
ctx: SubmissionContext<Platform.IOS>,
|
||||
source: AscApiKeySource
|
||||
): Promise<AscApiKeyResult> {
|
||||
if (source.sourceType === AscApiKeySourceType.credentialsService) {
|
||||
return await getAscApiKeyFromCredentialsServiceAsync(ctx);
|
||||
} else {
|
||||
return await getAscApiKeyLocallyAsync(ctx, source);
|
||||
}
|
||||
}
|
||||
|
||||
async function maybeGetIosBundleIdentifierAsync(
|
||||
ctx: SubmissionContext<Platform.IOS>
|
||||
): Promise<string | null> {
|
||||
try {
|
||||
return await getBundleIdentifierAsync(ctx.projectDir, ctx.exp);
|
||||
} catch (error: any) {
|
||||
if (error instanceof AmbiguousBundleIdentifierError) {
|
||||
Log.warn(
|
||||
'bundleIdentifier in the Xcode project is ambiguous, specify it via "bundleIdentifier" field in the submit profile in the eas.json.'
|
||||
);
|
||||
return null;
|
||||
}
|
||||
throw new Error(`Failed to resolve bundleIdentifier in the Xcode project: ${error.message}.`);
|
||||
}
|
||||
}
|
||||
|
||||
async function promptForBundleIdentifierAsync(): Promise<string> {
|
||||
const { bundleIdentifier } = await promptAsync({
|
||||
name: 'bundleIdentifier',
|
||||
message: 'Bundle identifier:',
|
||||
type: 'text',
|
||||
validate: value => (isBundleIdentifierValid(value) ? true : INVALID_BUNDLE_IDENTIFIER_MESSAGE),
|
||||
});
|
||||
return bundleIdentifier;
|
||||
}
|
||||
|
||||
async function getAscApiKeyFromCredentialsServiceAsync(
|
||||
ctx: SubmissionContext<Platform.IOS>
|
||||
): Promise<AscApiKeyResult> {
|
||||
const bundleIdentifier =
|
||||
ctx.applicationIdentifierOverride ??
|
||||
ctx.profile.bundleIdentifier ??
|
||||
(await maybeGetIosBundleIdentifierAsync(ctx)) ??
|
||||
(await promptForBundleIdentifierAsync());
|
||||
Log.log(`Looking up credentials configuration for ${bundleIdentifier}...`);
|
||||
|
||||
const appLookupParams = {
|
||||
account: nullthrows(
|
||||
ctx.user.accounts.find(a => a.name === ctx.accountName),
|
||||
`You do not have access to account: ${ctx.accountName}`
|
||||
),
|
||||
projectName: ctx.projectName,
|
||||
bundleIdentifier,
|
||||
};
|
||||
const setupAscApiKeyAction = new SetUpAscApiKey(
|
||||
appLookupParams,
|
||||
AppStoreApiKeyPurpose.SUBMISSION_SERVICE
|
||||
);
|
||||
const iosAppCredentials = await setupAscApiKeyAction.runAsync(ctx.credentialsCtx);
|
||||
const ascKeyForSubmissions = nullthrows(
|
||||
iosAppCredentials.appStoreConnectApiKeyForSubmissions,
|
||||
`An EAS Submit ASC Api Key could not be found for ${iosAppCredentials.appleAppIdentifier.bundleIdentifier}`
|
||||
);
|
||||
const { id, keyIdentifier, name } = ascKeyForSubmissions;
|
||||
Log.log(`Using Api Key ID: ${keyIdentifier}${name ? ` (${name})` : ''}`);
|
||||
return {
|
||||
result: {
|
||||
ascApiKeyId: id,
|
||||
},
|
||||
summary: {
|
||||
source: 'EAS servers',
|
||||
keyId: keyIdentifier,
|
||||
name: name ?? undefined,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export async function getAscApiKeyLocallyAsync(
|
||||
ctx: SubmissionContext<Platform.IOS>,
|
||||
source: AscApiKeySource
|
||||
@@ -70,6 +168,8 @@ export async function getAscApiKeyPathAsync(
|
||||
return await handlePathSourceAsync(ctx, source);
|
||||
case AscApiKeySourceType.prompt:
|
||||
return await handlePromptSourceAsync(ctx, source);
|
||||
case AscApiKeySourceType.credentialsService:
|
||||
throw new Error(`AscApiKeySourceType ${source} does not return a path.`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
import { Platform } from '@expo/eas-build-job';
|
||||
import nullthrows from 'nullthrows';
|
||||
|
||||
import { SetUpSubmissionCredentials } from '../../credentials/ios/actions/SetUpSubmissionCredentials';
|
||||
import Log from '../../log';
|
||||
import {
|
||||
INVALID_BUNDLE_IDENTIFIER_MESSAGE,
|
||||
isBundleIdentifierValid,
|
||||
} from '../../project/ios/bundleIdentifier';
|
||||
import { promptAsync } from '../../prompts';
|
||||
import { SubmissionContext } from '../context';
|
||||
import {
|
||||
AppSpecificPasswordCredentials,
|
||||
getAppleIdUsernameAsync,
|
||||
} from './AppSpecificPasswordSource';
|
||||
import { AscApiKeyResult } from './AscApiKeySource';
|
||||
|
||||
/**
|
||||
* The Credentials Service will either return an ASC API Key or an App Specific Password
|
||||
* When we no longer support the App Specific Password user prompt, refactor this into the AscApiKeySource
|
||||
*/
|
||||
export const CREDENTIALS_SERVICE_SOURCE = 'CREDENTIALS_SERVICE_SOURCE' as const;
|
||||
export interface CredentialsServiceSource {
|
||||
sourceType: typeof CREDENTIALS_SERVICE_SOURCE;
|
||||
bundleIdentifier?: string;
|
||||
}
|
||||
|
||||
async function promptForBundleIdentifierAsync(): Promise<string> {
|
||||
const { bundleIdentifier } = await promptAsync({
|
||||
name: 'bundleIdentifier',
|
||||
message: 'Bundle identifier:',
|
||||
type: 'text',
|
||||
validate: value => (isBundleIdentifierValid(value) ? true : INVALID_BUNDLE_IDENTIFIER_MESSAGE),
|
||||
});
|
||||
return bundleIdentifier;
|
||||
}
|
||||
|
||||
export async function getFromCredentialsServiceAsync(
|
||||
ctx: SubmissionContext<Platform.IOS>,
|
||||
source: CredentialsServiceSource
|
||||
): Promise<
|
||||
{ appSpecificPassword: AppSpecificPasswordCredentials } | { ascApiKeyResult: AscApiKeyResult }
|
||||
> {
|
||||
const bundleIdentifier = source.bundleIdentifier ?? (await promptForBundleIdentifierAsync());
|
||||
Log.log(`Looking up credentials configuration for ${bundleIdentifier}...`);
|
||||
|
||||
const appLookupParams = {
|
||||
account: nullthrows(
|
||||
ctx.user.accounts.find(a => a.name === ctx.accountName),
|
||||
`You do not have access to account: ${ctx.accountName}`
|
||||
),
|
||||
projectName: ctx.projectName,
|
||||
bundleIdentifier,
|
||||
};
|
||||
const setupSubmissionCredentialsAction = new SetUpSubmissionCredentials(appLookupParams);
|
||||
const ascOrAsp = await setupSubmissionCredentialsAction.runAsync(ctx.credentialsCtx);
|
||||
const isAppSpecificPassword = typeof ascOrAsp === 'string';
|
||||
if (isAppSpecificPassword) {
|
||||
return {
|
||||
appSpecificPassword: {
|
||||
password: ascOrAsp,
|
||||
appleIdUsername: await getAppleIdUsernameAsync(ctx),
|
||||
},
|
||||
};
|
||||
} else {
|
||||
const ascKeyForSubmissions = nullthrows(
|
||||
ascOrAsp.appStoreConnectApiKeyForSubmissions,
|
||||
`An EAS Submit ASC API Key could not be found for ${ascOrAsp.appleAppIdentifier.bundleIdentifier}`
|
||||
);
|
||||
const { id, keyIdentifier, name } = ascKeyForSubmissions;
|
||||
return {
|
||||
ascApiKeyResult: {
|
||||
result: {
|
||||
ascApiKeyId: id,
|
||||
},
|
||||
summary: {
|
||||
source: 'EAS servers',
|
||||
keyId: keyIdentifier,
|
||||
name: name ?? undefined,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -7,10 +7,6 @@ import wrapAnsi from 'wrap-ansi';
|
||||
import { MissingCredentialsError } from '../../credentials/errors';
|
||||
import { SubmissionFragment } from '../../graphql/generated';
|
||||
import Log, { learnMore } from '../../log';
|
||||
import {
|
||||
AmbiguousBundleIdentifierError,
|
||||
getBundleIdentifierAsync,
|
||||
} from '../../project/ios/bundleIdentifier';
|
||||
import { ArchiveSource } from '../ArchiveSource';
|
||||
import { resolveArchiveSource } from '../commons';
|
||||
import { SubmissionContext } from '../context';
|
||||
@@ -20,7 +16,6 @@ import {
|
||||
AppSpecificPasswordSourceType,
|
||||
} from './AppSpecificPasswordSource';
|
||||
import { AscApiKeySource, AscApiKeySourceType } from './AscApiKeySource';
|
||||
import { CREDENTIALS_SERVICE_SOURCE, CredentialsServiceSource } from './CredentialsServiceSource';
|
||||
import IosSubmitter, { IosSubmissionOptions } from './IosSubmitter';
|
||||
|
||||
export default class IosSubmitCommand {
|
||||
@@ -42,17 +37,12 @@ export default class IosSubmitCommand {
|
||||
: null;
|
||||
const maybeAscApiKeySource =
|
||||
'ascApiKeySource' in credentialsSource ? credentialsSource.ascApiKeySource : null;
|
||||
const maybeCredentialsServiceSource =
|
||||
'credentialsServiceSource' in credentialsSource
|
||||
? credentialsSource.credentialsServiceSource
|
||||
: null;
|
||||
const ascAppIdentifier = await this.resolveAscAppIdentifierAsync();
|
||||
|
||||
const errored = [
|
||||
archiveSource,
|
||||
...(maybeAppSpecificPasswordSource ? [maybeAppSpecificPasswordSource] : []),
|
||||
...(maybeAscApiKeySource ? [maybeAscApiKeySource] : []),
|
||||
...(maybeCredentialsServiceSource ? [maybeCredentialsServiceSource] : []),
|
||||
ascAppIdentifier,
|
||||
].filter(r => !r.ok);
|
||||
if (errored.length > 0) {
|
||||
@@ -75,42 +65,14 @@ export default class IosSubmitCommand {
|
||||
ascApiKeySource: maybeAscApiKeySource.enforceValue(),
|
||||
}
|
||||
: null),
|
||||
...(maybeCredentialsServiceSource
|
||||
? {
|
||||
credentialsServiceSource: maybeCredentialsServiceSource.enforceValue(),
|
||||
}
|
||||
: null),
|
||||
};
|
||||
}
|
||||
|
||||
private async maybeGetIosBundleIdentifierAsync(): Promise<Result<string | null>> {
|
||||
try {
|
||||
return result(await getBundleIdentifierAsync(this.ctx.projectDir, this.ctx.exp));
|
||||
} catch (error: any) {
|
||||
if (error instanceof AmbiguousBundleIdentifierError) {
|
||||
Log.warn(
|
||||
'bundleIdentifier in the Xcode project is ambiguous, specify it via "bundleIdentifier" field in the submit profile in the eas.json.'
|
||||
);
|
||||
return result(null);
|
||||
}
|
||||
return result(
|
||||
new Error(`Failed to resolve bundleIdentifier in the Xcode project: ${error.message}.`)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private async resolveCredentialSubmissionOptionsAsync(): Promise<
|
||||
| { appSpecificPasswordSource: Result<AppSpecificPasswordSource> }
|
||||
| { ascApiKeySource: Result<AscApiKeySource> }
|
||||
| { credentialsServiceSource: Result<CredentialsServiceSource> }
|
||||
> {
|
||||
const ascApiKeySource = this.resolveAscApiKeySource();
|
||||
const shouldSkipAscApiKeySource =
|
||||
!ascApiKeySource.ok && ascApiKeySource.enforceError() instanceof MissingCredentialsError;
|
||||
if (!shouldSkipAscApiKeySource) {
|
||||
return { ascApiKeySource };
|
||||
}
|
||||
|
||||
// if an App Specific Password env var is not specified, use ASC Api Key
|
||||
const appSpecificPasswordSource = this.resolveAppSpecificPasswordSource();
|
||||
const shouldSkipAppSpecificPasswordSource =
|
||||
!appSpecificPasswordSource.ok &&
|
||||
@@ -119,26 +81,8 @@ export default class IosSubmitCommand {
|
||||
return { appSpecificPasswordSource: this.resolveAppSpecificPasswordSource() };
|
||||
}
|
||||
|
||||
let bundleIdentifier =
|
||||
this.ctx.applicationIdentifierOverride ?? this.ctx.profile.bundleIdentifier;
|
||||
if (!bundleIdentifier) {
|
||||
const bundleIdentifierResult = await this.maybeGetIosBundleIdentifierAsync();
|
||||
if (!bundleIdentifierResult.ok) {
|
||||
return {
|
||||
credentialsServiceSource: result(bundleIdentifierResult.reason),
|
||||
};
|
||||
}
|
||||
const bundleIdentifierValue = bundleIdentifierResult.enforceValue();
|
||||
if (bundleIdentifierValue) {
|
||||
bundleIdentifier = bundleIdentifierValue;
|
||||
}
|
||||
}
|
||||
return {
|
||||
credentialsServiceSource: result({
|
||||
sourceType: CREDENTIALS_SERVICE_SOURCE,
|
||||
bundleIdentifier,
|
||||
}),
|
||||
};
|
||||
const ascApiKeySource = this.resolveAscApiKeySource();
|
||||
return { ascApiKeySource };
|
||||
}
|
||||
|
||||
private resolveAppSpecificPasswordSource(): Result<AppSpecificPasswordSource> {
|
||||
@@ -187,11 +131,7 @@ export default class IosSubmitCommand {
|
||||
});
|
||||
}
|
||||
|
||||
return result(
|
||||
new MissingCredentialsError(
|
||||
'Set the ascApiKeyPath, ascApiKeyIssuerId and ascApiKeyId fields in eas.json.'
|
||||
)
|
||||
);
|
||||
return result({ sourceType: AscApiKeySourceType.credentialsService });
|
||||
}
|
||||
|
||||
private resolveArchiveSource(): Result<ArchiveSource> {
|
||||
|
||||
@@ -23,12 +23,8 @@ import {
|
||||
AscApiKeyFromExpoServers,
|
||||
AscApiKeyResult,
|
||||
AscApiKeySource,
|
||||
getAscApiKeyLocallyAsync,
|
||||
getAscApiKeyResultAsync,
|
||||
} from './AscApiKeySource';
|
||||
import {
|
||||
CredentialsServiceSource,
|
||||
getFromCredentialsServiceAsync,
|
||||
} from './CredentialsServiceSource';
|
||||
|
||||
export interface IosSubmissionOptions
|
||||
extends Pick<IosSubmissionConfigInput, 'appleIdUsername' | 'ascAppIdentifier'> {
|
||||
@@ -36,7 +32,6 @@ export interface IosSubmissionOptions
|
||||
archiveSource: ArchiveSource;
|
||||
appSpecificPasswordSource?: AppSpecificPasswordSource;
|
||||
ascApiKeySource?: AscApiKeySource;
|
||||
credentialsServiceSource?: CredentialsServiceSource;
|
||||
}
|
||||
|
||||
interface ResolvedSourceOptions {
|
||||
@@ -74,15 +69,11 @@ export default class IosSubmitter extends BaseSubmitter<
|
||||
)
|
||||
: null;
|
||||
const maybeAppStoreConnectApiKey = this.options.ascApiKeySource
|
||||
? await getAscApiKeyLocallyAsync(this.ctx, this.options.ascApiKeySource)
|
||||
: null;
|
||||
const maybeAscOrAspFromCredentialsService = this.options.credentialsServiceSource
|
||||
? await getFromCredentialsServiceAsync(this.ctx, this.options.credentialsServiceSource)
|
||||
? await getAscApiKeyResultAsync(this.ctx, this.options.ascApiKeySource)
|
||||
: null;
|
||||
return {
|
||||
...(maybeAppSpecificPassword ? { appSpecificPassword: maybeAppSpecificPassword } : null),
|
||||
...(maybeAppStoreConnectApiKey ? { ascApiKeyResult: maybeAppStoreConnectApiKey } : null),
|
||||
...(maybeAscOrAspFromCredentialsService ? maybeAscOrAspFromCredentialsService : null),
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
@@ -10,16 +10,19 @@ import {
|
||||
testAppQueryByIdResponse,
|
||||
testProjectId,
|
||||
} from '../../../credentials/__tests__/fixtures-constants';
|
||||
import { testCommonIosAppCredentialsFragment } from '../../../credentials/__tests__/fixtures-ios';
|
||||
import { SetUpAscApiKey } from '../../../credentials/ios/actions/SetUpAscApiKey';
|
||||
import { getCredentialsFromUserAsync } from '../../../credentials/utils/promptForCredentials';
|
||||
import { AppQuery } from '../../../graphql/queries/AppQuery';
|
||||
import { createTestProject } from '../../../project/__tests__/project-utils';
|
||||
import { getBundleIdentifierAsync } from '../../../project/ios/bundleIdentifier';
|
||||
import { promptAsync } from '../../../prompts';
|
||||
import { SubmissionContext, createSubmissionContextAsync } from '../../context';
|
||||
import {
|
||||
AscApiKeySource,
|
||||
AscApiKeySourceType,
|
||||
getAscApiKeyLocallyAsync,
|
||||
getAscApiKeyPathAsync,
|
||||
getAscApiKeyResultAsync,
|
||||
} from '../AscApiKeySource';
|
||||
|
||||
jest.mock('fs');
|
||||
@@ -29,6 +32,7 @@ jest.mock('../../../user/User', () => ({
|
||||
getUserAsync: jest.fn(() => mockJester),
|
||||
}));
|
||||
jest.mock('../../../graphql/queries/AppQuery');
|
||||
jest.mock('../../../project/ios/bundleIdentifier');
|
||||
|
||||
const testProject = createTestProject(testProjectId, mockJester.accounts[0].name, {
|
||||
android: {
|
||||
@@ -179,14 +183,14 @@ describe(getAscApiKeyPathAsync, () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe(getAscApiKeyLocallyAsync, () => {
|
||||
describe(getAscApiKeyResultAsync, () => {
|
||||
it('returns a local Asc API Key file with a AscApiKeySourceType.path source', async () => {
|
||||
const ctx = await getIosSubmissionContextAsync();
|
||||
const source: AscApiKeySource = {
|
||||
sourceType: AscApiKeySourceType.path,
|
||||
path: { keyP8Path: '/asc-api-key.p8', keyId: 'test-key-id', issuerId: 'test-issuer-id' },
|
||||
};
|
||||
const ascApiKeyResult = await getAscApiKeyLocallyAsync(ctx, source);
|
||||
const ascApiKeyResult = await getAscApiKeyResultAsync(ctx, source);
|
||||
expect(ascApiKeyResult).toMatchObject({
|
||||
result: {
|
||||
keyP8: 'super secret',
|
||||
@@ -213,7 +217,7 @@ describe(getAscApiKeyLocallyAsync, () => {
|
||||
const source: AscApiKeySource = {
|
||||
sourceType: AscApiKeySourceType.prompt,
|
||||
};
|
||||
const serviceAccountResult = await getAscApiKeyLocallyAsync(ctx, source);
|
||||
const serviceAccountResult = await getAscApiKeyResultAsync(ctx, source);
|
||||
expect(serviceAccountResult).toMatchObject({
|
||||
result: {
|
||||
keyP8: 'super secret',
|
||||
@@ -227,4 +231,45 @@ describe(getAscApiKeyLocallyAsync, () => {
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an Asc Api Key from server with a AscApiKeySourceType.credentialService source', async () => {
|
||||
const graphqlClient = {} as any as ExpoGraphqlClient;
|
||||
const analytics = instance(mock<Analytics>());
|
||||
const ctx = await createSubmissionContextAsync({
|
||||
platform: Platform.IOS,
|
||||
projectDir: testProject.projectRoot,
|
||||
archiveFlags: {
|
||||
url: 'http://expo.dev/fake.apk',
|
||||
},
|
||||
profile: {
|
||||
language: 'en-US',
|
||||
},
|
||||
nonInteractive: true,
|
||||
actor: mockJester,
|
||||
graphqlClient,
|
||||
analytics,
|
||||
exp: testProject.appJSON.expo,
|
||||
projectId,
|
||||
});
|
||||
const source: AscApiKeySource = {
|
||||
sourceType: AscApiKeySourceType.credentialsService,
|
||||
};
|
||||
jest
|
||||
.spyOn(SetUpAscApiKey.prototype, 'runAsync')
|
||||
.mockImplementation(async _ctx => testCommonIosAppCredentialsFragment);
|
||||
jest.mocked(getBundleIdentifierAsync).mockImplementation(async () => 'com.hello.world');
|
||||
|
||||
const result = await getAscApiKeyResultAsync(ctx, source);
|
||||
expect(result).toEqual({
|
||||
result: {
|
||||
ascApiKeyId: testCommonIosAppCredentialsFragment.appStoreConnectApiKeyForSubmissions?.id,
|
||||
},
|
||||
summary: {
|
||||
keyId:
|
||||
testCommonIosAppCredentialsFragment.appStoreConnectApiKeyForSubmissions?.keyIdentifier,
|
||||
name: testCommonIosAppCredentialsFragment.appStoreConnectApiKeyForSubmissions?.name,
|
||||
source: 'EAS servers',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,124 +0,0 @@
|
||||
import { Platform } from '@expo/eas-build-job';
|
||||
import { instance, mock } from 'ts-mockito';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import { Analytics } from '../../../analytics/AnalyticsManager';
|
||||
import { ExpoGraphqlClient } from '../../../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
import {
|
||||
jester as mockJester,
|
||||
testAppQueryByIdResponse,
|
||||
testProjectId,
|
||||
} from '../../../credentials/__tests__/fixtures-constants';
|
||||
import { testCommonIosAppCredentialsFragment } from '../../../credentials/__tests__/fixtures-ios';
|
||||
import { SetUpSubmissionCredentials } from '../../../credentials/ios/actions/SetUpSubmissionCredentials';
|
||||
import { AppQuery } from '../../../graphql/queries/AppQuery';
|
||||
import { createTestProject } from '../../../project/__tests__/project-utils';
|
||||
import { getBundleIdentifierAsync } from '../../../project/ios/bundleIdentifier';
|
||||
import { promptAsync } from '../../../prompts';
|
||||
import { createSubmissionContextAsync } from '../../context';
|
||||
import {
|
||||
CREDENTIALS_SERVICE_SOURCE,
|
||||
getFromCredentialsServiceAsync,
|
||||
} from '../CredentialsServiceSource';
|
||||
|
||||
jest.mock('fs');
|
||||
jest.mock('../../../prompts');
|
||||
jest.mock('../../../credentials/utils/promptForCredentials');
|
||||
jest.mock('../../../user/User', () => ({
|
||||
getUserAsync: jest.fn(() => mockJester),
|
||||
}));
|
||||
jest.mock('../../../project/ios/bundleIdentifier');
|
||||
jest.mock('../../../graphql/queries/AppQuery');
|
||||
|
||||
const testProject = createTestProject(testProjectId, mockJester.accounts[0].name, {
|
||||
android: {
|
||||
package: 'com.expo.test.project',
|
||||
},
|
||||
});
|
||||
const projectId = uuidv4();
|
||||
|
||||
beforeEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe(getFromCredentialsServiceAsync, () => {
|
||||
beforeEach(() => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue(testAppQueryByIdResponse);
|
||||
});
|
||||
|
||||
it('returns an App Specific Password from the credentialService source', async () => {
|
||||
const graphqlClient = instance(mock<ExpoGraphqlClient>());
|
||||
const analytics = instance(mock<Analytics>());
|
||||
const ctx = await createSubmissionContextAsync({
|
||||
platform: Platform.IOS,
|
||||
projectDir: testProject.projectRoot,
|
||||
archiveFlags: {
|
||||
url: 'http://expo.dev/fake.apk',
|
||||
},
|
||||
profile: {
|
||||
language: 'en-US',
|
||||
},
|
||||
nonInteractive: false,
|
||||
actor: mockJester,
|
||||
graphqlClient,
|
||||
analytics,
|
||||
exp: testProject.appJSON.expo,
|
||||
projectId,
|
||||
});
|
||||
jest
|
||||
.spyOn(SetUpSubmissionCredentials.prototype, 'runAsync')
|
||||
.mockImplementation(async _ctx => 'super secret');
|
||||
jest.mocked(getBundleIdentifierAsync).mockImplementation(async () => 'com.hello.world');
|
||||
jest.mocked(promptAsync).mockImplementationOnce(async () => ({ appleId: '[email protected]' }));
|
||||
|
||||
const result = await getFromCredentialsServiceAsync(ctx, {
|
||||
sourceType: CREDENTIALS_SERVICE_SOURCE,
|
||||
bundleIdentifier: 'com.expo.test.project',
|
||||
});
|
||||
expect(result).toEqual({
|
||||
appSpecificPassword: { password: 'super secret', appleIdUsername: '[email protected]' },
|
||||
});
|
||||
});
|
||||
it('returns an ASC API Key from the credentialService source', async () => {
|
||||
const graphqlClient = instance(mock<ExpoGraphqlClient>());
|
||||
const analytics = instance(mock<Analytics>());
|
||||
const ctx = await createSubmissionContextAsync({
|
||||
platform: Platform.IOS,
|
||||
projectDir: testProject.projectRoot,
|
||||
archiveFlags: {
|
||||
url: 'http://expo.dev/fake.apk',
|
||||
},
|
||||
profile: {
|
||||
language: 'en-US',
|
||||
},
|
||||
nonInteractive: true,
|
||||
actor: mockJester,
|
||||
graphqlClient,
|
||||
analytics,
|
||||
exp: testProject.appJSON.expo,
|
||||
projectId,
|
||||
});
|
||||
jest
|
||||
.spyOn(SetUpSubmissionCredentials.prototype, 'runAsync')
|
||||
.mockImplementation(async _ctx => testCommonIosAppCredentialsFragment);
|
||||
jest.mocked(getBundleIdentifierAsync).mockImplementation(async () => 'com.hello.world');
|
||||
|
||||
const result = await getFromCredentialsServiceAsync(ctx, {
|
||||
sourceType: CREDENTIALS_SERVICE_SOURCE,
|
||||
bundleIdentifier: 'com.expo.test.project',
|
||||
});
|
||||
expect(result).toEqual({
|
||||
ascApiKeyResult: {
|
||||
result: {
|
||||
ascApiKeyId: testCommonIosAppCredentialsFragment.appStoreConnectApiKeyForSubmissions?.id,
|
||||
},
|
||||
summary: {
|
||||
keyId:
|
||||
testCommonIosAppCredentialsFragment.appStoreConnectApiKeyForSubmissions?.keyIdentifier,
|
||||
name: testCommonIosAppCredentialsFragment.appStoreConnectApiKeyForSubmissions?.name,
|
||||
source: 'EAS servers',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -53,7 +53,7 @@ export async function readChannelSafelyAsync(projectDir: string): Promise<string
|
||||
try {
|
||||
const expoPlist = await readExpoPlistAsync(projectDir);
|
||||
const updatesRequestHeaders = expoPlist['EXUpdatesRequestHeaders'];
|
||||
return updatesRequestHeaders['expo-channel-name'] ?? null;
|
||||
return updatesRequestHeaders?.['expo-channel-name'] ?? null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
"outDir": "build",
|
||||
"rootDir": "src",
|
||||
"typeRoots": [
|
||||
"../../node_modules/@types",
|
||||
"../../ts-declarations",
|
||||
"../../node_modules/@types",
|
||||
"./node_modules/@types"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@expo/eas-json",
|
||||
"description": "A library for interacting with eas.json",
|
||||
"version": "3.12.1",
|
||||
"version": "3.13.0",
|
||||
"author": "Expo <[email protected]>",
|
||||
"bugs": "https://github.com/expo/eas-cli/issues",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "7.18.6",
|
||||
"@expo/eas-build-job": "1.0.12",
|
||||
"@expo/eas-build-job": "1.0.13",
|
||||
"chalk": "4.1.2",
|
||||
"env-string": "1.0.1",
|
||||
"fs-extra": "10.1.0",
|
||||
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
declare module 'prompts/lib/elements' {
|
||||
class MultiselectPrompt {
|
||||
selectionFormat: string | undefined;
|
||||
done: boolean | undefined;
|
||||
value: any[] | undefined;
|
||||
|
||||
constructor(parameters: any);
|
||||
on(event: string, callback: (args: any) => any): any;
|
||||
renderDoneOrInstructions(): string;
|
||||
}
|
||||
}
|
||||
@@ -1347,7 +1347,28 @@
|
||||
node-forge "^1.2.1"
|
||||
nullthrows "^1.1.1"
|
||||
|
||||
"@expo/config-plugins@5.0.4", "@expo/config-plugins@~5.0.3":
|
||||
"@expo/config-plugins@6.0.2":
|
||||
version "6.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-6.0.2.tgz#cf07319515022ba94d9aa9fa30e0cff43a14256f"
|
||||
integrity sha512-Cn01fXMHwjU042EgO9oO3Mna0o/UCrW91MQLMbJa4pXM41CYGjNgVy1EVXiuRRx/upegHhvltBw5D+JaUm8aZQ==
|
||||
dependencies:
|
||||
"@expo/config-types" "^48.0.0"
|
||||
"@expo/json-file" "~8.2.37"
|
||||
"@expo/plist" "^0.0.20"
|
||||
"@expo/sdk-runtime-versions" "^1.0.0"
|
||||
"@react-native/normalize-color" "^2.0.0"
|
||||
chalk "^4.1.2"
|
||||
debug "^4.3.1"
|
||||
find-up "~5.0.0"
|
||||
getenv "^1.0.0"
|
||||
glob "7.1.6"
|
||||
resolve-from "^5.0.0"
|
||||
semver "^7.3.5"
|
||||
slash "^3.0.0"
|
||||
xcode "^3.0.1"
|
||||
xml2js "0.4.23"
|
||||
|
||||
"@expo/config-plugins@~5.0.3":
|
||||
version "5.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-5.0.4.tgz#216fea6558fe66615af1370de55193f4181cb23e"
|
||||
integrity sha512-vzUcVpqOMs3h+hyRdhGwk+eGIOhXa5xYdd92yO17RMNHav3v/+ekMbs7XA2c3lepMO8Yd4/5hqmRw9ZTL6jGzg==
|
||||
@@ -1373,6 +1394,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@expo/config-types/-/config-types-47.0.0.tgz#99eeabe0bba7a776e0f252b78beb0c574692c38d"
|
||||
integrity sha512-r0pWfuhkv7KIcXMUiNACJmJKKwlTBGMw9VZHNdppS8/0Nve8HZMTkNRFQzTHW1uH3pBj8jEXpyw/2vSWDHex9g==
|
||||
|
||||
"@expo/config-types@^48.0.0":
|
||||
version "48.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@expo/config-types/-/config-types-48.0.0.tgz#15a46921565ffeda3c3ba010701398f05193d5b3"
|
||||
integrity sha512-DwyV4jTy/+cLzXGAo1xftS6mVlSiLIWZjl9DjTCLPFVgNYQxnh7htPilRv4rBhiNs7KaznWqKU70+4zQoKVT9A==
|
||||
|
||||
"@expo/[email protected]", "@expo/config@~7.0.2":
|
||||
version "7.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@expo/config/-/config-7.0.3.tgz#c9c634e76186de25e296485e51418f1e52966e6e"
|
||||
@@ -1390,10 +1416,10 @@
|
||||
slugify "^1.3.4"
|
||||
sucrase "^3.20.0"
|
||||
|
||||
"@expo/[email protected]2":
|
||||
version "1.0.12"
|
||||
resolved "https://registry.yarnpkg.com/@expo/eas-build-job/-/eas-build-job-1.0.12.tgz#1538abb3013f54b2b1b58858dc6c9cad5114962a"
|
||||
integrity sha512-MyOBSjKiySLsTA8exw7nLK8SdzRok9EZT0mmesWzpMDjZI0fuoEYDnj0ODKTpoJE3X0LW+c5a9pfx9/QbkSn5Q==
|
||||
"@expo/[email protected]3":
|
||||
version "1.0.13"
|
||||
resolved "https://registry.yarnpkg.com/@expo/eas-build-job/-/eas-build-job-1.0.13.tgz#1cd3981e86e1d4235f20a96f7ac768793b4f7c62"
|
||||
integrity sha512-Q0i3GposBj/b2OPL0CV00HczawtslorNpoJSBQfB4aNR6i7DBIZZ1jWJtrFP8+zHZqlUi4d21aoblNUrKpgBew==
|
||||
dependencies:
|
||||
joi "^17.7.0"
|
||||
semver "^7.3.8"
|
||||
@@ -1424,7 +1450,7 @@
|
||||
json5 "^1.0.1"
|
||||
write-file-atomic "^2.3.0"
|
||||
|
||||
"@expo/[email protected]":
|
||||
"@expo/[email protected]", "@expo/json-file@~8.2.37":
|
||||
version "8.2.37"
|
||||
resolved "https://registry.yarnpkg.com/@expo/json-file/-/json-file-8.2.37.tgz#9c02d3b42134907c69cc0a027b18671b69344049"
|
||||
integrity sha512-YaH6rVg11JoTS2P6LsW7ybS2CULjf40AbnAHw2F1eDPuheprNjARZMnyHFPkKv7GuxCy+B9GPcbOKgc4cgA80Q==
|
||||
@@ -1433,10 +1459,10 @@
|
||||
json5 "^2.2.2"
|
||||
write-file-atomic "^2.3.0"
|
||||
|
||||
"@expo/[email protected].0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@expo/logger/-/logger-1.0.0.tgz#41f17209e11aa83eabd5722c0efbc5b80efc7c41"
|
||||
integrity sha512-i07o2xUsmtpC2mQ3ZHOJRtFEqWTfQabOb3U5Q0Hwip/BvI0yj8Pweu2ExhKLERbGugt4tSSLdQJUcKQbOrue6g==
|
||||
"@expo/[email protected].13":
|
||||
version "1.0.13"
|
||||
resolved "https://registry.yarnpkg.com/@expo/logger/-/logger-1.0.13.tgz#f9d02d76867aaaa7e33b30dc5a493202da5d5414"
|
||||
integrity sha512-x1dp47CCR/mohJcYhg1cv17nDP2ih5MqQcW4CJL02GpNYPlvWSR5V5203kmOdYdCWq2Rs1j45Yo9VmpS2dxSfw==
|
||||
dependencies:
|
||||
"@expo/bunyan" "^4.0.0"
|
||||
|
||||
@@ -1489,7 +1515,7 @@
|
||||
base64-js "^1.2.3"
|
||||
xmlbuilder "^14.0.0"
|
||||
|
||||
"@expo/[email protected]":
|
||||
"@expo/[email protected]", "@expo/plist@^0.0.20":
|
||||
version "0.0.20"
|
||||
resolved "https://registry.yarnpkg.com/@expo/plist/-/plist-0.0.20.tgz#a6b3124438031c02b762bad5a47b70584d3c0072"
|
||||
integrity sha512-UXQ4LXCfTZ580LDHGJ5q62jSTwJFFJ1GqBu8duQMThiHKWbMJ+gajJh6rsB6EJ3aLUr9wcauxneL5LVRFxwBEA==
|
||||
@@ -1579,12 +1605,12 @@
|
||||
dependencies:
|
||||
cross-spawn "^7.0.3"
|
||||
|
||||
"@expo/[email protected]1":
|
||||
version "1.0.11"
|
||||
resolved "https://registry.yarnpkg.com/@expo/steps/-/steps-1.0.11.tgz#d839674ad96655dde7e5ee424923d553dc48c6c6"
|
||||
integrity sha512-9PTW4Y4RTJoqVxViMvyFoypNVEipcdjVntfOSKPHNZMFxD9GOMTmgYebJPeiz3dZrIRSyV9s8ABmbZSxABgIBA==
|
||||
"@expo/[email protected]3":
|
||||
version "1.0.13"
|
||||
resolved "https://registry.yarnpkg.com/@expo/steps/-/steps-1.0.13.tgz#97d448055a8fda8c1e04b2c7c95e2e9cfae3820e"
|
||||
integrity sha512-Hf8VFgwaFsvIb9/8r02/RO5eb1gDUSVyBFgBYVb3iMJvjoZXv74+mJllbh3x1EO28ai68vcEtp8uZ8Su2sLuwg==
|
||||
dependencies:
|
||||
"@expo/logger" "1.0.0"
|
||||
"@expo/logger" "1.0.13"
|
||||
"@expo/spawn-async" "^1.7.0"
|
||||
arg "^5.0.2"
|
||||
joi "^17.7.0"
|
||||
|
||||
Reference in new issue
Block a user