mirror of
https://github.com/expo/eas-cli.git
synced 2026-11-13 20:28:08 -10:00
Compare commits
56
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
819f0b4c6f | ||
|
|
9ffd3a096b | ||
|
|
e3ff26e1ca | ||
|
|
bbd26a8030 | ||
|
|
57dd372957 | ||
|
|
5232641217 | ||
|
|
3c3d3150c9 | ||
|
|
fd322d4189 | ||
|
|
77254f6be1 | ||
|
|
44fcbbaf17 | ||
|
|
db841b45ee | ||
|
|
568669d384 | ||
|
|
aa50bf11ce | ||
|
|
119133360b | ||
|
|
3f0f25dd46 | ||
|
|
e821ae95e1 | ||
|
|
f4e51b4fbc | ||
|
|
963bea9b03 | ||
|
|
9bf2020b2b | ||
|
|
50e695b5a3 | ||
|
|
f3577deac4 | ||
|
|
f11c0b4d34 | ||
|
|
88411e8fc0 | ||
|
|
c199173704 | ||
|
|
800098b958 | ||
|
|
146468914f | ||
|
|
0e48417983 | ||
|
|
cf61f585e6 | ||
|
|
cc700ae263 | ||
|
|
4e94c60c7f | ||
|
|
37f8e117e1 | ||
|
|
46095d2da4 | ||
|
|
6c01856617 | ||
|
|
f8cd50e0ed | ||
|
|
fd0a129a4f | ||
|
|
c44e07bfeb | ||
|
|
951583e6ea | ||
|
|
3f9247ca84 | ||
|
|
c38638e94e | ||
|
|
3b46466a9d | ||
|
|
806085cbf1 | ||
|
|
398b41cc81 | ||
|
|
d23a97238b | ||
|
|
5b6f312ccb | ||
|
|
2bcab0f2b4 | ||
|
|
b90ce63067 | ||
|
|
be02aced9d | ||
|
|
f788b081c6 | ||
|
|
654f973d0e | ||
|
|
2e614cbde9 | ||
|
|
b7150163d9 | ||
|
|
0922121e84 | ||
|
|
4ace7d20fb | ||
|
|
4ae9aed8f6 | ||
|
|
54d6079406 | ||
|
|
f08adad1e7 |
No files matched your search
@@ -8,10 +8,76 @@ This is the log of notable changes to EAS CLI and related packages.
|
||||
|
||||
### 🎉 New features
|
||||
|
||||
- Add styling to SSO auth redirect completion page. ([#1929](https://github.com/expo/eas-cli/pull/1929) by [@wschurman](https://github.com/wschurman))
|
||||
- Ignore entitlements from native template when `/ios` is gitignored. ([#1906](https://github.com/expo/eas-cli/pull/1906) by [@byCedric](https://github.com/byCedric))
|
||||
- Use node server default port selection for SSO login server. ([#1930](https://github.com/expo/eas-cli/pull/1930) by [@wschurman](https://github.com/wschurman))
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Limit project file upload size to 2GB. ([#1928](https://github.com/expo/eas-cli/pull/1928) by [@khamilowicz](https://github.com/khamilowicz))
|
||||
- Bump urql graphql client major version. ([#1936](https://github.com/expo/eas-cli/pull/1936) by [@quinlanj](https://github.com/quinlanj))
|
||||
|
||||
## [3.15.1](https://github.com/expo/eas-cli/releases/tag/v3.15.1) - 2023-07-11
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
- Ensure useClassicUpdates is not set when using EAS Update commands. ([#1915](https://github.com/expo/eas-cli/pull/1915) by [@ide](https://github.com/ide))
|
||||
- Handle multiple GraphQLErrors when receiving a CombinedError. ([#1924](https://github.com/expo/eas-cli/pull/1924) by [@radoslawkrzemien](https://github.com/radoslawkrzemien))
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Bump Expo package dependencies. ([#1911](https://github.com/expo/eas-cli/pull/1911) by [@brentvatne](https://github.com/brentvatne))
|
||||
- Better bare workflow runtimeVersion error. ([#1910](https://github.com/expo/eas-cli/pull/1910) by [@quinlanj](https://github.com/quinlanj))
|
||||
- Fix runtime version print logs. ([#1925](https://github.com/expo/eas-cli/pull/1925) by [@quinlanj](https://github.com/quinlanj))
|
||||
- Add info about new `macos-ventura-13.4-xcode-14.3.1` image to `eas.schema.json`. ([#1920](https://github.com/expo/eas-cli/pull/1920) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
|
||||
## [3.15.0](https://github.com/expo/eas-cli/releases/tag/v3.15.0) - 2023-06-30
|
||||
|
||||
### 🎉 New features
|
||||
|
||||
- Show build profile when selecting a build for eas build:run. ([#1901](https://github.com/expo/eas-cli/pull/1901) by [@keith-kurak](https://github.com/keith-kurak))
|
||||
- Adds -m alias to --message in update/republish and removed README comment. ([#1905](https://github.com/expo/eas-cli/pull/1905) by [@pusongqi](https://github.com/pusongqi))
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Better runtimeVersion output. ([#1894](https://github.com/expo/eas-cli/pull/1894) by [@quinlanj](https://github.com/quinlanj))
|
||||
- Print better error message when uploading project archive tarball fails. ([#1897](https://github.com/expo/eas-cli/pull/1897) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
- Adds support for 2 new server-side errors related to build limits. ([#1921](https://github.com/expo/eas-cli/pull/1921) by [@sundeeppeswani](https://github.com/sundeeppeswani))
|
||||
|
||||
## [3.14.0](https://github.com/expo/eas-cli/releases/tag/v3.14.0) - 2023-06-20
|
||||
|
||||
### 🎉 New features
|
||||
|
||||
- Added support for SSO users. ([#1875](https://github.com/expo/eas-cli/pull/1875) by [@lzkb](https://github.com/lzkb))
|
||||
- Added new bundle identifier capabilities and entitlements from WWDC23. ([#1870](https://github.com/expo/eas-cli/pull/1870) by [@EvanBacon](https://github.com/EvanBacon))
|
||||
- Selecting default keystore via CLI. ([#1889](https://github.com/expo/eas-cli/pull/1889) by [@khamilowicz](https://github.com/khamilowicz))
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Change sso flag display. ([#1890](https://github.com/expo/eas-cli/pull/1890) by [@lzkb](https://github.com/lzkb))
|
||||
- Build:configure -- add channels to eas.json if using eas updates. ([#1887](https://github.com/expo/eas-cli/pull/1887) by [@quinlanj](https://github.com/quinlanj))
|
||||
- Eas update: Error gracefully if no git repo. ([#1884](https://github.com/expo/eas-cli/pull/1884) by [@quinlanj](https://github.com/quinlanj))
|
||||
- Error gracefully if expo pkg not installed. ([#1883](https://github.com/expo/eas-cli/pull/1883) by [@quinlanj](https://github.com/quinlanj))
|
||||
- Update `eas build:configure` command to show the link of `eas.json` when generated. ([#1878](https://github.com/expo/eas-cli/pull/1878) by [@amandeepmittal](https://github.com/amandeepmittal))
|
||||
- Create app.json or add the "expo" key if either are missing, before modifying or reading the file. ([#1881](https://github.com/expo/eas-cli/pull/1881) by [@brentvatne](https://github.com/brentvatne))
|
||||
- Include the original stack in re-thrown errors thrown from EAS CLI commands. ([#1882](https://github.com/expo/eas-cli/pull/1882) by [@brentvatne](https://github.com/brentvatne))
|
||||
- Make `update:configure` less verbose. ([#1888](https://github.com/expo/eas-cli/pull/1888) by [@quinlanj](https://github.com/quinlanj))
|
||||
- Improve validation for values from app config. ([#1893](https://github.com/expo/eas-cli/pull/1893) by [@wkozyra95](https://github.com/wkozyra95))
|
||||
- Improve `expo-updates` validation for builds with `channel` property set. ([#1885](https://github.com/expo/eas-cli/pull/1885) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
|
||||
## [3.13.3](https://github.com/expo/eas-cli/releases/tag/v3.13.3) - 2023-06-05
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
- Show original GraphQL error message in case of an unexpected error. ([#1862](https://github.com/expo/eas-cli/pull/1862) by [@dsokal](https://github.com/dsokal))
|
||||
- Fix updates synchronization of native files to include strings.xml for bare projects. ([#1865](https://github.com/expo/eas-cli/pull/1865) by [@wschurman](https://github.com/wschurman))
|
||||
|
||||
## [3.13.2](https://github.com/expo/eas-cli/releases/tag/v3.13.2) - 2023-05-26
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Refactor getExpoConfig to remove dangerous default. ([#1857](https://github.com/expo/eas-cli/pull/1857) by [@wschurman](https://github.com/wschurman))
|
||||
- Add support for pending-cancel build status. ([#1855](https://github.com/expo/eas-cli/pull/1855) by [@radoslawkrzemien](https://github.com/radoslawkrzemien))
|
||||
|
||||
@@ -28,6 +94,7 @@ This is the log of notable changes to EAS CLI and related packages.
|
||||
### 🎉 New features
|
||||
|
||||
- Add clear cache flag to eas update. ([#1839](https://github.com/expo/eas-cli/pull/1839) by [@quinlanj](https://github.com/quinlanj))
|
||||
- Print EAS Update assets that timed out during upload or processing. ([#1849](https://github.com/expo/eas-cli/pull/1849) by [@wschurman](https://github.com/wschurman))
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
|
||||
+6
-6
@@ -1,10 +1,10 @@
|
||||
* @dsokal @wkozyra95
|
||||
* @szdziedzic @khamilowicz
|
||||
|
||||
packages/eas-cli/src/build @dsokal @wkozyra95
|
||||
packages/eas-cli/src/commands/build @dsokal @wkozyra95
|
||||
packages/eas-cli/src/build @szdziedzic @khamilowicz
|
||||
packages/eas-cli/src/commands/build @szdziedzic @khamilowicz
|
||||
|
||||
packages/eas-cli/src/submit @dsokal
|
||||
packages/eas-cli/src/commands/submit.ts @dsokal
|
||||
packages/eas-cli/src/submit @szdziedzic @khamilowicz
|
||||
packages/eas-cli/src/commands/submit.ts @szdziedzic @khamilowicz
|
||||
|
||||
packages/eas-cli/src/update @EvanBacon @byCedric @wschurman
|
||||
packages/eas-cli/src/commands/update @EvanBacon @byCedric @wschurman
|
||||
@@ -13,4 +13,4 @@ packages/eas-cli/schema @bycedric
|
||||
packages/eas-cli/src/metadata @bycedric
|
||||
packages/eas-cli/src/commands/metadata @bycedric
|
||||
|
||||
packages/eas-json @dsokal @wkozyra95
|
||||
packages/eas-json @szdziedzic @khamilowicz
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true,
|
||||
"version": "3.13.2",
|
||||
"version": "3.15.1",
|
||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json"
|
||||
}
|
||||
+61
-61
@@ -133,7 +133,7 @@ ALIASES
|
||||
$ eas login
|
||||
```
|
||||
|
||||
_See code: [src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/account/login.ts)_
|
||||
_See code: [src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v3.15.1/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.13.2/packages/eas-cli/src/commands/account/logout.ts)_
|
||||
_See code: [src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v3.15.1/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.13.2/packages/eas-cli/src/commands/account/view.ts)_
|
||||
_See code: [src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v3.15.1/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.13.2/packages/eas-cli/src/commands/analytics.ts)_
|
||||
_See code: [src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v3.15.1/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.13.2/packages/eas-cli/src/commands/branch/create.ts)_
|
||||
_See code: [src/commands/branch/create.ts](https://github.com/expo/eas-cli/blob/v3.15.1/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.13.2/packages/eas-cli/src/commands/branch/delete.ts)_
|
||||
_See code: [src/commands/branch/delete.ts](https://github.com/expo/eas-cli/blob/v3.15.1/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.13.2/packages/eas-cli/src/commands/branch/list.ts)_
|
||||
_See code: [src/commands/branch/list.ts](https://github.com/expo/eas-cli/blob/v3.15.1/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.13.2/packages/eas-cli/src/commands/branch/rename.ts)_
|
||||
_See code: [src/commands/branch/rename.ts](https://github.com/expo/eas-cli/blob/v3.15.1/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.13.2/packages/eas-cli/src/commands/branch/view.ts)_
|
||||
_See code: [src/commands/branch/view.ts](https://github.com/expo/eas-cli/blob/v3.15.1/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.13.2/packages/eas-cli/src/commands/build/index.ts)_
|
||||
_See code: [src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v3.15.1/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.13.2/packages/eas-cli/src/commands/build/cancel.ts)_
|
||||
_See code: [src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v3.15.1/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.13.2/packages/eas-cli/src/commands/build/configure.ts)_
|
||||
_See code: [src/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v3.15.1/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.13.2/packages/eas-cli/src/commands/build/inspect.ts)_
|
||||
_See code: [src/commands/build/inspect.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/build/inspect.ts)_
|
||||
|
||||
## `eas build:list`
|
||||
|
||||
@@ -452,7 +452,7 @@ DESCRIPTION
|
||||
list all builds for your project
|
||||
```
|
||||
|
||||
_See code: [src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/build/list.ts)_
|
||||
_See code: [src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/build/list.ts)_
|
||||
|
||||
## `eas build:resign`
|
||||
|
||||
@@ -478,7 +478,7 @@ DESCRIPTION
|
||||
re-sign a build archive
|
||||
```
|
||||
|
||||
_See code: [src/commands/build/resign.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/build/resign.ts)_
|
||||
_See code: [src/commands/build/resign.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/build/resign.ts)_
|
||||
|
||||
## `eas build:run`
|
||||
|
||||
@@ -502,7 +502,7 @@ DESCRIPTION
|
||||
run simulator/emulator builds from eas-cli
|
||||
```
|
||||
|
||||
_See code: [src/commands/build/run.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/build/run.ts)_
|
||||
_See code: [src/commands/build/run.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/build/run.ts)_
|
||||
|
||||
## `eas build:submit`
|
||||
|
||||
@@ -551,7 +551,7 @@ DESCRIPTION
|
||||
get the latest version from EAS servers
|
||||
```
|
||||
|
||||
_See code: [src/commands/build/version/get.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/build/version/get.ts)_
|
||||
_See code: [src/commands/build/version/get.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/build/version/get.ts)_
|
||||
|
||||
## `eas build:version:set`
|
||||
|
||||
@@ -570,7 +570,7 @@ DESCRIPTION
|
||||
update version of an app
|
||||
```
|
||||
|
||||
_See code: [src/commands/build/version/set.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/build/version/set.ts)_
|
||||
_See code: [src/commands/build/version/set.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/build/version/set.ts)_
|
||||
|
||||
## `eas build:version:sync`
|
||||
|
||||
@@ -589,7 +589,7 @@ DESCRIPTION
|
||||
update a version in native code with a value stored on EAS servers
|
||||
```
|
||||
|
||||
_See code: [src/commands/build/version/sync.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/build/version/sync.ts)_
|
||||
_See code: [src/commands/build/version/sync.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/build/version/sync.ts)_
|
||||
|
||||
## `eas build:view [BUILD_ID]`
|
||||
|
||||
@@ -606,7 +606,7 @@ DESCRIPTION
|
||||
view a build for your project
|
||||
```
|
||||
|
||||
_See code: [src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/build/view.ts)_
|
||||
_See code: [src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/build/view.ts)_
|
||||
|
||||
## `eas channel:create [NAME]`
|
||||
|
||||
@@ -627,7 +627,7 @@ DESCRIPTION
|
||||
create a channel
|
||||
```
|
||||
|
||||
_See code: [src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/channel/create.ts)_
|
||||
_See code: [src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/channel/create.ts)_
|
||||
|
||||
## `eas channel:edit [NAME]`
|
||||
|
||||
@@ -649,7 +649,7 @@ DESCRIPTION
|
||||
point a channel at a new branch
|
||||
```
|
||||
|
||||
_See code: [src/commands/channel/edit.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/channel/edit.ts)_
|
||||
_See code: [src/commands/channel/edit.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/channel/edit.ts)_
|
||||
|
||||
## `eas channel:list`
|
||||
|
||||
@@ -669,7 +669,7 @@ DESCRIPTION
|
||||
list all channels
|
||||
```
|
||||
|
||||
_See code: [src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/channel/list.ts)_
|
||||
_See code: [src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/channel/list.ts)_
|
||||
|
||||
## `eas channel:rollout [CHANNEL]`
|
||||
|
||||
@@ -693,7 +693,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.13.2/packages/eas-cli/src/commands/channel/rollout.ts)_
|
||||
_See code: [src/commands/channel/rollout.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/channel/rollout.ts)_
|
||||
|
||||
## `eas channel:view [NAME]`
|
||||
|
||||
@@ -716,7 +716,7 @@ DESCRIPTION
|
||||
view a channel
|
||||
```
|
||||
|
||||
_See code: [src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/channel/view.ts)_
|
||||
_See code: [src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/channel/view.ts)_
|
||||
|
||||
## `eas config`
|
||||
|
||||
@@ -737,7 +737,7 @@ DESCRIPTION
|
||||
display project configuration (app.json + eas.json)
|
||||
```
|
||||
|
||||
_See code: [src/commands/config.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/config.ts)_
|
||||
_See code: [src/commands/config.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/config.ts)_
|
||||
|
||||
## `eas credentials`
|
||||
|
||||
@@ -754,7 +754,7 @@ DESCRIPTION
|
||||
manage credentials
|
||||
```
|
||||
|
||||
_See code: [src/commands/credentials.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/credentials.ts)_
|
||||
_See code: [src/commands/credentials.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/credentials.ts)_
|
||||
|
||||
## `eas device:create`
|
||||
|
||||
@@ -768,7 +768,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.13.2/packages/eas-cli/src/commands/device/create.ts)_
|
||||
_See code: [src/commands/device/create.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/device/create.ts)_
|
||||
|
||||
## `eas device:delete`
|
||||
|
||||
@@ -788,7 +788,7 @@ DESCRIPTION
|
||||
remove a registered device from your account
|
||||
```
|
||||
|
||||
_See code: [src/commands/device/delete.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/device/delete.ts)_
|
||||
_See code: [src/commands/device/delete.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/device/delete.ts)_
|
||||
|
||||
## `eas device:list`
|
||||
|
||||
@@ -809,7 +809,7 @@ DESCRIPTION
|
||||
list all registered devices for your account
|
||||
```
|
||||
|
||||
_See code: [src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/device/list.ts)_
|
||||
_See code: [src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/device/list.ts)_
|
||||
|
||||
## `eas device:rename`
|
||||
|
||||
@@ -830,7 +830,7 @@ DESCRIPTION
|
||||
rename a registered device
|
||||
```
|
||||
|
||||
_See code: [src/commands/device/rename.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/device/rename.ts)_
|
||||
_See code: [src/commands/device/rename.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/device/rename.ts)_
|
||||
|
||||
## `eas device:view [UDID]`
|
||||
|
||||
@@ -844,7 +844,7 @@ DESCRIPTION
|
||||
view a device for your project
|
||||
```
|
||||
|
||||
_See code: [src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/device/view.ts)_
|
||||
_See code: [src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/device/view.ts)_
|
||||
|
||||
## `eas diagnostics`
|
||||
|
||||
@@ -858,7 +858,7 @@ DESCRIPTION
|
||||
display environment info
|
||||
```
|
||||
|
||||
_See code: [src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/diagnostics.ts)_
|
||||
_See code: [src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/diagnostics.ts)_
|
||||
|
||||
## `eas help [COMMAND]`
|
||||
|
||||
@@ -946,7 +946,7 @@ DESCRIPTION
|
||||
validate the local store configuration
|
||||
```
|
||||
|
||||
_See code: [src/commands/metadata/lint.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/metadata/lint.ts)_
|
||||
_See code: [src/commands/metadata/lint.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/metadata/lint.ts)_
|
||||
|
||||
## `eas metadata:pull`
|
||||
|
||||
@@ -963,7 +963,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.13.2/packages/eas-cli/src/commands/metadata/pull.ts)_
|
||||
_See code: [src/commands/metadata/pull.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/metadata/pull.ts)_
|
||||
|
||||
## `eas metadata:push`
|
||||
|
||||
@@ -980,7 +980,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.13.2/packages/eas-cli/src/commands/metadata/push.ts)_
|
||||
_See code: [src/commands/metadata/push.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/metadata/push.ts)_
|
||||
|
||||
## `eas open`
|
||||
|
||||
@@ -994,7 +994,7 @@ DESCRIPTION
|
||||
open the project page in a web browser
|
||||
```
|
||||
|
||||
_See code: [src/commands/open.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/open.ts)_
|
||||
_See code: [src/commands/open.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/open.ts)_
|
||||
|
||||
## `eas project:info`
|
||||
|
||||
@@ -1008,7 +1008,7 @@ DESCRIPTION
|
||||
information about the current project
|
||||
```
|
||||
|
||||
_See code: [src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/project/info.ts)_
|
||||
_See code: [src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/project/info.ts)_
|
||||
|
||||
## `eas project:init`
|
||||
|
||||
@@ -1030,7 +1030,7 @@ ALIASES
|
||||
$ eas init
|
||||
```
|
||||
|
||||
_See code: [src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/project/init.ts)_
|
||||
_See code: [src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/project/init.ts)_
|
||||
|
||||
## `eas secret:create`
|
||||
|
||||
@@ -1053,7 +1053,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.13.2/packages/eas-cli/src/commands/secret/create.ts)_
|
||||
_See code: [src/commands/secret/create.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/secret/create.ts)_
|
||||
|
||||
## `eas secret:delete`
|
||||
|
||||
@@ -1071,7 +1071,7 @@ DESCRIPTION
|
||||
delete an environment secret by ID
|
||||
```
|
||||
|
||||
_See code: [src/commands/secret/delete.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/secret/delete.ts)_
|
||||
_See code: [src/commands/secret/delete.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/secret/delete.ts)_
|
||||
|
||||
## `eas secret:list`
|
||||
|
||||
@@ -1085,7 +1085,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.13.2/packages/eas-cli/src/commands/secret/list.ts)_
|
||||
_See code: [src/commands/secret/list.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/secret/list.ts)_
|
||||
|
||||
## `eas secret:push`
|
||||
|
||||
@@ -1105,7 +1105,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.13.2/packages/eas-cli/src/commands/secret/push.ts)_
|
||||
_See code: [src/commands/secret/push.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/secret/push.ts)_
|
||||
|
||||
## `eas submit`
|
||||
|
||||
@@ -1135,7 +1135,7 @@ ALIASES
|
||||
$ eas build:submit
|
||||
```
|
||||
|
||||
_See code: [src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/submit.ts)_
|
||||
_See code: [src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/submit.ts)_
|
||||
|
||||
## `eas update`
|
||||
|
||||
@@ -1143,11 +1143,12 @@ publish an update group
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ eas update [--branch <value>] [--channel <value>] [--message <value>] [--republish | --input-dir <value>
|
||||
| --skip-bundler] [--group <value> | | ] [--clear-cache] [-p android|ios|all] [--auto] [--private-key-path <value>]
|
||||
$ eas update [--branch <value>] [--channel <value>] [-m <value>] [--republish | --input-dir <value> |
|
||||
--skip-bundler] [--group <value> | | ] [--clear-cache] [-p android|ios|all] [--auto] [--private-key-path <value>]
|
||||
[--json --non-interactive]
|
||||
|
||||
FLAGS
|
||||
-m, --message=<value> A short message describing the update
|
||||
-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
|
||||
@@ -1156,7 +1157,6 @@ FLAGS
|
||||
--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.
|
||||
--message=<value> A short message describing the update
|
||||
--non-interactive Run the command in non-interactive mode.
|
||||
--private-key-path=<value> File containing the PEM-encoded private key corresponding to the certificate in
|
||||
expo-updates' configuration. Defaults to a file named "private-key.pem" in the
|
||||
@@ -1168,7 +1168,7 @@ DESCRIPTION
|
||||
publish an update group
|
||||
```
|
||||
|
||||
_See code: [src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/update/index.ts)_
|
||||
_See code: [src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/update/index.ts)_
|
||||
|
||||
## `eas update:configure`
|
||||
|
||||
@@ -1186,7 +1186,7 @@ DESCRIPTION
|
||||
configure the project to support EAS Update
|
||||
```
|
||||
|
||||
_See code: [src/commands/update/configure.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/update/configure.ts)_
|
||||
_See code: [src/commands/update/configure.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/update/configure.ts)_
|
||||
|
||||
## `eas update:delete GROUPID`
|
||||
|
||||
@@ -1207,7 +1207,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.13.2/packages/eas-cli/src/commands/update/delete.ts)_
|
||||
_See code: [src/commands/update/delete.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/update/delete.ts)_
|
||||
|
||||
## `eas update:list`
|
||||
|
||||
@@ -1229,7 +1229,7 @@ DESCRIPTION
|
||||
view the recent updates
|
||||
```
|
||||
|
||||
_See code: [src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/update/list.ts)_
|
||||
_See code: [src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/update/list.ts)_
|
||||
|
||||
## `eas update:republish`
|
||||
|
||||
@@ -1237,23 +1237,23 @@ roll back to an existing update
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ eas update:republish [--channel <value> | --branch <value> | --group <value>] [--message <value>] [-p
|
||||
android|ios|all] [--json --non-interactive]
|
||||
$ eas update:republish [--channel <value> | --branch <value> | --group <value>] [-m <value>] [-p android|ios|all]
|
||||
[--json --non-interactive]
|
||||
|
||||
FLAGS
|
||||
-m, --message=<value> Short message describing the republished update
|
||||
-p, --platform=(android|ios|all) [default: all]
|
||||
--branch=<value> Branch name to select an update to republish from
|
||||
--channel=<value> Channel name to select an update to republish from
|
||||
--group=<value> Update group ID to republish
|
||||
--json Enable JSON output, non-JSON messages will be printed to stderr.
|
||||
--message=<value> Short message describing the republished update
|
||||
--non-interactive Run the command in non-interactive mode.
|
||||
|
||||
DESCRIPTION
|
||||
roll back to an existing update
|
||||
```
|
||||
|
||||
_See code: [src/commands/update/republish.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/update/republish.ts)_
|
||||
_See code: [src/commands/update/republish.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/update/republish.ts)_
|
||||
|
||||
## `eas update:view GROUPID`
|
||||
|
||||
@@ -1273,7 +1273,7 @@ DESCRIPTION
|
||||
update group details
|
||||
```
|
||||
|
||||
_See code: [src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/update/view.ts)_
|
||||
_See code: [src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/update/view.ts)_
|
||||
|
||||
## `eas webhook:create`
|
||||
|
||||
@@ -1294,7 +1294,7 @@ DESCRIPTION
|
||||
create a webhook
|
||||
```
|
||||
|
||||
_See code: [src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/webhook/create.ts)_
|
||||
_See code: [src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/webhook/create.ts)_
|
||||
|
||||
## `eas webhook:delete [ID]`
|
||||
|
||||
@@ -1314,7 +1314,7 @@ DESCRIPTION
|
||||
delete a webhook
|
||||
```
|
||||
|
||||
_See code: [src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/webhook/delete.ts)_
|
||||
_See code: [src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/webhook/delete.ts)_
|
||||
|
||||
## `eas webhook:list`
|
||||
|
||||
@@ -1332,7 +1332,7 @@ DESCRIPTION
|
||||
list webhooks
|
||||
```
|
||||
|
||||
_See code: [src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/webhook/list.ts)_
|
||||
_See code: [src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/webhook/list.ts)_
|
||||
|
||||
## `eas webhook:update`
|
||||
|
||||
@@ -1354,7 +1354,7 @@ DESCRIPTION
|
||||
update a webhook
|
||||
```
|
||||
|
||||
_See code: [src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/webhook/update.ts)_
|
||||
_See code: [src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/webhook/update.ts)_
|
||||
|
||||
## `eas webhook:view ID`
|
||||
|
||||
@@ -1371,7 +1371,7 @@ DESCRIPTION
|
||||
view a webhook
|
||||
```
|
||||
|
||||
_See code: [src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v3.13.2/packages/eas-cli/src/commands/webhook/view.ts)_
|
||||
_See code: [src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v3.15.1/packages/eas-cli/src/commands/webhook/view.ts)_
|
||||
|
||||
## `eas whoami`
|
||||
|
||||
|
||||
Generated
+404
-142
@@ -7252,6 +7252,18 @@
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "filter",
|
||||
"description": null,
|
||||
"type": {
|
||||
"kind": "INPUT_OBJECT",
|
||||
"name": "ChannelFilterInput",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null,
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "first",
|
||||
"description": null,
|
||||
@@ -9250,6 +9262,22 @@
|
||||
"name": "AppInsights",
|
||||
"description": null,
|
||||
"fields": [
|
||||
{
|
||||
"name": "hasEventsFromExpoInsightsClientModule",
|
||||
"description": null,
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "Boolean",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "totalUniqueUsers",
|
||||
"description": null,
|
||||
@@ -13469,6 +13497,277 @@
|
||||
],
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "BackgroundJobReceipt",
|
||||
"description": null,
|
||||
"fields": [
|
||||
{
|
||||
"name": "account",
|
||||
"description": null,
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "OBJECT",
|
||||
"name": "Account",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "createdAt",
|
||||
"description": null,
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "DateTime",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "errorCode",
|
||||
"description": null,
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "errorMessage",
|
||||
"description": null,
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"description": null,
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "ID",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "resultId",
|
||||
"description": null,
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "ID",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "resultType",
|
||||
"description": null,
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "ENUM",
|
||||
"name": "BackgroundJobResultType",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "state",
|
||||
"description": null,
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "ENUM",
|
||||
"name": "BackgroundJobState",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "tries",
|
||||
"description": null,
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "Int",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "updatedAt",
|
||||
"description": null,
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "DateTime",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "willRetry",
|
||||
"description": null,
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "Boolean",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"inputFields": null,
|
||||
"interfaces": [],
|
||||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "BackgroundJobReceiptQuery",
|
||||
"description": null,
|
||||
"fields": [
|
||||
{
|
||||
"name": "byId",
|
||||
"description": "Look up background job receipt by ID",
|
||||
"args": [
|
||||
{
|
||||
"name": "id",
|
||||
"description": null,
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "ID",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"defaultValue": null,
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "OBJECT",
|
||||
"name": "BackgroundJobReceipt",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"inputFields": null,
|
||||
"interfaces": [],
|
||||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "ENUM",
|
||||
"name": "BackgroundJobResultType",
|
||||
"description": null,
|
||||
"fields": null,
|
||||
"inputFields": null,
|
||||
"interfaces": null,
|
||||
"enumValues": [
|
||||
{
|
||||
"name": "GITHUB_BUILD",
|
||||
"description": null,
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "ENUM",
|
||||
"name": "BackgroundJobState",
|
||||
"description": null,
|
||||
"fields": null,
|
||||
"inputFields": null,
|
||||
"interfaces": null,
|
||||
"enumValues": [
|
||||
{
|
||||
"name": "FAILURE",
|
||||
"description": null,
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "IN_PROGRESS",
|
||||
"description": null,
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "QUEUED",
|
||||
"description": null,
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "SUCCESS",
|
||||
"description": null,
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "Billing",
|
||||
@@ -17037,6 +17336,29 @@
|
||||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "INPUT_OBJECT",
|
||||
"name": "ChannelFilterInput",
|
||||
"description": null,
|
||||
"fields": null,
|
||||
"inputFields": [
|
||||
{
|
||||
"name": "searchTerm",
|
||||
"description": null,
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null,
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"interfaces": null,
|
||||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "Charge",
|
||||
@@ -20686,7 +21008,7 @@
|
||||
"fields": [
|
||||
{
|
||||
"name": "createGitHubBuild",
|
||||
"description": "Create a GitHub build for an app",
|
||||
"description": "Create a GitHub build for an app. Returns the ID of the background job receipt. Use BackgroundJobReceiptQuery to get the status of the job.",
|
||||
"args": [
|
||||
{
|
||||
"name": "buildInput",
|
||||
@@ -20709,8 +21031,8 @@
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "Boolean",
|
||||
"kind": "OBJECT",
|
||||
"name": "BackgroundJobReceipt",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
@@ -28679,6 +29001,22 @@
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "backgroundJobReceipt",
|
||||
"description": null,
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "OBJECT",
|
||||
"name": "BackgroundJobReceiptQuery",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "buildJobs",
|
||||
"description": null,
|
||||
@@ -29314,8 +29652,8 @@
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
"isDeprecated": true,
|
||||
"deprecationReason": "No longer supported"
|
||||
},
|
||||
{
|
||||
"name": "apps",
|
||||
@@ -29524,8 +29862,8 @@
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
"isDeprecated": true,
|
||||
"deprecationReason": "No longer supported"
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
@@ -29552,8 +29890,8 @@
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
"isDeprecated": true,
|
||||
"deprecationReason": "No longer supported"
|
||||
},
|
||||
{
|
||||
"name": "isExpoAdmin",
|
||||
@@ -29592,8 +29930,8 @@
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
"isDeprecated": true,
|
||||
"deprecationReason": "No longer supported"
|
||||
},
|
||||
{
|
||||
"name": "notificationSubscriptions",
|
||||
@@ -29730,8 +30068,8 @@
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
"isDeprecated": true,
|
||||
"deprecationReason": "No longer supported"
|
||||
},
|
||||
{
|
||||
"name": "username",
|
||||
@@ -29784,30 +30122,6 @@
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "githubUsername",
|
||||
"description": null,
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null,
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "industry",
|
||||
"description": null,
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null,
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "lastName",
|
||||
"description": null,
|
||||
@@ -29819,30 +30133,6 @@
|
||||
"defaultValue": null,
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"description": null,
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null,
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "twitterUsername",
|
||||
"description": null,
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null,
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"interfaces": null,
|
||||
@@ -32955,6 +33245,22 @@
|
||||
"name": "UpdateBranch",
|
||||
"description": null,
|
||||
"fields": [
|
||||
{
|
||||
"name": "app",
|
||||
"description": null,
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "OBJECT",
|
||||
"name": "App",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "appId",
|
||||
"description": null,
|
||||
@@ -33367,6 +33673,22 @@
|
||||
"name": "UpdateChannel",
|
||||
"description": null,
|
||||
"fields": [
|
||||
{
|
||||
"name": "app",
|
||||
"description": null,
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "OBJECT",
|
||||
"name": "App",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "appId",
|
||||
"description": null,
|
||||
@@ -34413,8 +34735,8 @@
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
"isDeprecated": true,
|
||||
"deprecationReason": "No longer supported"
|
||||
},
|
||||
{
|
||||
"name": "apps",
|
||||
@@ -34651,8 +34973,8 @@
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
"isDeprecated": true,
|
||||
"deprecationReason": "No longer supported"
|
||||
},
|
||||
{
|
||||
"name": "hasPendingUserInvitations",
|
||||
@@ -34695,8 +35017,8 @@
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
"isDeprecated": true,
|
||||
"deprecationReason": "No longer supported"
|
||||
},
|
||||
{
|
||||
"name": "isExpoAdmin",
|
||||
@@ -34728,7 +35050,7 @@
|
||||
}
|
||||
},
|
||||
"isDeprecated": true,
|
||||
"deprecationReason": "This field no longer exists"
|
||||
"deprecationReason": "No longer supported"
|
||||
},
|
||||
{
|
||||
"name": "isSecondFactorAuthenticationEnabled",
|
||||
@@ -34767,8 +35089,8 @@
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
"isDeprecated": true,
|
||||
"deprecationReason": "No longer supported"
|
||||
},
|
||||
{
|
||||
"name": "notificationSubscriptions",
|
||||
@@ -34953,8 +35275,8 @@
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
"isDeprecated": true,
|
||||
"deprecationReason": "No longer supported"
|
||||
},
|
||||
{
|
||||
"name": "username",
|
||||
@@ -35140,8 +35462,8 @@
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
"isDeprecated": true,
|
||||
"deprecationReason": "No longer supported"
|
||||
},
|
||||
{
|
||||
"name": "apps",
|
||||
@@ -35350,8 +35672,8 @@
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
"isDeprecated": true,
|
||||
"deprecationReason": "No longer supported"
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
@@ -35378,8 +35700,8 @@
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
"isDeprecated": true,
|
||||
"deprecationReason": "No longer supported"
|
||||
},
|
||||
{
|
||||
"name": "isExpoAdmin",
|
||||
@@ -35418,8 +35740,8 @@
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
"isDeprecated": true,
|
||||
"deprecationReason": "No longer supported"
|
||||
},
|
||||
{
|
||||
"name": "notificationSubscriptions",
|
||||
@@ -35556,8 +35878,8 @@
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
"isDeprecated": true,
|
||||
"deprecationReason": "No longer supported"
|
||||
},
|
||||
{
|
||||
"name": "username",
|
||||
@@ -35681,18 +36003,6 @@
|
||||
"description": null,
|
||||
"fields": null,
|
||||
"inputFields": [
|
||||
{
|
||||
"name": "appetizeCode",
|
||||
"description": null,
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null,
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "email",
|
||||
"description": null,
|
||||
@@ -35729,18 +36039,6 @@
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "githubUsername",
|
||||
"description": null,
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null,
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"description": null,
|
||||
@@ -35753,18 +36051,6 @@
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "industry",
|
||||
"description": null,
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null,
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "lastName",
|
||||
"description": null,
|
||||
@@ -35777,18 +36063,6 @@
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"description": null,
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null,
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "profilePhoto",
|
||||
"description": null,
|
||||
@@ -35801,18 +36075,6 @@
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "twitterUsername",
|
||||
"description": null,
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null,
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "username",
|
||||
"description": null,
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
{
|
||||
"name": "eas-cli",
|
||||
"description": "EAS command line tool",
|
||||
"version": "3.13.2",
|
||||
"version": "3.15.1",
|
||||
"author": "Expo <[email protected]>",
|
||||
"bin": {
|
||||
"eas": "./bin/run"
|
||||
},
|
||||
"bugs": "https://github.com/expo/eas-cli/issues",
|
||||
"dependencies": {
|
||||
"@expo/apple-utils": "1.2.0",
|
||||
"@expo/apple-utils": "1.3.1",
|
||||
"@expo/code-signing-certificates": "0.0.5",
|
||||
"@expo/config": "7.0.3",
|
||||
"@expo/config-plugins": "6.0.2",
|
||||
"@expo/config-types": "47.0.0",
|
||||
"@expo/config": "8.1.2",
|
||||
"@expo/config-plugins": "7.2.4",
|
||||
"@expo/config-types": "49.0.0",
|
||||
"@expo/eas-build-job": "1.0.13",
|
||||
"@expo/eas-json": "3.13.0",
|
||||
"@expo/eas-json": "3.15.1",
|
||||
"@expo/json-file": "8.2.37",
|
||||
"@expo/multipart-body-parser": "1.1.0",
|
||||
"@expo/osascript": "2.0.33",
|
||||
@@ -23,17 +23,18 @@
|
||||
"@expo/plist": "0.0.20",
|
||||
"@expo/plugin-help": "5.1.22",
|
||||
"@expo/plugin-warn-if-update-available": "2.5.0",
|
||||
"@expo/prebuild-config": "5.0.7",
|
||||
"@expo/prebuild-config": "6.2.5",
|
||||
"@expo/results": "1.0.0",
|
||||
"@expo/rudder-sdk-node": "1.1.1",
|
||||
"@expo/spawn-async": "1.7.0",
|
||||
"@expo/steps": "1.0.13",
|
||||
"@expo/steps": "1.0.25",
|
||||
"@expo/timeago.js": "1.0.0",
|
||||
"@oclif/core": "1.23.2",
|
||||
"@oclif/plugin-autocomplete": "1.3.10",
|
||||
"@segment/ajv-human-errors": "^2.1.2",
|
||||
"@urql/core": "3.1.1",
|
||||
"@urql/exchange-retry": "1.0.0",
|
||||
"@urql/core": "4.0.11",
|
||||
"@urql/exchange-graphcache": "6.1.4",
|
||||
"@urql/exchange-retry": "1.2.0",
|
||||
"ajv": "8.11.0",
|
||||
"ajv-formats": "2.1.1",
|
||||
"better-opn": "3.0.2",
|
||||
|
||||
@@ -13,6 +13,8 @@ import {
|
||||
EasBuildFreeTierDisabledAndroidError,
|
||||
EasBuildFreeTierDisabledError,
|
||||
EasBuildFreeTierDisabledIOSError,
|
||||
EasBuildFreeTierIosLimitExceededError,
|
||||
EasBuildFreeTierLimitExceededError,
|
||||
EasBuildResourceClassNotAvailableInFreeTierError,
|
||||
EasBuildTooManyPendingBuildsError,
|
||||
RequestValidationError,
|
||||
@@ -25,12 +27,18 @@ beforeEach(() => {
|
||||
|
||||
const EXPECTED_STRINGIFIED_GRAPHQL_ERROR_JSON = `[
|
||||
{
|
||||
"name": "GraphQLError",
|
||||
"extensions": {},
|
||||
"message": "Error 1"
|
||||
},
|
||||
{
|
||||
"name": "GraphQLError",
|
||||
"extensions": {},
|
||||
"message": "Error 2"
|
||||
},
|
||||
{
|
||||
"name": "GraphQLError",
|
||||
"extensions": {},
|
||||
"message": "Error 3"
|
||||
}
|
||||
]`;
|
||||
@@ -280,6 +288,45 @@ describe(Build.name, () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('for EAS_BUILD_FREE_TIER_LIMIT_EXCEEDED', () => {
|
||||
it('throws correct EasCommandError subclass', async () => {
|
||||
const platform = Platform.ANDROID;
|
||||
const graphQLError = getGraphQLError('Error 1', 'EAS_BUILD_FREE_TIER_LIMIT_EXCEEDED');
|
||||
const graphQLErrors = [graphQLError];
|
||||
const error = new CombinedError({ graphQLErrors });
|
||||
|
||||
const handleBuildRequestErrorThrownError = getError<EasBuildFreeTierLimitExceededError>(
|
||||
() => {
|
||||
handleBuildRequestError(error, platform);
|
||||
}
|
||||
);
|
||||
|
||||
assertReThrownError(
|
||||
handleBuildRequestErrorThrownError,
|
||||
EasBuildFreeTierLimitExceededError,
|
||||
'Error 1'
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('for EAS_BUILD_FREE_TIER_IOS_LIMIT_EXCEEDED', () => {
|
||||
it('throws correct EasCommandError subclass', async () => {
|
||||
const platform = Platform.ANDROID;
|
||||
const graphQLError = getGraphQLError('Error 1', 'EAS_BUILD_FREE_TIER_IOS_LIMIT_EXCEEDED');
|
||||
const graphQLErrors = [graphQLError];
|
||||
const error = new CombinedError({ graphQLErrors });
|
||||
|
||||
const handleBuildRequestErrorThrownError =
|
||||
getError<EasBuildFreeTierIosLimitExceededError>(() => {
|
||||
handleBuildRequestError(error, platform);
|
||||
});
|
||||
|
||||
assertReThrownError(
|
||||
handleBuildRequestErrorThrownError,
|
||||
EasBuildFreeTierIosLimitExceededError,
|
||||
'Error 1'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('for VALIDATION_ERROR', () => {
|
||||
describe('with Android', () => {
|
||||
@@ -416,7 +463,30 @@ describe(Build.name, () => {
|
||||
const graphQLError = getGraphQLError('Error 1', 'UNKNOWN_GRAPHQL_ERROR');
|
||||
const graphQLErrors = [graphQLError];
|
||||
const error = new CombinedError({ graphQLErrors });
|
||||
const expectedMessage = EXPECTED_GENERIC_MESSAGE + `\nRequest ID: ${mockRequestId}`;
|
||||
const expectedMessage = `${EXPECTED_GENERIC_MESSAGE}\nRequest ID: ${mockRequestId}\nError message: Error 1`;
|
||||
|
||||
const handleBuildRequestErrorThrownError = getError<Error>(() => {
|
||||
handleBuildRequestError(error, platform);
|
||||
});
|
||||
|
||||
assertReThrownError(handleBuildRequestErrorThrownError, Error, expectedMessage);
|
||||
});
|
||||
it('throws base Error class with message including all error messages if combined error has multiple GraphQL errors', async () => {
|
||||
const platform = Platform.ANDROID;
|
||||
const graphQLErrors = [
|
||||
getGraphQLError('Error 1', 'UNKNOWN_GRAPHQL_ERROR'),
|
||||
getGraphQLError('Error 2', 'OTHER_GRAPHQL_ERROR'),
|
||||
getGraphQLError('Error 3', 'YET_ANOTHER_GRAPHQL_ERROR'),
|
||||
];
|
||||
const error = new CombinedError({ graphQLErrors });
|
||||
const expectedMessage =
|
||||
`${EXPECTED_GENERIC_MESSAGE}\n` +
|
||||
`Request ID: ${mockRequestId}\n` +
|
||||
'Error message: Error 1\n' +
|
||||
`Request ID: ${mockRequestId}\n` +
|
||||
'Error message: Error 2\n' +
|
||||
`Request ID: ${mockRequestId}\n` +
|
||||
'Error message: Error 3';
|
||||
|
||||
const handleBuildRequestErrorThrownError = getError<Error>(() => {
|
||||
handleBuildRequestError(error, platform);
|
||||
@@ -431,16 +501,13 @@ describe(Build.name, () => {
|
||||
delete graphQLError.extensions.requestId;
|
||||
const graphQLErrors = [graphQLError];
|
||||
const error = new CombinedError({ graphQLErrors });
|
||||
const expectedMessage = `${EXPECTED_GENERIC_MESSAGE}\nError message: Error 1`;
|
||||
|
||||
const handleBuildRequestErrorThrownError = getError<Error>(() => {
|
||||
handleBuildRequestError(error, platform);
|
||||
});
|
||||
|
||||
assertReThrownError(
|
||||
handleBuildRequestErrorThrownError,
|
||||
Error,
|
||||
EXPECTED_GENERIC_MESSAGE
|
||||
);
|
||||
assertReThrownError(handleBuildRequestErrorThrownError, Error, expectedMessage);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -450,7 +517,30 @@ describe(Build.name, () => {
|
||||
const graphQLError = getGraphQLError('Error 1', 'UNKNOWN_GRAPHQL_ERROR');
|
||||
const graphQLErrors = [graphQLError];
|
||||
const error = new CombinedError({ graphQLErrors });
|
||||
const expectedMessage = EXPECTED_GENERIC_MESSAGE + `\nRequest ID: ${mockRequestId}`;
|
||||
const expectedMessage = `${EXPECTED_GENERIC_MESSAGE}\nRequest ID: ${mockRequestId}\nError message: Error 1`;
|
||||
|
||||
const handleBuildRequestErrorThrownError = getError<Error>(() => {
|
||||
handleBuildRequestError(error, platform);
|
||||
});
|
||||
|
||||
assertReThrownError(handleBuildRequestErrorThrownError, Error, expectedMessage);
|
||||
});
|
||||
it('throws base Error class with message including all error messages if combined error has multiple GraphQL errors', async () => {
|
||||
const platform = Platform.IOS;
|
||||
const graphQLErrors = [
|
||||
getGraphQLError('Error 1', 'UNKNOWN_GRAPHQL_ERROR'),
|
||||
getGraphQLError('Error 2', 'OTHER_GRAPHQL_ERROR'),
|
||||
getGraphQLError('Error 3', 'YET_ANOTHER_GRAPHQL_ERROR'),
|
||||
];
|
||||
const error = new CombinedError({ graphQLErrors });
|
||||
const expectedMessage =
|
||||
`${EXPECTED_GENERIC_MESSAGE}\n` +
|
||||
`Request ID: ${mockRequestId}\n` +
|
||||
'Error message: Error 1\n' +
|
||||
`Request ID: ${mockRequestId}\n` +
|
||||
'Error message: Error 2\n' +
|
||||
`Request ID: ${mockRequestId}\n` +
|
||||
'Error message: Error 3';
|
||||
|
||||
const handleBuildRequestErrorThrownError = getError<Error>(() => {
|
||||
handleBuildRequestError(error, platform);
|
||||
@@ -465,16 +555,13 @@ describe(Build.name, () => {
|
||||
delete graphQLError.extensions.requestId;
|
||||
const graphQLErrors = [graphQLError];
|
||||
const error = new CombinedError({ graphQLErrors });
|
||||
const expectedMessage = `${EXPECTED_GENERIC_MESSAGE}\nError message: Error 1`;
|
||||
|
||||
const handleBuildRequestErrorThrownError = getError<Error>(() => {
|
||||
handleBuildRequestError(error, platform);
|
||||
});
|
||||
|
||||
assertReThrownError(
|
||||
handleBuildRequestErrorThrownError,
|
||||
Error,
|
||||
EXPECTED_GENERIC_MESSAGE
|
||||
);
|
||||
assertReThrownError(handleBuildRequestErrorThrownError, Error, expectedMessage);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,6 +4,7 @@ import assert from 'assert';
|
||||
import chalk from 'chalk';
|
||||
import cliProgress from 'cli-progress';
|
||||
import fs from 'fs-extra';
|
||||
import { GraphQLError } from 'graphql/error';
|
||||
import nullthrows from 'nullthrows';
|
||||
|
||||
import { BuildEvent } from '../analytics/AnalyticsManager';
|
||||
@@ -42,6 +43,9 @@ import {
|
||||
EasBuildFreeTierDisabledAndroidError,
|
||||
EasBuildFreeTierDisabledError,
|
||||
EasBuildFreeTierDisabledIOSError,
|
||||
EasBuildFreeTierIosLimitExceededError,
|
||||
EasBuildFreeTierLimitExceededError,
|
||||
EasBuildProjectArchiveUploadError,
|
||||
EasBuildResourceClassNotAvailableInFreeTierError,
|
||||
EasBuildTooManyPendingBuildsError,
|
||||
RequestValidationError,
|
||||
@@ -182,6 +186,8 @@ const SERVER_SIDE_DEFINED_ERRORS: Record<string, typeof EasCommandError> = {
|
||||
EAS_BUILD_FREE_TIER_DISABLED: EasBuildFreeTierDisabledError,
|
||||
EAS_BUILD_FREE_TIER_DISABLED_IOS: EasBuildFreeTierDisabledIOSError,
|
||||
EAS_BUILD_FREE_TIER_DISABLED_ANDROID: EasBuildFreeTierDisabledAndroidError,
|
||||
EAS_BUILD_FREE_TIER_LIMIT_EXCEEDED: EasBuildFreeTierLimitExceededError,
|
||||
EAS_BUILD_FREE_TIER_IOS_LIMIT_EXCEEDED: EasBuildFreeTierIosLimitExceededError,
|
||||
EAS_BUILD_RESOURCE_CLASS_NOT_AVAILABLE_IN_FREE_TIER:
|
||||
EasBuildResourceClassNotAvailableInFreeTierError,
|
||||
VALIDATION_ERROR: RequestValidationError,
|
||||
@@ -205,12 +211,19 @@ export function handleBuildRequestError(error: any, platform: Platform): never {
|
||||
`You have already reached the maximum number of pending ${requestedPlatformDisplayNames[platform]} builds for your account. Try again later.`
|
||||
);
|
||||
} else if (error?.graphQLErrors) {
|
||||
const requestIdLine = error?.graphQLErrors?.[0]?.extensions?.requestId
|
||||
? `\nRequest ID: ${error.graphQLErrors[0].extensions.requestId}`
|
||||
: '';
|
||||
const errorMessage = error.graphQLErrors
|
||||
.map((graphQLError: GraphQLError) => {
|
||||
const requestIdLine = graphQLError?.extensions?.requestId
|
||||
? `\nRequest ID: ${graphQLError.extensions.requestId}`
|
||||
: '';
|
||||
const errorMessageLine = graphQLError?.message
|
||||
? `\nError message: ${graphQLError.message}`
|
||||
: '';
|
||||
return `${requestIdLine}${errorMessageLine}`;
|
||||
})
|
||||
.join('');
|
||||
throw new Error(
|
||||
'Build request failed. Make sure you are using the latest eas-cli version. If the problem persists, report the issue.' +
|
||||
requestIdLine
|
||||
`Build request failed. Make sure you are using the latest eas-cli version. If the problem persists, report the issue.${errorMessage}`
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
@@ -242,6 +255,10 @@ async function uploadProjectAsync<TPlatform extends Platform>(
|
||||
);
|
||||
}
|
||||
|
||||
if (projectTarball.size > 2 * 1024 * 1024 * 1024) {
|
||||
throw new Error('Project archive is too big. Maximum allowed size is 2GB.');
|
||||
}
|
||||
|
||||
projectTarballPath = projectTarball.path;
|
||||
|
||||
const bucketKey = await uploadFileAtPathToGCSAsync(
|
||||
@@ -266,6 +283,12 @@ async function uploadProjectAsync<TPlatform extends Platform>(
|
||||
properties: ctx.analyticsEventProperties,
|
||||
}
|
||||
);
|
||||
} catch (err: any) {
|
||||
let errMessage = 'Failed to upload the project tarball to EAS Build';
|
||||
if (err.message) {
|
||||
errMessage += `\n\nReason: ${err.message}`;
|
||||
}
|
||||
throw new EasBuildProjectArchiveUploadError(errMessage);
|
||||
} finally {
|
||||
if (projectTarballPath) {
|
||||
await fs.remove(projectTarballPath);
|
||||
|
||||
@@ -3,7 +3,7 @@ import { EasJson, EasJsonAccessor } from '@expo/eas-json';
|
||||
import chalk from 'chalk';
|
||||
import fs from 'fs-extra';
|
||||
|
||||
import Log from '../log';
|
||||
import Log, { learnMore } from '../log';
|
||||
import { resolveWorkflowAsync } from '../project/workflow';
|
||||
import { easCliVersion } from '../utils/easCli';
|
||||
import { getVcsClient } from '../vcs';
|
||||
@@ -14,6 +14,10 @@ interface ConfigureParams {
|
||||
nonInteractive: boolean;
|
||||
}
|
||||
|
||||
export async function easJsonExistsAsync(projectDir: string): Promise<boolean> {
|
||||
return await fs.pathExists(EasJsonAccessor.formatEasJsonPath(projectDir));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates eas.json if it does not exist.
|
||||
*
|
||||
@@ -24,7 +28,7 @@ interface ConfigureParams {
|
||||
export async function ensureProjectConfiguredAsync(
|
||||
configureParams: ConfigureParams
|
||||
): Promise<boolean> {
|
||||
if (await fs.pathExists(EasJsonAccessor.formatEasJsonPath(configureParams.projectDir))) {
|
||||
if (await easJsonExistsAsync(configureParams.projectDir)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -102,5 +106,9 @@ async function createEasJsonAsync(projectDir: string): Promise<void> {
|
||||
|
||||
await fs.writeFile(easJsonPath, `${JSON.stringify(easJson, null, 2)}\n`);
|
||||
await getVcsClient().trackFileAsync(easJsonPath);
|
||||
Log.withTick(`Generated ${chalk.bold('eas.json')}`);
|
||||
Log.withTick(
|
||||
`Generated ${chalk.bold('eas.json')}. ${learnMore(
|
||||
'https://docs.expo.dev/build-reference/eas-json/'
|
||||
)}`
|
||||
);
|
||||
}
|
||||
@@ -8,6 +8,10 @@ export class EasBuildFreeTierDisabledIOSError extends EasCommandError {}
|
||||
|
||||
export class EasBuildFreeTierDisabledAndroidError extends EasCommandError {}
|
||||
|
||||
export class EasBuildFreeTierLimitExceededError extends EasCommandError {}
|
||||
|
||||
export class EasBuildFreeTierIosLimitExceededError extends EasCommandError {}
|
||||
|
||||
export class EasBuildResourceClassNotAvailableInFreeTierError extends EasCommandError {}
|
||||
|
||||
export class RequestValidationError extends EasCommandError {}
|
||||
@@ -15,3 +19,5 @@ export class RequestValidationError extends EasCommandError {}
|
||||
export class EasBuildDownForMaintenanceError extends EasCommandError {}
|
||||
|
||||
export class EasBuildTooManyPendingBuildsError extends EasCommandError {}
|
||||
|
||||
export class EasBuildProjectArchiveUploadError extends EasCommandError {}
|
||||
@@ -6,7 +6,7 @@ import semver from 'semver';
|
||||
import { ora } from '../ora';
|
||||
|
||||
const PLUGIN_PACKAGE_NAME = 'eas-cli-local-build-plugin';
|
||||
const PLUGIN_PACKAGE_VERSION = '0.0.128';
|
||||
const PLUGIN_PACKAGE_VERSION = '1.0.27';
|
||||
|
||||
export enum LocalBuildMode {
|
||||
/**
|
||||
|
||||
@@ -132,6 +132,7 @@ function createBuildToPartialChoiceMaker(
|
||||
name: build.platform === AppPlatform.Ios ? 'Build number' : 'Version code',
|
||||
value: build.appBuildVersion ? chalk.bold(build.appBuildVersion) : null,
|
||||
},
|
||||
{ name: 'Profile', value: build.buildProfile ? chalk.bold(build.buildProfile) : null },
|
||||
];
|
||||
|
||||
const filteredDescriptionArray: string[] = descriptionItems
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
} from '../graphql/generated';
|
||||
import { BuildQuery } from '../graphql/queries/BuildQuery';
|
||||
import { toAppPlatform, toPlatform } from '../graphql/types/AppPlatform';
|
||||
import Log from '../log';
|
||||
import Log, { learnMore } from '../log';
|
||||
import {
|
||||
RequestedPlatform,
|
||||
appPlatformDisplayNames,
|
||||
@@ -37,7 +37,12 @@ import {
|
||||
} from '../project/customBuildConfig';
|
||||
import { checkExpoSdkIsSupportedAsync } from '../project/expoSdk';
|
||||
import { validateMetroConfigForManagedWorkflowAsync } from '../project/metroConfig';
|
||||
import { validateAppVersionRuntimePolicySupportAsync } from '../project/projectUtils';
|
||||
import {
|
||||
installExpoUpdatesAsync,
|
||||
isExpoUpdatesInstalledAsDevDependency,
|
||||
isExpoUpdatesInstalledOrAvailable,
|
||||
validateAppVersionRuntimePolicySupportAsync,
|
||||
} from '../project/projectUtils';
|
||||
import {
|
||||
validateAppConfigForRemoteVersionSource,
|
||||
validateBuildProfileVersionSettings,
|
||||
@@ -113,6 +118,13 @@ export async function runBuildAndSubmitAsync(
|
||||
platforms,
|
||||
profileName: flags.profile ?? undefined,
|
||||
});
|
||||
Log.log(
|
||||
`Loaded "env" configuration for the "${buildProfiles[0].profileName}" profile: ${
|
||||
buildProfiles[0].profile.env
|
||||
? Object.keys(buildProfiles[0].profile.env).join(', ')
|
||||
: 'no environment variables specified'
|
||||
}. ${learnMore('https://docs.expo.dev/build-reference/variables/')}`
|
||||
);
|
||||
|
||||
await ensureExpoDevClientInstalledForDevClientBuildsAsync({
|
||||
projectDir,
|
||||
@@ -306,6 +318,14 @@ async function prepareAndStartBuildAsync({
|
||||
buildCtx.projectId,
|
||||
flags.nonInteractive
|
||||
);
|
||||
if (buildProfile.profile.channel) {
|
||||
await validateExpoUpdatesInstalledAsProjectDependencyAsync({
|
||||
projectDir,
|
||||
sdkVersion: buildCtx.exp.sdkVersion,
|
||||
nonInteractive: flags.nonInteractive,
|
||||
buildProfile,
|
||||
});
|
||||
}
|
||||
|
||||
await validateAppVersionRuntimePolicySupportAsync(buildCtx.projectDir, buildCtx.exp);
|
||||
if (easJsonCliConfig?.appVersionSource === AppVersionSource.REMOTE) {
|
||||
@@ -425,3 +445,40 @@ async function maybeDownloadAndRunSimulatorBuildsAsync(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function validateExpoUpdatesInstalledAsProjectDependencyAsync({
|
||||
projectDir,
|
||||
buildProfile,
|
||||
nonInteractive,
|
||||
sdkVersion,
|
||||
}: {
|
||||
projectDir: string;
|
||||
buildProfile: ProfileData<'build'>;
|
||||
nonInteractive: boolean;
|
||||
sdkVersion?: string;
|
||||
}): Promise<void> {
|
||||
if (isExpoUpdatesInstalledOrAvailable(projectDir, sdkVersion)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isExpoUpdatesInstalledAsDevDependency(projectDir)) {
|
||||
Log.warn(
|
||||
`The build profile "${buildProfile.profileName}" uses the channel "${buildProfile.profile.channel}", but you've added "expo-updates" as a dev dependency. To make channels work for your builds, move "expo-updates" from dev dependencies to the main dependencies in your project.`
|
||||
);
|
||||
} else if (nonInteractive) {
|
||||
Log.warn(
|
||||
`The build profile "${buildProfile.profileName}" has specified the channel "${buildProfile.profile.channel}", but the "expo-updates" package hasn't been installed. To use channels for your builds, install the "expo-updates" package by running "npx expo install expo-updates".`
|
||||
);
|
||||
} else {
|
||||
Log.warn(
|
||||
`The build profile "${buildProfile.profileName}" specifies the channel "${buildProfile.profile.channel}", but the "expo-updates" package is missing. To use channels in your builds, install the "expo-updates" package.`
|
||||
);
|
||||
const installExpoUpdates = await confirmAsync({
|
||||
message: `Would you like to install the "expo-updates" package?`,
|
||||
});
|
||||
if (installExpoUpdates) {
|
||||
await installExpoUpdatesAsync(projectDir, { silent: false });
|
||||
Log.withTick('Installed expo-updates');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
export class ListChannels {
|
||||
constructor() {}
|
||||
|
||||
async runAsync(): Promise<void> {}
|
||||
|
||||
// TODO return channels fragment
|
||||
async listChannelsAsync(): Promise<void> {}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Command } from '@oclif/core';
|
||||
import { CombinedError } from '@urql/core';
|
||||
import { GraphQLError } from 'graphql/error';
|
||||
import nullthrows from 'nullthrows';
|
||||
|
||||
import {
|
||||
@@ -193,16 +194,23 @@ export default abstract class EasCommand extends Command {
|
||||
if (err instanceof EasCommandError) {
|
||||
Log.error(err.message);
|
||||
} else if (err instanceof CombinedError && err?.graphQLErrors) {
|
||||
let cleanMessage = err.message.replace('[GraphQL] ', '');
|
||||
cleanMessage += err?.graphQLErrors?.[0]?.extensions?.requestId
|
||||
? `\nRequest ID: ${err.graphQLErrors[0].extensions.requestId}`
|
||||
: '';
|
||||
const cleanMessage = err?.graphQLErrors
|
||||
.map((graphQLError: GraphQLError) => {
|
||||
const messageLine = graphQLError.message.replace('[GraphQL] ', '');
|
||||
const requestIdLine = graphQLError.extensions?.requestId
|
||||
? `\nRequest ID: ${err.graphQLErrors[0].extensions.requestId}`
|
||||
: '';
|
||||
return `${messageLine}${requestIdLine}`;
|
||||
})
|
||||
.join('\n');
|
||||
Log.error(cleanMessage);
|
||||
baseMessage = BASE_GRAPHQL_ERROR_MESSAGE;
|
||||
} else {
|
||||
Log.error(err.message);
|
||||
}
|
||||
Log.debug(err);
|
||||
throw new Error(baseMessage);
|
||||
const sanitizedError = new Error(baseMessage);
|
||||
sanitizedError.stack = err.stack;
|
||||
throw sanitizedError;
|
||||
}
|
||||
}
|
||||
@@ -172,6 +172,44 @@ describe(EasCommand.name, () => {
|
||||
expect(logDebugSpy).toBeCalledWith(error);
|
||||
});
|
||||
|
||||
it('logs the cleaned messages with request IDs if multiple GraphQL errors present', async () => {
|
||||
const TestEasCommand = createTestEasCommand();
|
||||
const logErrorSpy = jest.spyOn(Log, 'error');
|
||||
const logDebugSpy = jest.spyOn(Log, 'debug');
|
||||
const runAsyncMock = jest.spyOn(TestEasCommand.prototype as any, 'runAsync');
|
||||
const graphQLErrors = [
|
||||
new GraphQLError('Unexpected GraphQL error message', null, null, null, null, null, {
|
||||
errorCode: 'UNKNOWN_GRAPHQL_ERROR',
|
||||
requestId: mockRequestId,
|
||||
}),
|
||||
new GraphQLError('Other GraphQL error message', null, null, null, null, null, {
|
||||
errorCode: 'OTHER_GRAPHQL_ERROR',
|
||||
requestId: mockRequestId,
|
||||
}),
|
||||
new GraphQLError('Yet another GraphQL error message', null, null, null, null, null, {
|
||||
errorCode: 'YET_ANOTHER_GRAPHQL_ERROR',
|
||||
requestId: mockRequestId,
|
||||
}),
|
||||
];
|
||||
const error = new CombinedError({ graphQLErrors });
|
||||
runAsyncMock.mockImplementation(() => {
|
||||
throw error;
|
||||
});
|
||||
try {
|
||||
await TestEasCommand.run();
|
||||
} catch {}
|
||||
|
||||
expect(logErrorSpy).toBeCalledWith(
|
||||
'Unexpected GraphQL error message\n' +
|
||||
`Request ID: ${mockRequestId}\n` +
|
||||
'Other GraphQL error message\n' +
|
||||
`Request ID: ${mockRequestId}\n` +
|
||||
'Yet another GraphQL error message\n' +
|
||||
`Request ID: ${mockRequestId}`
|
||||
);
|
||||
expect(logDebugSpy).toBeCalledWith(error);
|
||||
});
|
||||
|
||||
it('re-throws the error with default base message', async () => {
|
||||
const TestEasCommand = createTestEasCommand();
|
||||
const runAsyncMock = jest.spyOn(TestEasCommand.prototype as any, 'runAsync');
|
||||
@@ -186,7 +224,7 @@ describe(EasCommand.name, () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('re-throws the error with a different default base message in case of graphQLError', async () => {
|
||||
it('re-throws the error with a different default base message in case of CombinedError', async () => {
|
||||
const TestEasCommand = createTestEasCommand();
|
||||
const runAsyncMock = jest.spyOn(TestEasCommand.prototype as any, 'runAsync');
|
||||
runAsyncMock.mockImplementation(() => {
|
||||
@@ -200,6 +238,34 @@ describe(EasCommand.name, () => {
|
||||
expect((caughtError as Error).message).toEqual('GraphQL request failed.');
|
||||
}
|
||||
});
|
||||
|
||||
it('re-throws the error with a different default base message in case of CombinedError with multiple GraphQLErrors', async () => {
|
||||
const TestEasCommand = createTestEasCommand();
|
||||
const runAsyncMock = jest.spyOn(TestEasCommand.prototype as any, 'runAsync');
|
||||
runAsyncMock.mockImplementation(() => {
|
||||
const graphQLErrors = [
|
||||
new GraphQLError('Unexpected GraphQL error message', null, null, null, null, null, {
|
||||
errorCode: 'UNEXPECTED_GRAPHQL_ERROR',
|
||||
requestId: mockRequestId,
|
||||
}),
|
||||
new GraphQLError('Other GraphQL error message', null, null, null, null, null, {
|
||||
errorCode: 'OTHER_GRAPHQL_ERROR',
|
||||
requestId: mockRequestId,
|
||||
}),
|
||||
new GraphQLError('Yet another GraphQL error message', null, null, null, null, null, {
|
||||
errorCode: 'YET_ANOTHER_GRAPHQL_ERROR',
|
||||
requestId: mockRequestId,
|
||||
}),
|
||||
];
|
||||
throw new CombinedError({ graphQLErrors });
|
||||
});
|
||||
try {
|
||||
await TestEasCommand.run();
|
||||
} catch (caughtError) {
|
||||
expect(caughtError).toBeInstanceOf(Error);
|
||||
expect((caughtError as Error).message).toEqual('GraphQL request failed.');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
+5
-1
@@ -1,4 +1,4 @@
|
||||
import { getConfig, modifyConfigAsync } from '@expo/config';
|
||||
import { getConfig, getConfigFilePaths, modifyConfigAsync } from '@expo/config';
|
||||
import { vol } from 'memfs';
|
||||
import { anything, instance, mock, when } from 'ts-mockito';
|
||||
|
||||
@@ -26,6 +26,10 @@ describe(getProjectIdAsync, () => {
|
||||
let sessionManager: SessionManager;
|
||||
|
||||
beforeEach(() => {
|
||||
jest
|
||||
.mocked(getConfigFilePaths)
|
||||
.mockReturnValue({ staticConfigPath: null, dynamicConfigPath: null });
|
||||
|
||||
const sessionManagerMock = mock<SessionManager>();
|
||||
when(sessionManagerMock.ensureLoggedInAsync(anything())).thenResolve({
|
||||
actor: {
|
||||
|
||||
@@ -3,13 +3,14 @@ import {
|
||||
Client,
|
||||
OperationContext,
|
||||
OperationResult,
|
||||
PromisifiedSource,
|
||||
OperationResultSource,
|
||||
TypedDocumentNode,
|
||||
cacheExchange,
|
||||
createClient as createUrqlClient,
|
||||
dedupExchange,
|
||||
cacheExchange as defaultCacheExchange,
|
||||
fetchExchange,
|
||||
} from '@urql/core';
|
||||
import { cacheExchange as graphqlCacheExchange } from '@urql/exchange-graphcache';
|
||||
import { relayPagination } from '@urql/exchange-graphcache/extras';
|
||||
import { retryExchange } from '@urql/exchange-retry';
|
||||
import { DocumentNode } from 'graphql';
|
||||
import fetch from 'node-fetch';
|
||||
@@ -22,18 +23,28 @@ export interface ExpoGraphqlClient extends Client {
|
||||
query: DocumentNode | TypedDocumentNode<Data, Variables> | string,
|
||||
variables: Variables,
|
||||
context: Partial<OperationContext> & { additionalTypenames: string[] }
|
||||
): PromisifiedSource<OperationResult<Data, Variables>>;
|
||||
): OperationResultSource<OperationResult<Data, Variables>>;
|
||||
}
|
||||
|
||||
export function createGraphqlClient(authInfo: {
|
||||
accessToken: string | null;
|
||||
sessionSecret: string | null;
|
||||
}): ExpoGraphqlClient {
|
||||
// TODO: plumb this down, maybe use a feature gate for this?
|
||||
export function createGraphqlClient(
|
||||
authInfo: {
|
||||
accessToken: string | null;
|
||||
sessionSecret: string | null;
|
||||
},
|
||||
_options: { useGraphqlCachePolicy?: boolean } = {}
|
||||
): ExpoGraphqlClient {
|
||||
return createUrqlClient({
|
||||
url: getExpoApiBaseUrl() + '/graphql',
|
||||
exchanges: [
|
||||
dedupExchange,
|
||||
cacheExchange,
|
||||
//options.useGraphqlCachePolicy ? graphqlCacheExchange() : defaultCacheExchange,
|
||||
graphqlCacheExchange({
|
||||
resolvers: {
|
||||
App: {
|
||||
updateChannels: relayPagination(),
|
||||
},
|
||||
},
|
||||
}),
|
||||
retryExchange({
|
||||
maxDelayMs: 4000,
|
||||
retryIf: (err, operation) => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getProjectConfigDescription, modifyConfigAsync } from '@expo/config';
|
||||
import { getProjectConfigDescription } from '@expo/config';
|
||||
import { ExpoConfig } from '@expo/config-types';
|
||||
import { Env } from '@expo/eas-build-job';
|
||||
import chalk from 'chalk';
|
||||
@@ -6,7 +6,7 @@ import chalk from 'chalk';
|
||||
import { AppQuery } from '../../../graphql/queries/AppQuery';
|
||||
import Log, { learnMore } from '../../../log';
|
||||
import { ora } from '../../../ora';
|
||||
import { getPrivateExpoConfig } from '../../../project/expoConfig';
|
||||
import { createOrModifyExpoConfigAsync, getPrivateExpoConfig } from '../../../project/expoConfig';
|
||||
import { fetchOrCreateProjectIDForWriteToConfigWithConfirmationAsync } from '../../../project/fetchOrCreateProjectIDForWriteToConfigWithConfirmationAsync';
|
||||
import { toAppPrivacy } from '../../../project/projectUtils';
|
||||
import SessionManager from '../../../user/SessionManager';
|
||||
@@ -25,7 +25,7 @@ export async function saveProjectIdToAppConfigAsync(
|
||||
options: { env?: Env } = {}
|
||||
): Promise<void> {
|
||||
const exp = getPrivateExpoConfig(projectDir, options);
|
||||
const result = await modifyConfigAsync(
|
||||
const result = await createOrModifyExpoConfigAsync(
|
||||
projectDir,
|
||||
{
|
||||
extra: { ...exp.extra, eas: { ...exp.extra?.eas, projectId } },
|
||||
@@ -160,12 +160,12 @@ export async function getProjectIdAsync(
|
||||
switch (user.__typename) {
|
||||
case 'User':
|
||||
return user.username;
|
||||
case 'SSOUser':
|
||||
return user.username;
|
||||
case 'Robot':
|
||||
throw new Error(
|
||||
'The "owner" manifest property is required when using robot users. See: https://docs.expo.dev/versions/latest/config/app/#owner'
|
||||
);
|
||||
case 'SSOUser':
|
||||
throw new Error('SSO users are not supported yet.');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { Flags } from '@oclif/core';
|
||||
|
||||
import EasCommand from '../../commandUtils/EasCommand';
|
||||
import Log from '../../log';
|
||||
|
||||
@@ -5,13 +7,27 @@ export default class AccountLogin extends EasCommand {
|
||||
static override description = 'log in with your Expo account';
|
||||
static override aliases = ['login'];
|
||||
|
||||
static override flags = {
|
||||
// can pass either --sso or -s
|
||||
sso: Flags.boolean({
|
||||
description: 'Login with SSO',
|
||||
char: 's',
|
||||
default: false,
|
||||
hidden: true,
|
||||
}),
|
||||
};
|
||||
|
||||
static override contextDefinition = {
|
||||
...this.ContextOptions.SessionManagment,
|
||||
};
|
||||
|
||||
async runAsync(): Promise<void> {
|
||||
const {
|
||||
flags: { sso },
|
||||
} = await this.parse(AccountLogin);
|
||||
|
||||
const { sessionManager } = await this.getContextAsync(AccountLogin, { nonInteractive: false });
|
||||
await sessionManager.showLoginPromptAsync();
|
||||
await sessionManager.showLoginPromptAsync({ sso });
|
||||
Log.log('Logged in');
|
||||
}
|
||||
}
|
||||
@@ -7,10 +7,14 @@ import { ensureProjectConfiguredAsync } from '../../build/configure';
|
||||
import EasCommand from '../../commandUtils/EasCommand';
|
||||
import Log, { learnMore } from '../../log';
|
||||
import { RequestedPlatform } from '../../platform';
|
||||
import { isExpoUpdatesInstalled } from '../../project/projectUtils';
|
||||
import { isExpoUpdatesInstalled, isUsingEASUpdate } from '../../project/projectUtils';
|
||||
import { resolveWorkflowAsync } from '../../project/workflow';
|
||||
import { promptAsync } from '../../prompts';
|
||||
import { syncUpdatesConfigurationAsync as syncAndroidUpdatesConfigurationAsync } from '../../update/android/UpdatesModule';
|
||||
import {
|
||||
ensureEASUpdateIsConfiguredInEasJsonAsync,
|
||||
ensureUseClassicUpdatesIsRemovedAsync,
|
||||
} from '../../update/configure';
|
||||
import { syncUpdatesConfigurationAsync as syncIosUpdatesConfigurationAsync } from '../../update/ios/UpdatesModule';
|
||||
import { getVcsClient } from '../../vcs';
|
||||
|
||||
@@ -57,10 +61,19 @@ export default class BuildConfigure extends EasCommand {
|
||||
|
||||
// ensure eas.json exists
|
||||
Log.newLine();
|
||||
await ensureProjectConfiguredAsync({
|
||||
const didCreateEasJson = await ensureProjectConfiguredAsync({
|
||||
projectDir,
|
||||
nonInteractive: false,
|
||||
});
|
||||
if (didCreateEasJson && isUsingEASUpdate(exp, projectId)) {
|
||||
if (exp.updates?.useClassicUpdates) {
|
||||
// NOTE: this method modifies the Expo config; be sure to use this function's return value
|
||||
// if the config object is used later in the future
|
||||
await ensureUseClassicUpdatesIsRemovedAsync({ exp, projectDir });
|
||||
}
|
||||
|
||||
await ensureEASUpdateIsConfiguredInEasJsonAsync(projectDir);
|
||||
}
|
||||
|
||||
// configure expo-updates
|
||||
if (expoUpdatesIsInstalled) {
|
||||
|
||||
@@ -210,8 +210,9 @@ async function maybeGetBuildAsync(
|
||||
},
|
||||
paginatedQueryOptions,
|
||||
selectPromptDisabledFunction: build => !isRunnableOnSimulatorOrEmulator(build),
|
||||
selectPromptWarningMessage:
|
||||
'Artifacts for this build have expired and are no longer available, or this is not a simulator/emulator build.',
|
||||
selectPromptWarningMessage: `Artifacts for this build have expired and are no longer available, or this is not ${
|
||||
flags.selectedPlatform === AppPlatform.Ios ? 'a simulator' : 'an emulator'
|
||||
} build.`,
|
||||
});
|
||||
return validateChosenBuild(build, flags.selectedPlatform);
|
||||
} else if (flags.runArchiveFlags.latest) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AppJSONConfig, PackageJSONConfig, getConfig, modifyConfigAsync } from '@expo/config';
|
||||
import { AppJSONConfig, PackageJSONConfig, getConfig } from '@expo/config';
|
||||
import chalk from 'chalk';
|
||||
import { vol } from 'memfs';
|
||||
import { instance, mock } from 'ts-mockito';
|
||||
@@ -12,12 +12,17 @@ import FeatureGating from '../../../commandUtils/gating/FeatureGating';
|
||||
import { jester, jester2 } from '../../../credentials/__tests__/fixtures-constants';
|
||||
import { AppMutation } from '../../../graphql/mutations/AppMutation';
|
||||
import { AppQuery } from '../../../graphql/queries/AppQuery';
|
||||
import { createOrModifyExpoConfigAsync } from '../../../project/expoConfig';
|
||||
import { findProjectIdByAccountNameAndSlugNullableAsync } from '../../../project/fetchOrCreateProjectIDForWriteToConfigWithConfirmationAsync';
|
||||
import { confirmAsync, promptAsync } from '../../../prompts';
|
||||
import ProjectInit from '../init';
|
||||
|
||||
jest.mock('fs');
|
||||
jest.mock('@expo/config');
|
||||
jest.mock('../../../project/expoConfig', () => ({
|
||||
...jest.requireActual('../../../project/expoConfig'),
|
||||
createOrModifyExpoConfigAsync: jest.fn(),
|
||||
}));
|
||||
jest.mock('../../../prompts');
|
||||
jest.mock('../../../user/actions');
|
||||
jest.mock('../../../graphql/mutations/AppMutation');
|
||||
@@ -143,13 +148,16 @@ describe(ProjectInit.name, () => {
|
||||
});
|
||||
|
||||
describe('force', () => {
|
||||
it('does not prompt to overwrite when different', async () => {
|
||||
beforeEach(() => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: '1234',
|
||||
slug: 'testing-123',
|
||||
fullName: '@jester/testing-123',
|
||||
ownerAccount: jester.accounts[0],
|
||||
});
|
||||
});
|
||||
|
||||
it('does not prompt to overwrite when different', async () => {
|
||||
await new ProjectInit(['--id', '12345', '--force'], {
|
||||
root: '/test-project',
|
||||
} as any).run();
|
||||
@@ -183,7 +191,7 @@ describe(ProjectInit.name, () => {
|
||||
});
|
||||
|
||||
await new ProjectInit(['--id', '1234'], commandOptions).run();
|
||||
expect(modifyConfigAsync).not.toHaveBeenCalled();
|
||||
expect(createOrModifyExpoConfigAsync).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('prompts to configure if not consistent', async () => {
|
||||
@@ -195,14 +203,20 @@ describe(ProjectInit.name, () => {
|
||||
});
|
||||
|
||||
jest.mocked(confirmAsync).mockResolvedValue(true);
|
||||
jest.mocked(modifyConfigAsync).mockResolvedValue({ type: 'success', config: {} as any });
|
||||
jest
|
||||
.mocked(createOrModifyExpoConfigAsync)
|
||||
.mockResolvedValue({ type: 'success', config: {} as any });
|
||||
|
||||
await new ProjectInit(['--id', '1234'], commandOptions).run();
|
||||
|
||||
expect(confirmAsync).toHaveBeenCalled();
|
||||
expect(modifyConfigAsync).toHaveBeenCalledTimes(2);
|
||||
expect(modifyConfigAsync).toHaveBeenCalledWith('/test-project', { owner: 'jester2' });
|
||||
expect(modifyConfigAsync).toHaveBeenCalledWith('/test-project', { slug: 'testing-124' });
|
||||
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledTimes(2);
|
||||
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledWith('/test-project', {
|
||||
owner: 'jester2',
|
||||
});
|
||||
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledWith('/test-project', {
|
||||
slug: 'testing-124',
|
||||
});
|
||||
});
|
||||
|
||||
it('overrides if force flag is present and it is not consistent', async () => {
|
||||
@@ -213,14 +227,20 @@ describe(ProjectInit.name, () => {
|
||||
ownerAccount: jester2.accounts[0],
|
||||
});
|
||||
|
||||
jest.mocked(modifyConfigAsync).mockResolvedValue({ type: 'success', config: {} as any });
|
||||
jest
|
||||
.mocked(createOrModifyExpoConfigAsync)
|
||||
.mockResolvedValue({ type: 'success', config: {} as any });
|
||||
|
||||
await new ProjectInit(['--id', '1234', '--force'], commandOptions).run();
|
||||
|
||||
expect(confirmAsync).not.toHaveBeenCalled();
|
||||
expect(modifyConfigAsync).toHaveBeenCalledTimes(2);
|
||||
expect(modifyConfigAsync).toHaveBeenCalledWith('/test-project', { owner: 'jester2' });
|
||||
expect(modifyConfigAsync).toHaveBeenCalledWith('/test-project', { slug: 'testing-124' });
|
||||
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledTimes(2);
|
||||
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledWith('/test-project', {
|
||||
owner: 'jester2',
|
||||
});
|
||||
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledWith('/test-project', {
|
||||
slug: 'testing-124',
|
||||
});
|
||||
});
|
||||
|
||||
it('throws if non-interactive is present and it is not consistent', async () => {
|
||||
@@ -231,7 +251,9 @@ describe(ProjectInit.name, () => {
|
||||
ownerAccount: jester2.accounts[0],
|
||||
});
|
||||
|
||||
jest.mocked(modifyConfigAsync).mockResolvedValue({ type: 'success', config: {} as any });
|
||||
jest
|
||||
.mocked(createOrModifyExpoConfigAsync)
|
||||
.mockResolvedValue({ type: 'success', config: {} as any });
|
||||
|
||||
await expect(
|
||||
new ProjectInit(['--id', '1234', '--non-interactive'], commandOptions).run()
|
||||
@@ -240,7 +262,7 @@ describe(ProjectInit.name, () => {
|
||||
);
|
||||
|
||||
expect(confirmAsync).not.toHaveBeenCalled();
|
||||
expect(modifyConfigAsync).not.toHaveBeenCalled();
|
||||
expect(createOrModifyExpoConfigAsync).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -271,7 +293,7 @@ describe(ProjectInit.name, () => {
|
||||
});
|
||||
|
||||
await new ProjectInit(['--id', '1234'], commandOptions).run();
|
||||
expect(modifyConfigAsync).not.toHaveBeenCalled();
|
||||
expect(createOrModifyExpoConfigAsync).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('prompts to configure if not consistent', async () => {
|
||||
@@ -285,14 +307,20 @@ describe(ProjectInit.name, () => {
|
||||
});
|
||||
|
||||
jest.mocked(confirmAsync).mockResolvedValue(true);
|
||||
jest.mocked(modifyConfigAsync).mockResolvedValue({ type: 'success', config: {} as any });
|
||||
jest
|
||||
.mocked(createOrModifyExpoConfigAsync)
|
||||
.mockResolvedValue({ type: 'success', config: {} as any });
|
||||
|
||||
await new ProjectInit(['--id', '1234'], commandOptions).run();
|
||||
|
||||
expect(confirmAsync).toHaveBeenCalled();
|
||||
expect(modifyConfigAsync).toHaveBeenCalledTimes(2);
|
||||
expect(modifyConfigAsync).toHaveBeenCalledWith('/test-project', { owner: 'jester2' });
|
||||
expect(modifyConfigAsync).toHaveBeenCalledWith('/test-project', { slug: 'testing-124' });
|
||||
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledTimes(2);
|
||||
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledWith('/test-project', {
|
||||
owner: 'jester2',
|
||||
});
|
||||
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledWith('/test-project', {
|
||||
slug: 'testing-124',
|
||||
});
|
||||
});
|
||||
|
||||
it('overrides if force flag is present and it is not consistent', async () => {
|
||||
@@ -305,14 +333,20 @@ describe(ProjectInit.name, () => {
|
||||
ownerAccount: jester2.accounts[0],
|
||||
});
|
||||
|
||||
jest.mocked(modifyConfigAsync).mockResolvedValue({ type: 'success', config: {} as any });
|
||||
jest
|
||||
.mocked(createOrModifyExpoConfigAsync)
|
||||
.mockResolvedValue({ type: 'success', config: {} as any });
|
||||
|
||||
await new ProjectInit(['--id', '1234', '--force'], commandOptions).run();
|
||||
|
||||
expect(confirmAsync).not.toHaveBeenCalled();
|
||||
expect(modifyConfigAsync).toHaveBeenCalledTimes(2);
|
||||
expect(modifyConfigAsync).toHaveBeenCalledWith('/test-project', { owner: 'jester2' });
|
||||
expect(modifyConfigAsync).toHaveBeenCalledWith('/test-project', { slug: 'testing-124' });
|
||||
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledTimes(2);
|
||||
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledWith('/test-project', {
|
||||
owner: 'jester2',
|
||||
});
|
||||
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledWith('/test-project', {
|
||||
slug: 'testing-124',
|
||||
});
|
||||
});
|
||||
|
||||
it('throws if non-interactive is present and it is not consistent', async () => {
|
||||
@@ -325,7 +359,9 @@ describe(ProjectInit.name, () => {
|
||||
ownerAccount: jester2.accounts[0],
|
||||
});
|
||||
|
||||
jest.mocked(modifyConfigAsync).mockResolvedValue({ type: 'success', config: {} as any });
|
||||
jest
|
||||
.mocked(createOrModifyExpoConfigAsync)
|
||||
.mockResolvedValue({ type: 'success', config: {} as any });
|
||||
|
||||
await expect(
|
||||
new ProjectInit(['--id', '1234', '--non-interactive'], commandOptions).run()
|
||||
@@ -334,7 +370,7 @@ describe(ProjectInit.name, () => {
|
||||
);
|
||||
|
||||
expect(confirmAsync).not.toHaveBeenCalled();
|
||||
expect(modifyConfigAsync).not.toHaveBeenCalled();
|
||||
expect(createOrModifyExpoConfigAsync).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -367,14 +403,20 @@ describe(ProjectInit.name, () => {
|
||||
});
|
||||
|
||||
jest.mocked(confirmAsync).mockResolvedValue(true);
|
||||
jest.mocked(modifyConfigAsync).mockResolvedValue({ type: 'success', config: {} as any });
|
||||
jest
|
||||
.mocked(createOrModifyExpoConfigAsync)
|
||||
.mockResolvedValue({ type: 'success', config: {} as any });
|
||||
|
||||
await new ProjectInit([], commandOptions).run();
|
||||
|
||||
expect(confirmAsync).toHaveBeenCalled();
|
||||
expect(modifyConfigAsync).toHaveBeenCalledTimes(2);
|
||||
expect(modifyConfigAsync).toHaveBeenCalledWith('/test-project', { owner: 'jester2' });
|
||||
expect(modifyConfigAsync).toHaveBeenCalledWith('/test-project', { slug: 'testing-124' });
|
||||
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledTimes(2);
|
||||
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledWith('/test-project', {
|
||||
owner: 'jester2',
|
||||
});
|
||||
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledWith('/test-project', {
|
||||
slug: 'testing-124',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getProjectConfigDescription, modifyConfigAsync } from '@expo/config';
|
||||
import { getProjectConfigDescription } from '@expo/config';
|
||||
import { ExpoConfig } from '@expo/config-types';
|
||||
import { Flags } from '@oclif/core';
|
||||
import chalk from 'chalk';
|
||||
@@ -13,7 +13,7 @@ import { AppMutation } from '../../graphql/mutations/AppMutation';
|
||||
import { AppQuery } from '../../graphql/queries/AppQuery';
|
||||
import Log, { link } from '../../log';
|
||||
import { ora } from '../../ora';
|
||||
import { getPrivateExpoConfig } from '../../project/expoConfig';
|
||||
import { createOrModifyExpoConfigAsync, getPrivateExpoConfig } from '../../project/expoConfig';
|
||||
import { findProjectIdByAccountNameAndSlugNullableAsync } from '../../project/fetchOrCreateProjectIDForWriteToConfigWithConfirmationAsync';
|
||||
import { toAppPrivacy } from '../../project/projectUtils';
|
||||
import { confirmAsync, promptAsync } from '../../prompts';
|
||||
@@ -60,7 +60,7 @@ export default class ProjectInit extends EasCommand {
|
||||
projectDir: string,
|
||||
modifications: Partial<ExpoConfig>
|
||||
): Promise<void> {
|
||||
const result = await modifyConfigAsync(projectDir, modifications);
|
||||
const result = await createOrModifyExpoConfigAsync(projectDir, modifications);
|
||||
switch (result.type) {
|
||||
case 'success':
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { ExpoConfig } from '@expo/config';
|
||||
import { instance, mock } from 'ts-mockito';
|
||||
|
||||
import { ExpoGraphqlClient } from '../../../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
import { ensureEASUpdateIsConfiguredAsync } from '../../../update/configure';
|
||||
|
||||
describe(ensureEASUpdateIsConfiguredAsync, () => {
|
||||
it('errors with "useClassicUpdates" set and no app.json', async () => {
|
||||
const graphqlClient = instance(mock<ExpoGraphqlClient>({}));
|
||||
const exp: ExpoConfig = {
|
||||
name: 'test',
|
||||
slug: 'test',
|
||||
updates: { useClassicUpdates: true },
|
||||
};
|
||||
|
||||
await expect(async () => {
|
||||
await ensureEASUpdateIsConfiguredAsync(graphqlClient, {
|
||||
exp,
|
||||
projectId: 'test',
|
||||
projectDir: '/tmp/test',
|
||||
platform: null,
|
||||
});
|
||||
}).rejects.toThrow(
|
||||
`Your app config sets "updates.useClassicUpdates" but EAS Update does not support classic updates. Remove "useClassicUpdates" from your app config and run this command again.`
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,14 +1,16 @@
|
||||
import { Flags } from '@oclif/core';
|
||||
import chalk from 'chalk';
|
||||
|
||||
import { easJsonExistsAsync } from '../../build/configure';
|
||||
import EasCommand from '../../commandUtils/EasCommand';
|
||||
import { EASNonInteractiveFlag } from '../../commandUtils/flags';
|
||||
import Log from '../../log';
|
||||
import Log, { learnMore } from '../../log';
|
||||
import { RequestedPlatform } from '../../platform';
|
||||
import {
|
||||
ensureEASUpdateIsConfiguredAsync,
|
||||
ensureEASUpdateIsConfiguredInEasJsonAsync,
|
||||
} from '../../update/configure';
|
||||
import { getVcsClient } from '../../vcs';
|
||||
|
||||
export default class UpdateConfigure extends EasCommand {
|
||||
static override description = 'configure the project to support EAS Update';
|
||||
@@ -39,9 +41,11 @@ export default class UpdateConfigure extends EasCommand {
|
||||
});
|
||||
|
||||
Log.log(
|
||||
'💡 The following process will configure your project to run EAS Update. These changes only apply to your local project files and you can safely revert them at any time.'
|
||||
'💡 The following process will configure your project to use EAS Update. These changes only apply to your local project files and you can safely revert them at any time.'
|
||||
);
|
||||
|
||||
await getVcsClient().ensureRepoExistsAsync();
|
||||
|
||||
await ensureEASUpdateIsConfiguredAsync(graphqlClient, {
|
||||
exp,
|
||||
projectId,
|
||||
@@ -52,23 +56,16 @@ export default class UpdateConfigure extends EasCommand {
|
||||
await ensureEASUpdateIsConfiguredInEasJsonAsync(projectDir);
|
||||
|
||||
Log.addNewLineIfNone();
|
||||
Log.log(`🎉 Your app is configured with EAS Update!`);
|
||||
Log.log(`🎉 Your app is configured to use EAS Update!`);
|
||||
Log.newLine();
|
||||
Log.log(`${chalk.bold('Next steps')}:`);
|
||||
Log.newLine();
|
||||
Log.log('Update a production build:');
|
||||
Log.log(`1. Create a new build. Example: ${chalk.bold('eas build --profile production')}.`);
|
||||
Log.log('2. Make changes in your project.');
|
||||
Log.log(`3. Publish an update. Example: ${chalk.bold('eas update --channel production')}.`);
|
||||
Log.log('4. Force close and reopen the app at least twice to view the update.');
|
||||
|
||||
Log.newLine();
|
||||
Log.log('Preview an update:');
|
||||
const easJsonExists = await easJsonExistsAsync(projectDir);
|
||||
if (!easJsonExists) {
|
||||
Log.log(`- Run ${chalk.bold('eas build:configure')} to complete your installation`);
|
||||
}
|
||||
Log.log(
|
||||
`1. Publish an update to a branch. Example: ${chalk.bold('eas update --branch new-feature')}.`
|
||||
);
|
||||
Log.log(
|
||||
'2. In Expo Go or a development build, navigate to Projects > [project name] > Branch > Open.'
|
||||
`- ${learnMore('https://docs.expo.dev/eas-update/introduction/', {
|
||||
learnMoreMessage: 'Learn more about other capabilities of EAS Update',
|
||||
})}`
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import { RequestedPlatform } from '../../platform';
|
||||
import { getOwnerAccountForProjectIdAsync } from '../../project/projectUtils';
|
||||
import {
|
||||
ExpoCLIExportPlatformFlag,
|
||||
RawAsset,
|
||||
buildBundlesAsync,
|
||||
buildUnsortedUpdateInfoGroupAsync,
|
||||
collectAssetsAsync,
|
||||
@@ -45,6 +46,7 @@ import {
|
||||
getManifestBodyAsync,
|
||||
signBody,
|
||||
} from '../../utils/code-signing';
|
||||
import areSetsEqual from '../../utils/expodash/areSetsEqual';
|
||||
import uniqBy from '../../utils/expodash/uniqBy';
|
||||
import formatFields from '../../utils/formatFields';
|
||||
import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
|
||||
@@ -96,6 +98,7 @@ export default class UpdatePublish extends EasCommand {
|
||||
required: false,
|
||||
}),
|
||||
message: Flags.string({
|
||||
char: 'm',
|
||||
description: 'A short message describing the update',
|
||||
required: false,
|
||||
}),
|
||||
@@ -238,14 +241,58 @@ export default class UpdatePublish extends EasCommand {
|
||||
const assets = filterExportedPlatformsByFlag(collectedAssets, platformFlag);
|
||||
realizedPlatforms = Object.keys(assets) as PublishPlatform[];
|
||||
|
||||
const uploadResults = await uploadAssetsAsync(
|
||||
graphqlClient,
|
||||
assets,
|
||||
projectId,
|
||||
(totalAssets, missingAssets) => {
|
||||
assetSpinner.text = `Uploading (${totalAssets - missingAssets}/${totalAssets})`;
|
||||
}
|
||||
);
|
||||
// Timeout mechanism:
|
||||
// - Start with 60 second timeout. 60 seconds is chosen because the cloud function that processes
|
||||
// uploaded assets has a timeout of 60 seconds.
|
||||
// - Each time one or more assets reports as ready, reset the timeout to 60 seconds.
|
||||
// - Start upload. Internally, uploadAssetsAsync uploads them all and then checks for successful
|
||||
// processing every (5 + n) seconds with a linear backoff of n + 1 second.
|
||||
// - At the same time as upload is started, start timeout checker which checks every 1 second to see
|
||||
// if timeout has been reached. When timeout expires, send a cancellation signal to currently running
|
||||
// upload function call to instruct it to stop uploading or checking for successful processing.
|
||||
let lastUploadedStorageKeys = new Set<string>();
|
||||
let lastAssetUploadResults: {
|
||||
asset: RawAsset & { storageKey: string };
|
||||
finished: boolean;
|
||||
}[] = [];
|
||||
let timeAtWhichToTimeout = Date.now() + 60 * 1000; // sixty seconds from now
|
||||
const cancelationToken = { isCanceledOrFinished: false };
|
||||
|
||||
const uploadResults = await Promise.race([
|
||||
uploadAssetsAsync(
|
||||
graphqlClient,
|
||||
assets,
|
||||
projectId,
|
||||
cancelationToken,
|
||||
assetUploadResults => {
|
||||
const currentUploadedStorageKeys = new Set(
|
||||
assetUploadResults.filter(r => r.finished).map(r => r.asset.storageKey)
|
||||
);
|
||||
if (!areSetsEqual(currentUploadedStorageKeys, lastUploadedStorageKeys)) {
|
||||
timeAtWhichToTimeout = Date.now() + 60 * 1000; // reset timeout to sixty seconds from now
|
||||
lastUploadedStorageKeys = currentUploadedStorageKeys;
|
||||
lastAssetUploadResults = assetUploadResults;
|
||||
}
|
||||
|
||||
const totalAssets = assetUploadResults.length;
|
||||
const missingAssetCount = assetUploadResults.filter(a => !a.finished).length;
|
||||
assetSpinner.text = `Uploading (${totalAssets - missingAssetCount}/${totalAssets})`;
|
||||
}
|
||||
),
|
||||
(async () => {
|
||||
while (Date.now() < timeAtWhichToTimeout) {
|
||||
if (cancelationToken.isCanceledOrFinished) {
|
||||
break;
|
||||
}
|
||||
await new Promise(res => setTimeout(res, 1000)); // wait 1 second
|
||||
}
|
||||
cancelationToken.isCanceledOrFinished = true;
|
||||
const timedOutAssets = lastAssetUploadResults
|
||||
.filter(r => !r.finished)
|
||||
.map(r => `\n- ${r.asset.originalPath ?? r.asset.path}`);
|
||||
throw new Error(`Asset processing timed out for assets: ${timedOutAssets}`);
|
||||
})(),
|
||||
]);
|
||||
|
||||
uploadedAssetCount = uploadResults.uniqueUploadedAssetCount;
|
||||
assetLimitPerUpdateGroup = uploadResults.assetLimitPerUpdateGroup;
|
||||
|
||||
@@ -72,6 +72,7 @@ export default class UpdateRepublish extends EasCommand {
|
||||
exclusive: ['branch', 'channel'],
|
||||
}),
|
||||
message: Flags.string({
|
||||
char: 'm',
|
||||
description: 'Short message describing the republished update',
|
||||
required: false,
|
||||
}),
|
||||
|
||||
@@ -151,6 +151,7 @@ export function getNewAndroidApiMock(): { [key in keyof typeof AndroidGraphqlCli
|
||||
updateAndroidAppCredentialsAsync: jest.fn(),
|
||||
updateAndroidAppBuildCredentialsAsync: jest.fn(),
|
||||
createAndroidAppBuildCredentialsAsync: jest.fn(),
|
||||
setDefaultAndroidAppBuildCredentialsAsync: jest.fn(),
|
||||
getDefaultAndroidAppBuildCredentialsAsync: jest.fn(),
|
||||
getAndroidAppBuildCredentialsByNameAsync: jest.fn(),
|
||||
createOrUpdateAndroidAppBuildCredentialsByNameAsync: jest.fn(),
|
||||
|
||||
@@ -146,6 +146,16 @@ export async function updateAndroidAppBuildCredentialsAsync(
|
||||
);
|
||||
}
|
||||
|
||||
export async function setDefaultAndroidAppBuildCredentialsAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
buildCredentials: AndroidAppBuildCredentialsFragment
|
||||
): Promise<AndroidAppBuildCredentialsFragment> {
|
||||
return await AndroidAppBuildCredentialsMutation.setDefaultAndroidAppBuildCredentialsAsync(
|
||||
graphqlClient,
|
||||
buildCredentials.id
|
||||
);
|
||||
}
|
||||
|
||||
export async function createAndroidAppBuildCredentialsAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
appLookupParams: AppLookupParams,
|
||||
@@ -164,14 +174,6 @@ export async function createAndroidAppBuildCredentialsAsync(
|
||||
graphqlClient,
|
||||
appLookupParams
|
||||
);
|
||||
const buildCredentialsList = androidAppCredentials.androidAppBuildCredentialsList;
|
||||
const existingDefaultBuildCredentials =
|
||||
buildCredentialsList.find(buildCredentials => buildCredentials.isDefault) ?? null;
|
||||
if (existingDefaultBuildCredentials && isDefault) {
|
||||
throw new Error(
|
||||
'Cannot create new default Android Build Credentials. A set of default credentials exists already.'
|
||||
);
|
||||
}
|
||||
|
||||
return await AndroidAppBuildCredentialsMutation.createAndroidAppBuildCredentialsAsync(
|
||||
graphqlClient,
|
||||
|
||||
+32
@@ -5,6 +5,7 @@ import gql from 'graphql-tag';
|
||||
import { ExpoGraphqlClient } from '../../../../../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
import { withErrorHandlingAsync } from '../../../../../graphql/client';
|
||||
import {
|
||||
AndroidAppBuildCredentials,
|
||||
AndroidAppBuildCredentialsFragment,
|
||||
AndroidAppBuildCredentialsInput,
|
||||
CreateAndroidAppBuildCredentialsMutation,
|
||||
@@ -55,6 +56,37 @@ export const AndroidAppBuildCredentialsMutation = {
|
||||
);
|
||||
return data.androidAppBuildCredentials.createAndroidAppBuildCredentials;
|
||||
},
|
||||
async setDefaultAndroidAppBuildCredentialsAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
androidAppBuildCredentialsId: string
|
||||
): Promise<AndroidAppBuildCredentialsFragment> {
|
||||
const data = await withErrorHandlingAsync(
|
||||
graphqlClient
|
||||
.mutation<AndroidAppBuildCredentials>(
|
||||
gql`
|
||||
mutation AndroidAppBuildCredentialsMutation(
|
||||
$androidAppBuildCredentialsId: ID!
|
||||
$isDefault: Boolean!
|
||||
) {
|
||||
androidAppBuildCredentials {
|
||||
setDefault(id: $androidAppBuildCredentialsId, isDefault: $isDefault) {
|
||||
id
|
||||
...AndroidAppBuildCredentialsFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
${print(AndroidAppBuildCredentialsFragmentNode)}
|
||||
`,
|
||||
{
|
||||
androidAppBuildCredentialsId,
|
||||
isDefault: true,
|
||||
}
|
||||
)
|
||||
.toPromise()
|
||||
);
|
||||
assert(data, `GraphQL: 'setDefault' not defined in server response ${JSON.stringify(data)}}`);
|
||||
return data;
|
||||
},
|
||||
async setKeystoreAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
androidAppBuildCredentialsId: string,
|
||||
|
||||
@@ -513,6 +513,20 @@ export const CapabilityMapping: CapabilityClassifier[] = [
|
||||
validateOptions: createValidateStringArrayOptions(['app-usage', 'system-installation']),
|
||||
getOptions: getDefinedOptions,
|
||||
},
|
||||
{
|
||||
name: 'Apple Pay Later Merchandising',
|
||||
entitlement: 'com.apple.developer.pay-later-merchandising',
|
||||
capability: CapabilityType.APPLE_PAY_LATER_MERCHANDISING,
|
||||
validateOptions: createValidateStringArrayOptions(['payinfour-merchandising']),
|
||||
getOptions: getDefinedOptions,
|
||||
},
|
||||
{
|
||||
name: 'Sensitive Content Analysis',
|
||||
entitlement: 'com.apple.developer.sensitivecontentanalysis.client',
|
||||
capability: CapabilityType.SENSITIVE_CONTENT_ANALYSIS,
|
||||
validateOptions: createValidateStringArrayOptions(['analysis']),
|
||||
getOptions: getDefinedOptions,
|
||||
},
|
||||
{
|
||||
// Not in Xcode
|
||||
// https://developer-mdn.apple.com/documentation/devicecheck/preparing_to_use_the_app_attest_service
|
||||
@@ -698,6 +712,36 @@ export const CapabilityMapping: CapabilityClassifier[] = [
|
||||
validateOptions: validateBooleanOptions,
|
||||
getOptions: getBooleanOptions,
|
||||
},
|
||||
{
|
||||
entitlement: 'com.apple.developer.shared-with-you.collaboration',
|
||||
name: 'Messages Collaboration',
|
||||
capability: CapabilityType.MESSAGES_COLLABORATION,
|
||||
validateOptions: validateBooleanOptions,
|
||||
getOptions: getBooleanOptions,
|
||||
},
|
||||
{
|
||||
entitlement: 'com.apple.developer.submerged-shallow-depth-and-pressure',
|
||||
name: 'Shallow Depth and Pressure',
|
||||
capability: CapabilityType.SHALLOW_DEPTH_PRESSURE,
|
||||
validateOptions: validateBooleanOptions,
|
||||
getOptions: getBooleanOptions,
|
||||
},
|
||||
{
|
||||
entitlement: 'com.apple.developer.proximity-reader.identity.display',
|
||||
name: 'Tap to Present ID on iPhone (Display Only)',
|
||||
capability: CapabilityType.TAP_TO_DISPLAY_ID,
|
||||
validateOptions: validateBooleanOptions,
|
||||
getOptions: getBooleanOptions,
|
||||
},
|
||||
{
|
||||
entitlement: 'com.apple.developer.matter.allow-setup-payload',
|
||||
name: 'Matter Allow Setup Payload',
|
||||
capability: CapabilityType.MATTER_ALLOW_SETUP_PAYLOAD,
|
||||
validateOptions: validateBooleanOptions,
|
||||
getOptions: getBooleanOptions,
|
||||
},
|
||||
|
||||
// VMNET
|
||||
|
||||
// These don't appear to have entitlements, so it's unclear how we can automatically enable / disable them at this time.
|
||||
// TODO: Maybe add a warning about manually enabling features?
|
||||
|
||||
@@ -18,6 +18,7 @@ export enum AndroidActionType {
|
||||
GoBackToCaller,
|
||||
GoBackToHighLevelActions,
|
||||
CreateKeystore,
|
||||
SetDefaultKeystore,
|
||||
DownloadKeystore,
|
||||
RemoveKeystore,
|
||||
CreateFcm,
|
||||
|
||||
@@ -52,6 +52,11 @@ export const buildCredentialsActions: ActionInfo[] = [
|
||||
title: 'Set up a new keystore',
|
||||
scope: Scope.Project,
|
||||
},
|
||||
{
|
||||
value: AndroidActionType.SetDefaultKeystore,
|
||||
title: 'Change default keystore',
|
||||
scope: Scope.Project,
|
||||
},
|
||||
{
|
||||
value: AndroidActionType.DownloadKeystore,
|
||||
title: 'Download existing keystore',
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import { AndroidAppBuildCredentialsFragment } from '../../graphql/generated';
|
||||
import Log from '../../log';
|
||||
import { confirmAsync } from '../../prompts';
|
||||
import { promptForNameAsync } from '../android/actions/BuildCredentialsUtils';
|
||||
import { CreateKeystore } from '../android/actions/CreateKeystore';
|
||||
import { AppLookupParams } from '../android/api/GraphqlClient';
|
||||
import { CredentialsContext } from '../context';
|
||||
|
||||
export class CreateAndroidBuildCredentials {
|
||||
constructor(private app: AppLookupParams) {}
|
||||
|
||||
async runAsync(ctx: CredentialsContext): Promise<AndroidAppBuildCredentialsFragment> {
|
||||
const name = await promptForNameAsync();
|
||||
|
||||
const buildCredentialsList = await ctx.android.getAndroidAppBuildCredentialsListAsync(
|
||||
ctx.graphqlClient,
|
||||
this.app
|
||||
);
|
||||
|
||||
let isDefault = true;
|
||||
if (buildCredentialsList.length > 0) {
|
||||
isDefault = await confirmAsync({
|
||||
message: 'Do you want to set this as your default build credentials?',
|
||||
initial: false,
|
||||
});
|
||||
}
|
||||
|
||||
const keystore = await new CreateKeystore(this.app.account).runAsync(ctx);
|
||||
const createAndroidCredentials = await ctx.android.createAndroidAppBuildCredentialsAsync(
|
||||
ctx.graphqlClient,
|
||||
this.app,
|
||||
{
|
||||
name,
|
||||
isDefault,
|
||||
androidKeystoreId: keystore.id,
|
||||
}
|
||||
);
|
||||
|
||||
Log.succeed(`Created Android build credentials ${createAndroidCredentials.name}`);
|
||||
return createAndroidCredentials;
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,6 @@ import {
|
||||
} from '../android/actions/BuildCredentialsUtils';
|
||||
import { CreateFcm } from '../android/actions/CreateFcm';
|
||||
import { CreateGoogleServiceAccountKey } from '../android/actions/CreateGoogleServiceAccountKey';
|
||||
import { CreateKeystore } from '../android/actions/CreateKeystore';
|
||||
import { DownloadKeystore } from '../android/actions/DownloadKeystore';
|
||||
import { RemoveFcm } from '../android/actions/RemoveFcm';
|
||||
import { SelectAndRemoveGoogleServiceAccountKey } from '../android/actions/RemoveGoogleServiceAccountKey';
|
||||
@@ -36,13 +35,11 @@ import {
|
||||
gsaKeyActions,
|
||||
highLevelActions,
|
||||
} from './AndroidActions';
|
||||
import { CreateAndroidBuildCredentials } from './CreateAndroidBuildCredentials';
|
||||
import { Action, PressAnyKeyToContinue } from './HelperActions';
|
||||
import {
|
||||
SelectAndroidBuildCredentials,
|
||||
SelectAndroidBuildCredentialsResultType,
|
||||
SelectExistingAndroidBuildCredentials,
|
||||
} from './SelectAndroidBuildCredentials';
|
||||
import { SelectExistingAndroidBuildCredentials } from './SelectAndroidBuildCredentials';
|
||||
import { SelectBuildProfileFromEasJson } from './SelectBuildProfileFromEasJson';
|
||||
import { SetDefaultAndroidKeystore } from './SetDefaultAndroidKeystore';
|
||||
|
||||
export class ManageAndroid {
|
||||
constructor(private callingAction: Action, private projectDir: string) {}
|
||||
@@ -163,31 +160,9 @@ export class ManageAndroid {
|
||||
);
|
||||
const appLookupParams = await getAppLookupParamsFromContextAsync(ctx, gradleContext);
|
||||
if (action === AndroidActionType.CreateKeystore) {
|
||||
const selectBuildCredentialsResult = await new SelectAndroidBuildCredentials(
|
||||
appLookupParams
|
||||
).runAsync(ctx);
|
||||
const keystore = await new CreateKeystore(appLookupParams.account).runAsync(ctx);
|
||||
if (
|
||||
selectBuildCredentialsResult.resultType ===
|
||||
SelectAndroidBuildCredentialsResultType.CREATE_REQUEST
|
||||
) {
|
||||
await ctx.android.createAndroidAppBuildCredentialsAsync(
|
||||
ctx.graphqlClient,
|
||||
appLookupParams,
|
||||
{
|
||||
...selectBuildCredentialsResult.result,
|
||||
androidKeystoreId: keystore.id,
|
||||
}
|
||||
);
|
||||
} else {
|
||||
await ctx.android.updateAndroidAppBuildCredentialsAsync(
|
||||
ctx.graphqlClient,
|
||||
selectBuildCredentialsResult.result,
|
||||
{
|
||||
androidKeystoreId: keystore.id,
|
||||
}
|
||||
);
|
||||
}
|
||||
await new CreateAndroidBuildCredentials(appLookupParams).runAsync(ctx);
|
||||
} else if (action === AndroidActionType.SetDefaultKeystore) {
|
||||
await new SetDefaultAndroidKeystore(appLookupParams).runAsync(ctx);
|
||||
} else if (action === AndroidActionType.DownloadKeystore) {
|
||||
const buildCredentials = await new SelectExistingAndroidBuildCredentials(
|
||||
appLookupParams
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import { AndroidAppBuildCredentialsFragment } from '../../graphql/generated';
|
||||
import Log from '../../log';
|
||||
import { promptAsync } from '../../prompts';
|
||||
import { sortBuildCredentials } from '../android/actions/BuildCredentialsUtils';
|
||||
import { AppLookupParams } from '../android/api/GraphqlClient';
|
||||
import { CredentialsContext } from '../context';
|
||||
|
||||
export class SetDefaultAndroidKeystore {
|
||||
constructor(private app: AppLookupParams) {}
|
||||
|
||||
async runAsync(ctx: CredentialsContext): Promise<AndroidAppBuildCredentialsFragment | undefined> {
|
||||
const buildCredentialsList = await ctx.android.getAndroidAppBuildCredentialsListAsync(
|
||||
ctx.graphqlClient,
|
||||
this.app
|
||||
);
|
||||
if (buildCredentialsList.length === 0) {
|
||||
Log.log(`You don't have any Android build credentials`);
|
||||
return;
|
||||
}
|
||||
const sortedBuildCredentialsList = sortBuildCredentials(buildCredentialsList);
|
||||
const sortedBuildCredentialsChoices = sortedBuildCredentialsList.map(buildCredentials => ({
|
||||
title: buildCredentials.isDefault
|
||||
? `${buildCredentials.name} (Default)`
|
||||
: buildCredentials.name,
|
||||
value: buildCredentials,
|
||||
}));
|
||||
|
||||
const { buildCredentialsResult } = await promptAsync({
|
||||
type: 'select',
|
||||
name: 'buildCredentialsResult',
|
||||
message: 'Select build credentials',
|
||||
choices: [...sortedBuildCredentialsChoices, { title: 'Cancel', value: null }],
|
||||
});
|
||||
|
||||
if (!buildCredentialsResult?.androidKeystore) {
|
||||
return;
|
||||
}
|
||||
|
||||
Log.log('Updating the default build credentials for this project...');
|
||||
return await ctx.android.setDefaultAndroidAppBuildCredentialsAsync(ctx.graphqlClient, {
|
||||
...buildCredentialsResult,
|
||||
isDefault: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,16 @@ export async function withErrorHandlingAsync<T>(promise: Promise<OperationResult
|
||||
const { data, error } = await promise;
|
||||
|
||||
if (error) {
|
||||
if (error.graphQLErrors.some(e => e?.extensions?.isTransient)) {
|
||||
if (
|
||||
error.graphQLErrors.some(
|
||||
e =>
|
||||
e?.extensions?.isTransient &&
|
||||
![
|
||||
'EAS_BUILD_FREE_TIER_LIMIT_EXCEEDED',
|
||||
'EAS_BUILD_FREE_TIER_IOS_LIMIT_EXCEEDED',
|
||||
].includes(e?.extensions?.errorCode as string)
|
||||
)
|
||||
) {
|
||||
Log.error(`We've encountered a transient error. Try again shortly.`);
|
||||
}
|
||||
throw error;
|
||||
|
||||
+65
-13
@@ -1164,6 +1164,7 @@ export type AppBuildsPaginatedArgs = {
|
||||
export type AppChannelsPaginatedArgs = {
|
||||
after?: InputMaybe<Scalars['String']>;
|
||||
before?: InputMaybe<Scalars['String']>;
|
||||
filter?: InputMaybe<ChannelFilterInput>;
|
||||
first?: InputMaybe<Scalars['Int']>;
|
||||
last?: InputMaybe<Scalars['Int']>;
|
||||
};
|
||||
@@ -1363,6 +1364,7 @@ export type AppInput = {
|
||||
|
||||
export type AppInsights = {
|
||||
__typename?: 'AppInsights';
|
||||
hasEventsFromExpoInsightsClientModule: Scalars['Boolean'];
|
||||
totalUniqueUsers?: Maybe<Scalars['Int']>;
|
||||
uniqueUsersByAppVersionOverTime: UniqueUsersOverTimeData;
|
||||
uniqueUsersByPlatformOverTime: UniqueUsersOverTimeData;
|
||||
@@ -1980,6 +1982,43 @@ export enum AuthProtocolType {
|
||||
Oidc = 'OIDC'
|
||||
}
|
||||
|
||||
export type BackgroundJobReceipt = {
|
||||
__typename?: 'BackgroundJobReceipt';
|
||||
account: Account;
|
||||
createdAt: Scalars['DateTime'];
|
||||
errorCode?: Maybe<Scalars['String']>;
|
||||
errorMessage?: Maybe<Scalars['String']>;
|
||||
id: Scalars['ID'];
|
||||
resultId?: Maybe<Scalars['ID']>;
|
||||
resultType: BackgroundJobResultType;
|
||||
state: BackgroundJobState;
|
||||
tries: Scalars['Int'];
|
||||
updatedAt: Scalars['DateTime'];
|
||||
willRetry: Scalars['Boolean'];
|
||||
};
|
||||
|
||||
export type BackgroundJobReceiptQuery = {
|
||||
__typename?: 'BackgroundJobReceiptQuery';
|
||||
/** Look up background job receipt by ID */
|
||||
byId: BackgroundJobReceipt;
|
||||
};
|
||||
|
||||
|
||||
export type BackgroundJobReceiptQueryByIdArgs = {
|
||||
id: Scalars['ID'];
|
||||
};
|
||||
|
||||
export enum BackgroundJobResultType {
|
||||
GithubBuild = 'GITHUB_BUILD'
|
||||
}
|
||||
|
||||
export enum BackgroundJobState {
|
||||
Failure = 'FAILURE',
|
||||
InProgress = 'IN_PROGRESS',
|
||||
Queued = 'QUEUED',
|
||||
Success = 'SUCCESS'
|
||||
}
|
||||
|
||||
export type Billing = {
|
||||
__typename?: 'Billing';
|
||||
/** History of invoices */
|
||||
@@ -2480,6 +2519,10 @@ export type Card = {
|
||||
last4?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type ChannelFilterInput = {
|
||||
searchTerm?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type Charge = {
|
||||
__typename?: 'Charge';
|
||||
amount: Scalars['Int'];
|
||||
@@ -3011,8 +3054,8 @@ export enum GitHubAppInstallationStatus {
|
||||
|
||||
export type GitHubAppMutation = {
|
||||
__typename?: 'GitHubAppMutation';
|
||||
/** Create a GitHub build for an app */
|
||||
createGitHubBuild: Scalars['Boolean'];
|
||||
/** Create a GitHub build for an app. Returns the ID of the background job receipt. Use BackgroundJobReceiptQuery to get the status of the job. */
|
||||
createGitHubBuild: BackgroundJobReceipt;
|
||||
};
|
||||
|
||||
|
||||
@@ -4122,6 +4165,7 @@ export type RootQuery = {
|
||||
/** Top-level query object for querying Apple Teams. */
|
||||
appleTeam: AppleTeamQuery;
|
||||
asset: AssetQuery;
|
||||
backgroundJobReceipt: BackgroundJobReceiptQuery;
|
||||
buildJobs: BuildJobQuery;
|
||||
buildOrBuildJob: BuildOrBuildJobQuery;
|
||||
/** Top-level query object for querying BuildPublicData publicly. */
|
||||
@@ -4221,6 +4265,7 @@ export type SsoUser = Actor & UserActor & {
|
||||
/** Coalesced project activity for all apps belonging to all accounts this user belongs to. Only resolves for the viewer. */
|
||||
activityTimelineProjectActivities: Array<ActivityTimelineProjectActivity>;
|
||||
appCount: Scalars['Int'];
|
||||
/** @deprecated No longer supported */
|
||||
appetizeCode?: Maybe<Scalars['String']>;
|
||||
/** Apps this user has published. If this user is the viewer, this field returns the apps the user has access to. */
|
||||
apps: Array<App>;
|
||||
@@ -4238,11 +4283,14 @@ export type SsoUser = Actor & UserActor & {
|
||||
fullName?: Maybe<Scalars['String']>;
|
||||
/** GitHub account linked to a user */
|
||||
githubUser?: Maybe<GitHubUser>;
|
||||
/** @deprecated No longer supported */
|
||||
githubUsername?: Maybe<Scalars['String']>;
|
||||
id: Scalars['ID'];
|
||||
/** @deprecated No longer supported */
|
||||
industry?: Maybe<Scalars['String']>;
|
||||
isExpoAdmin: Scalars['Boolean'];
|
||||
lastName?: Maybe<Scalars['String']>;
|
||||
/** @deprecated No longer supported */
|
||||
location?: Maybe<Scalars['String']>;
|
||||
notificationSubscriptions: Array<NotificationSubscription>;
|
||||
/** Associated accounts */
|
||||
@@ -4250,6 +4298,7 @@ export type SsoUser = Actor & UserActor & {
|
||||
profilePhoto: Scalars['String'];
|
||||
/** Snacks associated with this account */
|
||||
snacks: Array<Snack>;
|
||||
/** @deprecated No longer supported */
|
||||
twitterUsername?: Maybe<Scalars['String']>;
|
||||
username: Scalars['String'];
|
||||
};
|
||||
@@ -4291,11 +4340,7 @@ export type SsoUserSnacksArgs = {
|
||||
|
||||
export type SsoUserDataInput = {
|
||||
firstName?: InputMaybe<Scalars['String']>;
|
||||
githubUsername?: InputMaybe<Scalars['String']>;
|
||||
industry?: InputMaybe<Scalars['String']>;
|
||||
lastName?: InputMaybe<Scalars['String']>;
|
||||
location?: InputMaybe<Scalars['String']>;
|
||||
twitterUsername?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type SsoUserQuery = {
|
||||
@@ -4748,6 +4793,7 @@ export type Update = ActivityTimelineProjectActivity & {
|
||||
|
||||
export type UpdateBranch = {
|
||||
__typename?: 'UpdateBranch';
|
||||
app: App;
|
||||
appId: Scalars['ID'];
|
||||
createdAt: Scalars['DateTime'];
|
||||
id: Scalars['ID'];
|
||||
@@ -4809,6 +4855,7 @@ export type UpdateBranchMutationPublishUpdateGroupsArgs = {
|
||||
|
||||
export type UpdateChannel = {
|
||||
__typename?: 'UpdateChannel';
|
||||
app: App;
|
||||
appId: Scalars['ID'];
|
||||
branchMapping: Scalars['String'];
|
||||
createdAt: Scalars['DateTime'];
|
||||
@@ -4960,6 +5007,7 @@ export type User = Actor & UserActor & {
|
||||
/** Coalesced project activity for all apps belonging to all accounts this user belongs to. Only resolves for the viewer. */
|
||||
activityTimelineProjectActivities: Array<ActivityTimelineProjectActivity>;
|
||||
appCount: Scalars['Int'];
|
||||
/** @deprecated No longer supported */
|
||||
appetizeCode?: Maybe<Scalars['String']>;
|
||||
/** Apps this user has published */
|
||||
apps: Array<App>;
|
||||
@@ -4979,16 +5027,19 @@ export type User = Actor & UserActor & {
|
||||
fullName?: Maybe<Scalars['String']>;
|
||||
/** GitHub account linked to a user */
|
||||
githubUser?: Maybe<GitHubUser>;
|
||||
/** @deprecated No longer supported */
|
||||
githubUsername?: Maybe<Scalars['String']>;
|
||||
/** Whether this user has any pending user invitations. Only resolves for the viewer. */
|
||||
hasPendingUserInvitations: Scalars['Boolean'];
|
||||
id: Scalars['ID'];
|
||||
/** @deprecated No longer supported */
|
||||
industry?: Maybe<Scalars['String']>;
|
||||
isExpoAdmin: Scalars['Boolean'];
|
||||
/** @deprecated This field no longer exists */
|
||||
/** @deprecated No longer supported */
|
||||
isLegacy: Scalars['Boolean'];
|
||||
isSecondFactorAuthenticationEnabled: Scalars['Boolean'];
|
||||
lastName?: Maybe<Scalars['String']>;
|
||||
/** @deprecated No longer supported */
|
||||
location?: Maybe<Scalars['String']>;
|
||||
notificationSubscriptions: Array<NotificationSubscription>;
|
||||
/** Pending UserInvitations for this user. Only resolves for the viewer. */
|
||||
@@ -5000,6 +5051,7 @@ export type User = Actor & UserActor & {
|
||||
secondFactorDevices: Array<UserSecondFactorDevice>;
|
||||
/** Snacks associated with this account */
|
||||
snacks: Array<Snack>;
|
||||
/** @deprecated No longer supported */
|
||||
twitterUsername?: Maybe<Scalars['String']>;
|
||||
username: Scalars['String'];
|
||||
};
|
||||
@@ -5050,6 +5102,7 @@ export type UserActor = {
|
||||
*/
|
||||
activityTimelineProjectActivities: Array<ActivityTimelineProjectActivity>;
|
||||
appCount: Scalars['Int'];
|
||||
/** @deprecated No longer supported */
|
||||
appetizeCode?: Maybe<Scalars['String']>;
|
||||
/** Apps this user has published */
|
||||
apps: Array<App>;
|
||||
@@ -5071,11 +5124,14 @@ export type UserActor = {
|
||||
fullName?: Maybe<Scalars['String']>;
|
||||
/** GitHub account linked to a user */
|
||||
githubUser?: Maybe<GitHubUser>;
|
||||
/** @deprecated No longer supported */
|
||||
githubUsername?: Maybe<Scalars['String']>;
|
||||
id: Scalars['ID'];
|
||||
/** @deprecated No longer supported */
|
||||
industry?: Maybe<Scalars['String']>;
|
||||
isExpoAdmin: Scalars['Boolean'];
|
||||
lastName?: Maybe<Scalars['String']>;
|
||||
/** @deprecated No longer supported */
|
||||
location?: Maybe<Scalars['String']>;
|
||||
notificationSubscriptions: Array<NotificationSubscription>;
|
||||
/** Associated accounts */
|
||||
@@ -5083,6 +5139,7 @@ export type UserActor = {
|
||||
profilePhoto: Scalars['String'];
|
||||
/** Snacks associated with this user's personal account */
|
||||
snacks: Array<Snack>;
|
||||
/** @deprecated No longer supported */
|
||||
twitterUsername?: Maybe<Scalars['String']>;
|
||||
username: Scalars['String'];
|
||||
};
|
||||
@@ -5141,17 +5198,12 @@ export type UserActorQueryByUsernameArgs = {
|
||||
};
|
||||
|
||||
export type UserDataInput = {
|
||||
appetizeCode?: InputMaybe<Scalars['String']>;
|
||||
email?: InputMaybe<Scalars['String']>;
|
||||
firstName?: InputMaybe<Scalars['String']>;
|
||||
fullName?: InputMaybe<Scalars['String']>;
|
||||
githubUsername?: InputMaybe<Scalars['String']>;
|
||||
id?: InputMaybe<Scalars['ID']>;
|
||||
industry?: InputMaybe<Scalars['String']>;
|
||||
lastName?: InputMaybe<Scalars['String']>;
|
||||
location?: InputMaybe<Scalars['String']>;
|
||||
profilePhoto?: InputMaybe<Scalars['String']>;
|
||||
twitterUsername?: InputMaybe<Scalars['String']>;
|
||||
username?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
@@ -6156,7 +6208,7 @@ export type ViewUpdateGroupsOnAppQuery = { __typename?: 'RootQuery', app: { __ty
|
||||
export type CurrentUserQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type CurrentUserQuery = { __typename?: 'RootQuery', meActor?: { __typename: 'Robot', firstName?: string | null, id: string, featureGates: any, isExpoAdmin: boolean, accounts: Array<{ __typename?: 'Account', id: string, name: string, users: Array<{ __typename?: 'UserPermission', role: Role, actor: { __typename?: 'Robot', id: string } | { __typename?: 'SSOUser', id: string } | { __typename?: 'User', id: string } }> }> } | { __typename: 'SSOUser', username: string, id: string, featureGates: any, isExpoAdmin: boolean, accounts: Array<{ __typename?: 'Account', id: string, name: string, users: Array<{ __typename?: 'UserPermission', role: Role, actor: { __typename?: 'Robot', id: string } | { __typename?: 'SSOUser', id: string } | { __typename?: 'User', id: string } }> }> } | { __typename: 'User', username: string, id: string, featureGates: any, isExpoAdmin: boolean, primaryAccount: { __typename?: 'Account', id: string, name: string, users: Array<{ __typename?: 'UserPermission', role: Role, actor: { __typename?: 'Robot', id: string } | { __typename?: 'SSOUser', id: string } | { __typename?: 'User', id: string } }> }, accounts: Array<{ __typename?: 'Account', id: string, name: string, users: Array<{ __typename?: 'UserPermission', role: Role, actor: { __typename?: 'Robot', id: string } | { __typename?: 'SSOUser', id: string } | { __typename?: 'User', id: string } }> }> } | null };
|
||||
export type CurrentUserQuery = { __typename?: 'RootQuery', meActor?: { __typename: 'Robot', firstName?: string | null, id: string, featureGates: any, isExpoAdmin: boolean, accounts: Array<{ __typename?: 'Account', id: string, name: string, users: Array<{ __typename?: 'UserPermission', role: Role, actor: { __typename?: 'Robot', id: string } | { __typename?: 'SSOUser', id: string } | { __typename?: 'User', id: string } }> }> } | { __typename: 'SSOUser', username: string, id: string, featureGates: any, isExpoAdmin: boolean, primaryAccount: { __typename?: 'Account', id: string, name: string, users: Array<{ __typename?: 'UserPermission', role: Role, actor: { __typename?: 'Robot', id: string } | { __typename?: 'SSOUser', id: string } | { __typename?: 'User', id: string } }> }, accounts: Array<{ __typename?: 'Account', id: string, name: string, users: Array<{ __typename?: 'UserPermission', role: Role, actor: { __typename?: 'Robot', id: string } | { __typename?: 'SSOUser', id: string } | { __typename?: 'User', id: string } }> }> } | { __typename: 'User', username: string, id: string, featureGates: any, isExpoAdmin: boolean, primaryAccount: { __typename?: 'Account', id: string, name: string, users: Array<{ __typename?: 'UserPermission', role: Role, actor: { __typename?: 'Robot', id: string } | { __typename?: 'SSOUser', id: string } | { __typename?: 'User', id: string } }> }, accounts: Array<{ __typename?: 'Account', id: string, name: string, users: Array<{ __typename?: 'UserPermission', role: Role, actor: { __typename?: 'Robot', id: string } | { __typename?: 'SSOUser', id: string } | { __typename?: 'User', id: string } }> }> } | null };
|
||||
|
||||
export type WebhooksByAppIdQueryVariables = Exact<{
|
||||
appId: Scalars['String'];
|
||||
|
||||
@@ -106,6 +106,41 @@ export const ChannelQuery = {
|
||||
throw new Error(`Could not find channels on project with id ${appId}`);
|
||||
}
|
||||
|
||||
return updateChannels;
|
||||
},
|
||||
async viewUpdateChannelsPaginatedOnAppAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
{ appId, limit, offset }: ViewUpdateChannelsOnAppQueryVariables
|
||||
): Promise<UpdateChannelObject[]> {
|
||||
const response = await withErrorHandlingAsync(
|
||||
graphqlClient
|
||||
.query<ViewUpdateChannelsOnAppQuery, ViewUpdateChannelsOnAppQueryVariables>(
|
||||
gql`
|
||||
query ViewUpdateChannelsOnApp($appId: String!, $offset: Int!, $limit: Int!) {
|
||||
app {
|
||||
byId(appId: $appId) {
|
||||
id
|
||||
updateChannels(offset: $offset, limit: $limit) {
|
||||
id
|
||||
name
|
||||
branchMapping
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${print(UpdateFragmentNode)}
|
||||
`,
|
||||
{ appId, offset, limit },
|
||||
{ additionalTypenames: ['UpdateChannel', 'UpdateBranch', 'Update'] }
|
||||
)
|
||||
.toPromise()
|
||||
);
|
||||
const { updateChannels } = response.app.byId;
|
||||
|
||||
if (!updateChannels) {
|
||||
throw new Error(`Could not find channels on project with id ${appId}`);
|
||||
}
|
||||
|
||||
return updateChannels;
|
||||
},
|
||||
};
|
||||
@@ -16,7 +16,7 @@ export const UserQuery = {
|
||||
meActor {
|
||||
__typename
|
||||
id
|
||||
... on User {
|
||||
... on UserActor {
|
||||
username
|
||||
primaryAccount {
|
||||
id
|
||||
@@ -26,9 +26,6 @@ export const UserQuery = {
|
||||
... on Robot {
|
||||
firstName
|
||||
}
|
||||
... on SSOUser {
|
||||
username
|
||||
}
|
||||
accounts {
|
||||
id
|
||||
...AccountFragment
|
||||
@@ -41,7 +38,7 @@ export const UserQuery = {
|
||||
`,
|
||||
{},
|
||||
{
|
||||
additionalTypenames: ['User'],
|
||||
additionalTypenames: ['User', 'SSOUser'],
|
||||
}
|
||||
)
|
||||
.toPromise()
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
import { getConfigFilePaths, modifyConfigAsync } from '@expo/config';
|
||||
import JsonFile from '@expo/json-file';
|
||||
import { writeFileSync } from 'fs-extra';
|
||||
|
||||
import { createOrModifyExpoConfigAsync } from '../expoConfig';
|
||||
|
||||
jest.mock('fs-extra');
|
||||
jest.mock('@expo/config');
|
||||
jest.mock('@expo/json-file');
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
describe('expoConfig', () => {
|
||||
describe('createOrModifyExpoConfigAsync', () => {
|
||||
it('should create a new app config file if it does not exist', async () => {
|
||||
jest.mocked(getConfigFilePaths).mockReturnValue({
|
||||
staticConfigPath: null,
|
||||
dynamicConfigPath: null,
|
||||
});
|
||||
|
||||
await createOrModifyExpoConfigAsync('/app', {});
|
||||
expect(writeFileSync).toHaveBeenCalledWith('/app/app.json', '{\n "expo": {}\n}');
|
||||
});
|
||||
|
||||
it('should delegate to modifyConfigAsync if ', async () => {
|
||||
jest.mocked(getConfigFilePaths).mockReturnValue({
|
||||
staticConfigPath: '/app/app.json',
|
||||
dynamicConfigPath: null,
|
||||
});
|
||||
jest.mocked(JsonFile.readAsync).mockResolvedValue({ expo: {} });
|
||||
|
||||
await createOrModifyExpoConfigAsync('/app', {});
|
||||
// modifyConfigAsync is mocked so this shouldn't be called
|
||||
expect(writeFileSync).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should modify an existing config file if it exists', async () => {
|
||||
jest.mocked(getConfigFilePaths).mockReturnValue({
|
||||
staticConfigPath: '/app/app.json',
|
||||
dynamicConfigPath: null,
|
||||
});
|
||||
jest.mocked(JsonFile.readAsync).mockResolvedValue({ expo: {} });
|
||||
|
||||
await createOrModifyExpoConfigAsync('/app', { owner: 'ccheever' });
|
||||
expect(modifyConfigAsync).toHaveBeenCalledWith('/app', { owner: 'ccheever' });
|
||||
});
|
||||
|
||||
it('adds expo key if app.json is missing it', async () => {
|
||||
jest.mocked(getConfigFilePaths).mockReturnValue({
|
||||
staticConfigPath: '/app/app.json',
|
||||
dynamicConfigPath: null,
|
||||
});
|
||||
jest.mocked(JsonFile.readAsync).mockResolvedValue({ name: 'App' });
|
||||
|
||||
await createOrModifyExpoConfigAsync('/app', { owner: 'ccheever' });
|
||||
expect(JsonFile.writeAsync).toHaveBeenCalledWith('/app/app.json', { name: 'App', expo: {} });
|
||||
expect(modifyConfigAsync).toHaveBeenCalledWith('/app', { owner: 'ccheever' });
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -571,7 +571,13 @@ describe(uploadAssetsAsync, () => {
|
||||
|
||||
mockdate.set(0);
|
||||
await expect(
|
||||
uploadAssetsAsync(graphqlClient, assetsForUpdateInfoGroup, testProjectId)
|
||||
uploadAssetsAsync(
|
||||
graphqlClient,
|
||||
assetsForUpdateInfoGroup,
|
||||
testProjectId,
|
||||
{ isCanceledOrFinished: false },
|
||||
() => {}
|
||||
)
|
||||
).resolves.toEqual({
|
||||
assetCount: 6,
|
||||
launchAssetCount: 2,
|
||||
@@ -609,7 +615,15 @@ describe(uploadAssetsAsync, () => {
|
||||
|
||||
mockdate.set(0);
|
||||
await expect(
|
||||
uploadAssetsAsync(graphqlClient, assetsForUpdateInfoGroup, testProjectId)
|
||||
uploadAssetsAsync(
|
||||
graphqlClient,
|
||||
assetsForUpdateInfoGroup,
|
||||
testProjectId,
|
||||
{
|
||||
isCanceledOrFinished: false,
|
||||
},
|
||||
() => {}
|
||||
)
|
||||
).resolves.toEqual({
|
||||
assetCount: 6,
|
||||
launchAssetCount: 2,
|
||||
@@ -645,20 +659,16 @@ describe(uploadAssetsAsync, () => {
|
||||
}, // ios.code
|
||||
];
|
||||
});
|
||||
const updateSpinnerFn = jest.fn((_totalAssets, _missingAssets) => {});
|
||||
const onAssetUploadResultsChangedFn = jest.fn(_assetUploadResults => {});
|
||||
|
||||
mockdate.set(0);
|
||||
await uploadAssetsAsync(
|
||||
graphqlClient,
|
||||
assetsForUpdateInfoGroup,
|
||||
testProjectId,
|
||||
updateSpinnerFn
|
||||
{ isCanceledOrFinished: false },
|
||||
onAssetUploadResultsChangedFn
|
||||
);
|
||||
const calls = updateSpinnerFn.mock.calls;
|
||||
expect(calls).toEqual([
|
||||
[3, 3],
|
||||
[3, 2],
|
||||
[3, 0],
|
||||
]);
|
||||
expect(onAssetUploadResultsChangedFn).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,10 @@
|
||||
import { ExpoConfig, getConfig } from '@expo/config';
|
||||
import { ExpoConfig, getConfig, getConfigFilePaths, modifyConfigAsync } from '@expo/config';
|
||||
import { Env } from '@expo/eas-build-job';
|
||||
import JsonFile from '@expo/json-file';
|
||||
import fs from 'fs-extra';
|
||||
import Joi from 'joi';
|
||||
import nullthrows from 'nullthrows';
|
||||
import path from 'path';
|
||||
|
||||
export type PublicExpoConfig = Omit<
|
||||
ExpoConfig,
|
||||
@@ -19,6 +24,21 @@ interface ExpoConfigOptionsInternal extends ExpoConfigOptions {
|
||||
isPublicConfig?: boolean;
|
||||
}
|
||||
|
||||
export async function createOrModifyExpoConfigAsync(
|
||||
projectDir: string,
|
||||
exp: Partial<ExpoConfig>,
|
||||
readOptions?: { skipSDKVersionRequirement?: boolean }
|
||||
): ReturnType<typeof modifyConfigAsync> {
|
||||
ensureExpoConfigExists(projectDir);
|
||||
await ensureStaticExpoConfigIsValidAsync(projectDir);
|
||||
|
||||
if (readOptions) {
|
||||
return modifyConfigAsync(projectDir, exp, readOptions);
|
||||
} else {
|
||||
return modifyConfigAsync(projectDir, exp);
|
||||
}
|
||||
}
|
||||
|
||||
function getExpoConfigInternal(
|
||||
projectDir: string,
|
||||
opts: ExpoConfigOptionsInternal = {}
|
||||
@@ -33,19 +53,70 @@ function getExpoConfigInternal(
|
||||
skipSDKVersionRequirement: true,
|
||||
...(opts.isPublicConfig ? { isPublicConfig: true } : {}),
|
||||
});
|
||||
|
||||
const { error } = MinimalAppConfigSchema.validate(exp, {
|
||||
allowUnknown: true,
|
||||
abortEarly: true,
|
||||
});
|
||||
if (error) {
|
||||
throw new Error(`Invalid app config.\n${error.message}`);
|
||||
}
|
||||
return exp;
|
||||
} finally {
|
||||
process.env = originalProcessEnv;
|
||||
}
|
||||
}
|
||||
|
||||
const MinimalAppConfigSchema = Joi.object({
|
||||
slug: Joi.string().required(),
|
||||
name: Joi.string().required(),
|
||||
version: Joi.string(),
|
||||
android: Joi.object({
|
||||
versionCode: Joi.number().integer(),
|
||||
}),
|
||||
ios: Joi.object({
|
||||
buildNumber: Joi.string(),
|
||||
}),
|
||||
});
|
||||
|
||||
export function getPrivateExpoConfig(projectDir: string, opts: ExpoConfigOptions = {}): ExpoConfig {
|
||||
ensureExpoConfigExists(projectDir);
|
||||
|
||||
return getExpoConfigInternal(projectDir, { ...opts, isPublicConfig: false });
|
||||
}
|
||||
|
||||
export function ensureExpoConfigExists(projectDir: string): void {
|
||||
const paths = getConfigFilePaths(projectDir);
|
||||
if (!paths?.staticConfigPath && !paths?.dynamicConfigPath) {
|
||||
// eslint-disable-next-line node/no-sync
|
||||
fs.writeFileSync(path.join(projectDir, 'app.json'), JSON.stringify({ expo: {} }, null, 2));
|
||||
}
|
||||
}
|
||||
|
||||
async function ensureStaticExpoConfigIsValidAsync(projectDir: string): Promise<void> {
|
||||
if (isUsingStaticExpoConfig(projectDir)) {
|
||||
const staticConfigPath = nullthrows(getConfigFilePaths(projectDir).staticConfigPath);
|
||||
const staticConfig = await JsonFile.readAsync(staticConfigPath);
|
||||
|
||||
// Add the "expo" key if it doesn't exist on app.json yet, such as in
|
||||
// projects initialized with RNC CLI
|
||||
if (!staticConfig?.expo) {
|
||||
staticConfig.expo = {};
|
||||
await JsonFile.writeAsync(staticConfigPath, staticConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function isUsingStaticExpoConfig(projectDir: string): boolean {
|
||||
const paths = getConfigFilePaths(projectDir);
|
||||
return !!(paths.staticConfigPath?.endsWith('app.json') && !paths.dynamicConfigPath);
|
||||
}
|
||||
|
||||
export function getPublicExpoConfig(
|
||||
projectDir: string,
|
||||
opts: ExpoConfigOptions = {}
|
||||
): PublicExpoConfig {
|
||||
ensureExpoConfigExists(projectDir);
|
||||
|
||||
return getExpoConfigInternal(projectDir, { ...opts, isPublicConfig: true });
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { JSONObject } from '@expo/json-file';
|
||||
import { getPrebuildConfigAsync } from '@expo/prebuild-config';
|
||||
|
||||
import { readPlistAsync } from '../../utils/plist';
|
||||
import { hasIgnoredIosProjectAsync } from '../workflow';
|
||||
|
||||
interface Target {
|
||||
buildConfiguration?: string;
|
||||
@@ -13,6 +14,7 @@ export async function getManagedApplicationTargetEntitlementsAsync(
|
||||
env: Record<string, string>
|
||||
): Promise<JSONObject> {
|
||||
const originalProcessEnv: NodeJS.ProcessEnv = process.env;
|
||||
|
||||
try {
|
||||
process.env = {
|
||||
...process.env,
|
||||
@@ -24,6 +26,7 @@ export async function getManagedApplicationTargetEntitlementsAsync(
|
||||
projectRoot: projectDir,
|
||||
platforms: ['ios'],
|
||||
introspect: true,
|
||||
ignoreExistingNativeFiles: await hasIgnoredIosProjectAsync(projectDir),
|
||||
});
|
||||
return expWithMods.ios?.entitlements || {};
|
||||
} finally {
|
||||
|
||||
@@ -5,6 +5,7 @@ import path from 'path';
|
||||
import resolveFrom from 'resolve-from';
|
||||
import semver from 'semver';
|
||||
|
||||
import { getEASUpdateURL } from '../api';
|
||||
import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
import { AccountFragment, AppPrivacy } from '../graphql/generated';
|
||||
import { AppQuery } from '../graphql/queries/AppQuery';
|
||||
@@ -16,6 +17,8 @@ export function getUsername(exp: ExpoConfig, user: Actor): string | undefined {
|
||||
switch (user.__typename) {
|
||||
case 'User':
|
||||
return user.username;
|
||||
case 'SSOUser':
|
||||
return user.username;
|
||||
case 'Robot':
|
||||
// owner field is necessary to run `expo prebuild`
|
||||
if (!exp.owner) {
|
||||
@@ -25,8 +28,6 @@ export function getUsername(exp: ExpoConfig, user: Actor): string | undefined {
|
||||
}
|
||||
// robot users don't have usernames
|
||||
return undefined;
|
||||
case 'SSOUser':
|
||||
throw new Error('SSO users are not supported yet.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +67,11 @@ export function isExpoUpdatesInstalled(projectDir: string): boolean {
|
||||
return !!(packageJson.dependencies && 'expo-updates' in packageJson.dependencies);
|
||||
}
|
||||
|
||||
export function isExpoUpdatesInstalledAsDevDependency(projectDir: string): boolean {
|
||||
const packageJson = getPackageJson(projectDir);
|
||||
return !!(packageJson.devDependencies && 'expo-updates' in packageJson.devDependencies);
|
||||
}
|
||||
|
||||
export function isExpoUpdatesInstalledOrAvailable(
|
||||
projectDir: string,
|
||||
sdkVersion?: string
|
||||
@@ -78,6 +84,10 @@ export function isExpoUpdatesInstalledOrAvailable(
|
||||
return isExpoUpdatesInstalled(projectDir);
|
||||
}
|
||||
|
||||
export function isUsingEASUpdate(exp: ExpoConfig, projectId: string): boolean {
|
||||
return exp.updates?.url === getEASUpdateURL(projectId);
|
||||
}
|
||||
|
||||
export async function validateAppVersionRuntimePolicySupportAsync(
|
||||
projectDir: string,
|
||||
exp: ExpoConfig
|
||||
|
||||
@@ -385,7 +385,10 @@ export async function uploadAssetsAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
assetsForUpdateInfoGroup: CollectedAssets,
|
||||
projectId: string,
|
||||
updateSpinnerText?: (totalAssets: number, missingAssets: number) => void
|
||||
cancelationToken: { isCanceledOrFinished: boolean },
|
||||
onAssetUploadResultsChanged: (
|
||||
assetUploadResults: { asset: RawAsset & { storageKey: string }; finished: boolean }[]
|
||||
) => void
|
||||
): Promise<AssetUploadResult> {
|
||||
let assets: RawAsset[] = [];
|
||||
let platform: keyof CollectedAssets;
|
||||
@@ -413,13 +416,16 @@ export async function uploadAssetsAsync(
|
||||
}
|
||||
>(assetsWithStorageKey, asset => asset.storageKey);
|
||||
|
||||
const totalAssets = uniqueAssets.length;
|
||||
|
||||
updateSpinnerText?.(totalAssets, totalAssets);
|
||||
onAssetUploadResultsChanged?.(uniqueAssets.map(asset => ({ asset, finished: false })));
|
||||
let missingAssets = await filterOutAssetsThatAlreadyExistAsync(graphqlClient, uniqueAssets);
|
||||
let missingAssetStorageKeys = new Set(missingAssets.map(a => a.storageKey));
|
||||
const uniqueUploadedAssetCount = missingAssets.length;
|
||||
const uniqueUploadedAssetPaths = missingAssets.map(asset => asset.originalPath).filter(truthy);
|
||||
|
||||
if (cancelationToken.isCanceledOrFinished) {
|
||||
throw Error('Canceled upload');
|
||||
}
|
||||
|
||||
const missingAssetChunks = chunk(missingAssets, 100);
|
||||
const specifications: string[] = [];
|
||||
for (const missingAssets of missingAssetChunks) {
|
||||
@@ -430,7 +436,9 @@ export async function uploadAssetsAsync(
|
||||
specifications.push(...chunkSpecifications);
|
||||
}
|
||||
|
||||
updateSpinnerText?.(totalAssets, missingAssets.length);
|
||||
onAssetUploadResultsChanged?.(
|
||||
uniqueAssets.map(asset => ({ asset, finished: !missingAssetStorageKeys.has(asset.storageKey) }))
|
||||
);
|
||||
|
||||
const assetUploadPromiseLimit = promiseLimit(15);
|
||||
|
||||
@@ -438,6 +446,9 @@ export async function uploadAssetsAsync(
|
||||
PublishQuery.getAssetLimitPerUpdateGroupAsync(graphqlClient, projectId),
|
||||
missingAssets.map((missingAsset, i) => {
|
||||
assetUploadPromiseLimit(async () => {
|
||||
if (cancelationToken.isCanceledOrFinished) {
|
||||
throw Error('Canceled upload');
|
||||
}
|
||||
const presignedPost: PresignedPost = JSON.parse(specifications[i]);
|
||||
await uploadWithPresignedPostWithRetryAsync(missingAsset.path, presignedPost);
|
||||
});
|
||||
@@ -446,14 +457,27 @@ export async function uploadAssetsAsync(
|
||||
|
||||
let timeout = 1;
|
||||
while (missingAssets.length > 0) {
|
||||
if (cancelationToken.isCanceledOrFinished) {
|
||||
throw Error('Canceled upload');
|
||||
}
|
||||
|
||||
const timeoutPromise = new Promise(resolve =>
|
||||
setTimeout(resolve, Math.min(timeout * 1000, 5000))
|
||||
); // linear backoff
|
||||
missingAssets = await filterOutAssetsThatAlreadyExistAsync(graphqlClient, missingAssets);
|
||||
missingAssetStorageKeys = new Set(missingAssets.map(a => a.storageKey));
|
||||
await timeoutPromise; // await after filterOutAssetsThatAlreadyExistAsync for easy mocking with jest.runAllTimers
|
||||
timeout += 1;
|
||||
updateSpinnerText?.(totalAssets, missingAssets.length);
|
||||
onAssetUploadResultsChanged?.(
|
||||
uniqueAssets.map(asset => ({
|
||||
asset,
|
||||
finished: !missingAssetStorageKeys.has(asset.storageKey),
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
cancelationToken.isCanceledOrFinished = true;
|
||||
|
||||
return {
|
||||
assetCount: assets.length,
|
||||
launchAssetCount: launchAssets.length,
|
||||
@@ -620,7 +644,9 @@ export async function getRuntimeVersionObjectAsync(
|
||||
Workflow.MANAGED;
|
||||
if (!isManaged) {
|
||||
throw new Error(
|
||||
'Runtime version policies are only supported in the managed workflow. In the bare workflow, runtime version needs to be set manually.'
|
||||
`You're currently using the bare workflow, where runtime version policies are not supported. You must set your runtime version manually. For example, define your runtime version as "1.0.0", not {"policy": "appVersion"} in your app config. ${learnMore(
|
||||
'https://docs.expo.dev/eas-update/runtime-versions'
|
||||
)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,3 +44,15 @@ export async function resolveWorkflowPerPlatformAsync(
|
||||
]);
|
||||
return { android, ios };
|
||||
}
|
||||
|
||||
export async function hasIgnoredIosProjectAsync(projectDir: string): Promise<boolean> {
|
||||
const vcsClient = getVcsClient();
|
||||
const vcsRootPath = path.normalize(await vcsClient.getRootPathAsync());
|
||||
|
||||
try {
|
||||
const pbxProjectPath = IOSConfig.Paths.getPBXProjectPath(projectDir);
|
||||
return await vcsClient.isFileIgnoredAsync(path.relative(vcsRootPath, pbxProjectPath));
|
||||
} finally {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -94,6 +94,7 @@ function mockUpdateChannel({
|
||||
}): UpdateChannel {
|
||||
return {
|
||||
id: 'a2a1fa12-9d6a-433a-a432-49c64ef8439f',
|
||||
app: {} as App,
|
||||
name: channelName ?? 'default-channel-name',
|
||||
createdAt: '2022-12-07T02:24:29.786Z',
|
||||
appId: '123',
|
||||
@@ -109,6 +110,7 @@ function mockUpdateBranches(branchNames: string[]): UpdateBranch[] {
|
||||
return branchNames.map(branchName => ({
|
||||
id: 'f9dc4dbb-663f-4a19-8cf2-a783b484d2db',
|
||||
name: branchName ?? 'default-branch-name',
|
||||
app: {} as App,
|
||||
appId: '123',
|
||||
createdAt: '2022-12-07T02:24:29.786Z',
|
||||
updatedAt: '2022-12-07T02:24:29.786Z',
|
||||
@@ -140,6 +142,7 @@ function mockUpdateBranches(branchNames: string[]): UpdateBranch[] {
|
||||
branch: {
|
||||
id: 'f9dc4dbb-663f-4a19-8cf2-a783b484d2db',
|
||||
name: 'production3',
|
||||
app: {} as App,
|
||||
appId: '123',
|
||||
createdAt: '2022-12-07T02:24:29.786Z',
|
||||
updatedAt: '2022-12-07T02:24:29.786Z',
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import { ExpoConfig } from '@expo/config';
|
||||
import { AndroidConfig, AndroidManifest } from '@expo/config-plugins';
|
||||
import { AndroidConfig, AndroidManifest, XML } from '@expo/config-plugins';
|
||||
|
||||
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
import { RequestedPlatform } from '../../platform';
|
||||
import { getOwnerAccountForProjectIdAsync } from '../../project/projectUtils';
|
||||
import { ensureValidVersions } from '../utils';
|
||||
|
||||
/**
|
||||
* Synchronize updates configuration to native files. This needs to do essentially the same thing as `withUpdates`
|
||||
*/
|
||||
export async function syncUpdatesConfigurationAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
projectDir: string,
|
||||
@@ -15,9 +18,9 @@ export async function syncUpdatesConfigurationAsync(
|
||||
ensureValidVersions(exp, RequestedPlatform.Android);
|
||||
const accountName = (await getOwnerAccountForProjectIdAsync(graphqlClient, projectId)).name;
|
||||
|
||||
// sync AndroidManifest.xml
|
||||
const androidManifestPath = await AndroidConfig.Paths.getAndroidManifestAsync(projectDir);
|
||||
const androidManifest = await getAndroidManifestAsync(projectDir);
|
||||
|
||||
const updatedAndroidManifest = AndroidConfig.Updates.setUpdatesConfig(
|
||||
projectDir,
|
||||
exp,
|
||||
@@ -28,6 +31,17 @@ export async function syncUpdatesConfigurationAsync(
|
||||
androidManifestPath,
|
||||
updatedAndroidManifest
|
||||
);
|
||||
|
||||
// sync strings.xml
|
||||
const stringsJSONPath = await AndroidConfig.Strings.getProjectStringsXMLPathAsync(projectDir);
|
||||
const stringsResourceXML = await AndroidConfig.Resources.readResourcesXMLAsync({
|
||||
path: stringsJSONPath,
|
||||
});
|
||||
const updatedStringsResourceXML = AndroidConfig.Updates.applyRuntimeVersionFromConfig(
|
||||
exp,
|
||||
stringsResourceXML
|
||||
);
|
||||
await XML.writeXMLAsync({ path: stringsJSONPath, xml: updatedStringsResourceXML });
|
||||
}
|
||||
|
||||
export async function readReleaseChannelSafelyAsync(projectDir: string): Promise<string | null> {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { modifyConfigAsync } from '@expo/config';
|
||||
import { ExpoConfig } from '@expo/config-types';
|
||||
import { Platform, Workflow } from '@expo/eas-build-job';
|
||||
import { EasJsonAccessor } from '@expo/eas-json';
|
||||
@@ -10,11 +9,14 @@ import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGr
|
||||
import { AppPlatform } from '../graphql/generated';
|
||||
import Log, { learnMore } from '../log';
|
||||
import { RequestedPlatform, appPlatformDisplayNames } from '../platform';
|
||||
import { createOrModifyExpoConfigAsync, isUsingStaticExpoConfig } from '../project/expoConfig';
|
||||
import {
|
||||
installExpoUpdatesAsync,
|
||||
isExpoUpdatesInstalledAsDevDependency,
|
||||
isExpoUpdatesInstalledOrAvailable,
|
||||
} from '../project/projectUtils';
|
||||
import { resolveWorkflowPerPlatformAsync } from '../project/workflow';
|
||||
import { confirmAsync } from '../prompts';
|
||||
import { syncUpdatesConfigurationAsync as syncAndroidUpdatesConfigurationAsync } from './android/UpdatesModule';
|
||||
import { syncUpdatesConfigurationAsync as syncIosUpdatesConfigurationAsync } from './ios/UpdatesModule';
|
||||
|
||||
@@ -128,7 +130,7 @@ async function ensureEASUpdatesIsConfiguredInExpoConfigAsync({
|
||||
}
|
||||
|
||||
const mergedExp = mergeExpoConfig(exp, modifyConfig);
|
||||
const result = await modifyConfigAsync(projectDir, mergedExp);
|
||||
const result = await createOrModifyExpoConfigAsync(projectDir, mergedExp);
|
||||
|
||||
switch (result.type) {
|
||||
case 'success':
|
||||
@@ -153,6 +155,16 @@ async function ensureEASUpdatesIsConfiguredInExpoConfigAsync({
|
||||
}
|
||||
}
|
||||
|
||||
function serializeRuntimeVersionToString(
|
||||
runtimeVersion: NonNullable<ExpoConfig['runtimeVersion']>
|
||||
): string {
|
||||
if (typeof runtimeVersion === 'object') {
|
||||
return JSON.stringify(runtimeVersion);
|
||||
} else {
|
||||
return runtimeVersion;
|
||||
}
|
||||
}
|
||||
|
||||
function logEasUpdatesAutoConfig({
|
||||
modifyConfig,
|
||||
exp,
|
||||
@@ -168,22 +180,29 @@ function logEasUpdatesAutoConfig({
|
||||
);
|
||||
}
|
||||
|
||||
if (modifyConfig.android?.runtimeVersion ?? modifyConfig.runtimeVersion) {
|
||||
const androidRuntime = modifyConfig.android?.runtimeVersion ?? modifyConfig.runtimeVersion;
|
||||
const iosRuntime = modifyConfig.ios?.runtimeVersion ?? modifyConfig.runtimeVersion;
|
||||
if (androidRuntime && iosRuntime && androidRuntime === iosRuntime) {
|
||||
Log.withTick(
|
||||
`Configured runtimeVersion for ${
|
||||
appPlatformDisplayNames[AppPlatform.Android]
|
||||
} with "${JSON.stringify(
|
||||
modifyConfig.android?.runtimeVersion ?? modifyConfig.runtimeVersion
|
||||
)}"`
|
||||
);
|
||||
}
|
||||
|
||||
if (modifyConfig.ios?.runtimeVersion ?? modifyConfig.runtimeVersion) {
|
||||
Log.withTick(
|
||||
`Configured runtimeVersion for ${
|
||||
`Configured runtimeVersion for ${appPlatformDisplayNames[AppPlatform.Android]} and ${
|
||||
appPlatformDisplayNames[AppPlatform.Ios]
|
||||
} with "${JSON.stringify(modifyConfig.ios?.runtimeVersion ?? modifyConfig.runtimeVersion)}"`
|
||||
} with "${serializeRuntimeVersionToString(androidRuntime)}"`
|
||||
);
|
||||
} else {
|
||||
if (androidRuntime) {
|
||||
Log.withTick(
|
||||
`Configured runtimeVersion for ${
|
||||
appPlatformDisplayNames[AppPlatform.Android]
|
||||
} with "${serializeRuntimeVersionToString(androidRuntime)}"`
|
||||
);
|
||||
}
|
||||
if (iosRuntime) {
|
||||
Log.withTick(
|
||||
`Configured runtimeVersion for ${
|
||||
appPlatformDisplayNames[AppPlatform.Ios]
|
||||
} with "${serializeRuntimeVersionToString(iosRuntime)}"`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,9 +284,7 @@ export async function ensureEASUpdateIsConfiguredInEasJsonAsync(projectDir: stri
|
||||
Log.warn(
|
||||
`EAS Build is not configured. If you'd like to use EAS Build with EAS Update, run ${chalk.bold(
|
||||
'eas build:configure'
|
||||
)}, then re-run ${chalk.bold('eas update:configure')} to configure ${chalk.bold(
|
||||
'eas.json'
|
||||
)} with EAS Update.`
|
||||
)}.`
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -318,7 +335,8 @@ export async function ensureEASUpdateIsConfiguredInEasJsonAsync(projectDir: stri
|
||||
/**
|
||||
* Make sure EAS Update is fully configured in the current project.
|
||||
* This goes over a checklist and performs the following checks or changes:
|
||||
* - Enure the `expo-updates` package is currently installed.
|
||||
* - Ensure `updates.useClassicUpdates` (SDK 49) is not set in the app config
|
||||
* - Ensure the `expo-updates` package is currently installed.
|
||||
* - Ensure `app.json` is configured for EAS Updates
|
||||
* - Sets `runtimeVersion` if not set
|
||||
* - Sets `updates.url` if not set
|
||||
@@ -327,7 +345,7 @@ export async function ensureEASUpdateIsConfiguredInEasJsonAsync(projectDir: stri
|
||||
export async function ensureEASUpdateIsConfiguredAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
{
|
||||
exp: expWithoutUpdates,
|
||||
exp: expMaybeWithoutUpdates,
|
||||
projectId,
|
||||
projectDir,
|
||||
platform,
|
||||
@@ -338,13 +356,26 @@ export async function ensureEASUpdateIsConfiguredAsync(
|
||||
platform: RequestedPlatform | null;
|
||||
}
|
||||
): Promise<void> {
|
||||
// EAS Update and SDK 49's "useClassicUpdates" option are mutually exclusive
|
||||
if (expMaybeWithoutUpdates.updates?.useClassicUpdates) {
|
||||
expMaybeWithoutUpdates = await ensureUseClassicUpdatesIsRemovedAsync({
|
||||
exp: expMaybeWithoutUpdates,
|
||||
projectDir,
|
||||
});
|
||||
}
|
||||
|
||||
const hasExpoUpdates = isExpoUpdatesInstalledOrAvailable(
|
||||
projectDir,
|
||||
expWithoutUpdates.sdkVersion
|
||||
expMaybeWithoutUpdates.sdkVersion
|
||||
);
|
||||
if (!hasExpoUpdates) {
|
||||
const hasExpoUpdatesInDevDependencies = isExpoUpdatesInstalledAsDevDependency(projectDir);
|
||||
if (!hasExpoUpdates && !hasExpoUpdatesInDevDependencies) {
|
||||
await installExpoUpdatesAsync(projectDir, { silent: false });
|
||||
Log.withTick('Installed expo updates');
|
||||
Log.withTick('Installed expo-updates');
|
||||
} else if (hasExpoUpdatesInDevDependencies) {
|
||||
Log.warn(
|
||||
`The "expo-updates" package is installed as a dev dependency. This is not recommended. Move "expo-updates" to your main dependencies.`
|
||||
);
|
||||
}
|
||||
|
||||
// Bail out if using a platform that doesn't require runtime versions
|
||||
@@ -356,7 +387,7 @@ export async function ensureEASUpdateIsConfiguredAsync(
|
||||
const workflows = await resolveWorkflowPerPlatformAsync(projectDir);
|
||||
const { projectChanged, exp: expWithUpdates } =
|
||||
await ensureEASUpdatesIsConfiguredInExpoConfigAsync({
|
||||
exp: expWithoutUpdates,
|
||||
exp: expMaybeWithoutUpdates,
|
||||
projectDir,
|
||||
projectId,
|
||||
platform,
|
||||
@@ -381,3 +412,49 @@ export async function ensureEASUpdateIsConfiguredAsync(
|
||||
Log.newLine();
|
||||
}
|
||||
}
|
||||
|
||||
export async function ensureUseClassicUpdatesIsRemovedAsync({
|
||||
exp: expMaybeWithoutUpdates,
|
||||
projectDir,
|
||||
}: {
|
||||
exp: ExpoConfig;
|
||||
projectDir: string;
|
||||
}): Promise<ExpoConfig> {
|
||||
if (!isUsingStaticExpoConfig(projectDir)) {
|
||||
throw new Error(
|
||||
`Your app config sets "updates.useClassicUpdates" but EAS Update does not support classic updates. Remove "useClassicUpdates" from your app config and run this command again.`
|
||||
);
|
||||
}
|
||||
|
||||
const shouldEditConfig = await confirmAsync({
|
||||
message: `Your app config sets "updates.useClassicUpdates" but EAS Update does not support classic updates. Remove "updates.useClassicUpdates" from your app config?`,
|
||||
});
|
||||
if (!shouldEditConfig) {
|
||||
throw new Error(
|
||||
`Manually remove "updates.useClassicUpdates" from your app config and run this command again.`
|
||||
);
|
||||
}
|
||||
|
||||
const editedExpoConfig = mergeExpoConfig(expMaybeWithoutUpdates, {
|
||||
updates: { useClassicUpdates: undefined },
|
||||
}) as ExpoConfig;
|
||||
const result = await createOrModifyExpoConfigAsync(projectDir, editedExpoConfig);
|
||||
|
||||
switch (result.type) {
|
||||
case 'success':
|
||||
Log.withTick(`Removed "updates.useClassicUpdates"`);
|
||||
expMaybeWithoutUpdates = editedExpoConfig;
|
||||
break;
|
||||
|
||||
case 'warn':
|
||||
case 'fail':
|
||||
throw new Error(result.message);
|
||||
|
||||
default:
|
||||
throw new Error(
|
||||
`Unexpected result type "${result.type}" received when modifying the project config.`
|
||||
);
|
||||
}
|
||||
|
||||
return editedExpoConfig;
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import { UserQuery } from '../graphql/queries/UserQuery';
|
||||
import Log, { learnMore } from '../log';
|
||||
import { promptAsync, selectAsync } from '../prompts';
|
||||
import { getStateJsonPath } from '../utils/paths';
|
||||
import { fetchSessionSecretAndSsoUserAsync } from './fetchSessionSecretAndSsoUser';
|
||||
import { fetchSessionSecretAndUserAsync } from './fetchSessionSecretAndUser';
|
||||
|
||||
type UserSettingsData = {
|
||||
@@ -25,7 +26,7 @@ type SessionData = {
|
||||
// These fields are potentially used by Expo CLI.
|
||||
userId: string;
|
||||
username: string;
|
||||
currentConnection: 'Username-Password-Authentication';
|
||||
currentConnection: 'Username-Password-Authentication' | 'Browser-Flow-Authentication';
|
||||
};
|
||||
|
||||
export enum UserSecondFactorDeviceMethod {
|
||||
@@ -147,6 +148,7 @@ export default class SessionManager {
|
||||
public async showLoginPromptAsync({
|
||||
nonInteractive = false,
|
||||
printNewLine = false,
|
||||
sso = false,
|
||||
} = {}): Promise<void> {
|
||||
if (nonInteractive) {
|
||||
Errors.error(
|
||||
@@ -162,7 +164,16 @@ export default class SessionManager {
|
||||
Log.newLine();
|
||||
}
|
||||
|
||||
Log.log('Log in to EAS');
|
||||
if (sso) {
|
||||
await this.ssoLoginAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
Log.log(
|
||||
`Log in to EAS with email or username (exit and run ${chalk.bold(
|
||||
'eas login'
|
||||
)} for other options)`
|
||||
);
|
||||
|
||||
const { username, password } = await promptAsync([
|
||||
{
|
||||
@@ -194,6 +205,16 @@ export default class SessionManager {
|
||||
}
|
||||
}
|
||||
|
||||
private async ssoLoginAsync(): Promise<void> {
|
||||
const { sessionSecret, id, username } = await fetchSessionSecretAndSsoUserAsync();
|
||||
await this.setSessionAsync({
|
||||
sessionSecret,
|
||||
userId: id,
|
||||
username,
|
||||
currentConnection: 'Browser-Flow-Authentication',
|
||||
});
|
||||
}
|
||||
|
||||
private async loginAsync(input: {
|
||||
username: string;
|
||||
password: string;
|
||||
|
||||
@@ -3,7 +3,7 @@ import { CurrentUserQuery, Robot, SsoUser, User } from '../graphql/generated';
|
||||
export type Actor = NonNullable<CurrentUserQuery['meActor']>;
|
||||
|
||||
/**
|
||||
* Resolve the name of the actor, either normal user or robot user.
|
||||
* Resolve the name of the actor, either normal user, sso user or robot user.
|
||||
* This should be used whenever the "current user" needs to be displayed.
|
||||
* The display name CANNOT be used as project owner.
|
||||
*/
|
||||
|
||||
@@ -9,6 +9,7 @@ import Log from '../../log';
|
||||
import { promptAsync, selectAsync } from '../../prompts';
|
||||
import { getStateJsonPath } from '../../utils/paths';
|
||||
import SessionManager, { UserSecondFactorDeviceMethod } from '../SessionManager';
|
||||
import { fetchSessionSecretAndSsoUserAsync } from '../fetchSessionSecretAndSsoUser';
|
||||
import { fetchSessionSecretAndUserAsync } from '../fetchSessionSecretAndUser';
|
||||
|
||||
jest.mock('../../prompts');
|
||||
@@ -24,6 +25,7 @@ jest.mock('../../graphql/queries/UserQuery', () => ({
|
||||
},
|
||||
}));
|
||||
jest.mock('../fetchSessionSecretAndUser');
|
||||
jest.mock('../fetchSessionSecretAndSsoUser');
|
||||
jest.mock('../../api');
|
||||
|
||||
const authStub: any = {
|
||||
@@ -154,6 +156,29 @@ describe(SessionManager, () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('ssoLoginAsync', () => {
|
||||
it('saves user data to ~/.expo/state.json', async () => {
|
||||
jest.mocked(fetchSessionSecretAndSsoUserAsync).mockResolvedValue({
|
||||
sessionSecret: 'SESSION_SECRET',
|
||||
id: 'USER_ID',
|
||||
username: 'USERNAME',
|
||||
});
|
||||
const sessionManager = new SessionManager(analytics);
|
||||
await sessionManager['ssoLoginAsync']();
|
||||
expect(await fs.readFile(getStateJsonPath(), 'utf8')).toMatchInlineSnapshot(`
|
||||
"{
|
||||
"auth": {
|
||||
"sessionSecret": "SESSION_SECRET",
|
||||
"userId": "USER_ID",
|
||||
"username": "USERNAME",
|
||||
"currentConnection": "Browser-Flow-Authentication"
|
||||
}
|
||||
}
|
||||
"
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('logoutAsync', () => {
|
||||
it('removes the session secret', async () => {
|
||||
jest.mocked(fetchSessionSecretAndUserAsync).mockResolvedValue({
|
||||
@@ -230,6 +255,45 @@ describe(SessionManager, () => {
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('calls regular login if the sso flag is false', async () => {
|
||||
jest
|
||||
.mocked(promptAsync)
|
||||
.mockImplementationOnce(async () => ({ username: 'USERNAME', password: 'PASSWORD' }))
|
||||
.mockImplementation(() => {
|
||||
throw new Error("shouldn't happen");
|
||||
});
|
||||
|
||||
const sessionManager = new SessionManager(analytics);
|
||||
|
||||
// Regular login
|
||||
await sessionManager.showLoginPromptAsync({ sso: false });
|
||||
expect(fetchSessionSecretAndUserAsync).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('calls regular login if the sso flag is undefined', async () => {
|
||||
jest
|
||||
.mocked(promptAsync)
|
||||
.mockImplementationOnce(async () => ({ username: 'USERNAME', password: 'PASSWORD' }))
|
||||
.mockImplementation(() => {
|
||||
throw new Error("shouldn't happen");
|
||||
});
|
||||
|
||||
const sessionManager = new SessionManager(analytics);
|
||||
|
||||
// Regular login
|
||||
await sessionManager.showLoginPromptAsync({ sso: undefined });
|
||||
expect(fetchSessionSecretAndUserAsync).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('calls SSO login if the sso flag is true', async () => {
|
||||
const sessionManager = new SessionManager(analytics);
|
||||
|
||||
// SSO login
|
||||
await sessionManager.showLoginPromptAsync({ sso: true });
|
||||
expect(promptAsync).not.toHaveBeenCalled();
|
||||
expect(fetchSessionSecretAndSsoUserAsync).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('retryUsernamePasswordAuthWithOTPAsync', () => {
|
||||
|
||||
@@ -21,6 +21,26 @@ const userStub: Actor = {
|
||||
featureGates: {},
|
||||
};
|
||||
|
||||
const ssoUserStub: Actor = {
|
||||
__typename: 'SSOUser',
|
||||
id: 'ssoUserId',
|
||||
username: 'ssoUsername',
|
||||
primaryAccount: {
|
||||
id: 'account_id_888',
|
||||
name: 'ssoUsername',
|
||||
users: [{ role: Role.Owner, actor: { id: 'ssoUserId' } }],
|
||||
},
|
||||
accounts: [
|
||||
{
|
||||
id: 'account_id_888',
|
||||
name: 'ssoUsername',
|
||||
users: [{ role: Role.Owner, actor: { id: 'ssoUserId' } }],
|
||||
},
|
||||
],
|
||||
isExpoAdmin: false,
|
||||
featureGates: {},
|
||||
};
|
||||
|
||||
const robotStub: Actor = {
|
||||
__typename: 'Robot',
|
||||
id: 'userId',
|
||||
@@ -35,10 +55,14 @@ describe('getActorDisplayName', () => {
|
||||
expect(getActorDisplayName()).toBe('unknown');
|
||||
});
|
||||
|
||||
it('returns username for user actors', () => {
|
||||
it('returns username for regular user actors', () => {
|
||||
expect(getActorDisplayName(userStub)).toBe(userStub.username);
|
||||
});
|
||||
|
||||
it('returns username for SSO user actors', () => {
|
||||
expect(getActorDisplayName(ssoUserStub)).toBe(`${ssoUserStub.username}`);
|
||||
});
|
||||
|
||||
it('returns firstName with robot prefix for robot actors', () => {
|
||||
expect(getActorDisplayName(robotStub)).toBe(`${robotStub.firstName} (robot)`);
|
||||
});
|
||||
|
||||
@@ -2,7 +2,7 @@ import { AccountFragment } from '../graphql/generated';
|
||||
import { Actor } from './User';
|
||||
|
||||
export function ensureActorHasPrimaryAccount(user: Actor): AccountFragment {
|
||||
if (user.__typename === 'User') {
|
||||
if (user.__typename === 'User' || user.__typename === 'SSOUser') {
|
||||
return user.primaryAccount;
|
||||
}
|
||||
throw new Error('This action is not supported for robot users.');
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
import assert from 'assert';
|
||||
import openBrowserAsync from 'better-opn';
|
||||
import http from 'http';
|
||||
import { Socket } from 'node:net';
|
||||
import querystring from 'querystring';
|
||||
|
||||
import Log from '../log';
|
||||
|
||||
const successBody = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Expo SSO Login</title>
|
||||
<meta charset="utf-8">
|
||||
<style type="text/css">
|
||||
html {
|
||||
margin: 0;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #fff;
|
||||
font-family: Tahoma,Verdana;
|
||||
font-size: 16px;
|
||||
color: #000;
|
||||
max-width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: .5rem;
|
||||
margin: 1em;
|
||||
overflow-wrap: break-word
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
SSO login complete. You may now close this tab and return to the command prompt.
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
export async function getSessionUsingBrowserAuthFlowAsync({
|
||||
expoWebsiteUrl,
|
||||
}: {
|
||||
expoWebsiteUrl: string;
|
||||
}): Promise<string> {
|
||||
const scheme = 'http';
|
||||
const hostname = 'localhost';
|
||||
const path = '/auth/callback';
|
||||
|
||||
const buildExpoSsoLoginUrl = (port: number): string => {
|
||||
const data = {
|
||||
app_redirect_uri: `${scheme}://${hostname}:${port}${path}`,
|
||||
};
|
||||
const params = querystring.stringify(data);
|
||||
return `${expoWebsiteUrl}/sso-login?${params}`;
|
||||
};
|
||||
|
||||
// Start server and begin auth flow
|
||||
const executeAuthFlow = (): Promise<string> => {
|
||||
return new Promise<string>(async (resolve, reject) => {
|
||||
const connections = new Set<Socket>();
|
||||
|
||||
const server = http.createServer(
|
||||
(request: http.IncomingMessage, response: http.ServerResponse) => {
|
||||
try {
|
||||
if (!(request.method === 'GET' && request.url?.includes('/auth/callback'))) {
|
||||
throw new Error('Unexpected SSO login response.');
|
||||
}
|
||||
const url = new URL(request.url, `http:${request.headers.host}`);
|
||||
const sessionSecret = url.searchParams.get('session_secret');
|
||||
|
||||
if (!sessionSecret) {
|
||||
throw new Error('Request missing session_secret search parameter.');
|
||||
}
|
||||
resolve(sessionSecret);
|
||||
response.writeHead(200, { 'Content-Type': 'text/html' });
|
||||
response.write(successBody);
|
||||
response.end();
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
} finally {
|
||||
server.close();
|
||||
// Ensure that the server shuts down
|
||||
for (const connection of connections) {
|
||||
connection.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
server.listen(0, hostname, () => {
|
||||
Log.log('Waiting for browser login...');
|
||||
|
||||
const address = server.address();
|
||||
assert(
|
||||
address !== null && typeof address === 'object',
|
||||
'Server address and port should be set after listening has begun'
|
||||
);
|
||||
const port = address.port;
|
||||
const authorizeUrl = buildExpoSsoLoginUrl(port);
|
||||
openBrowserAsync(authorizeUrl);
|
||||
});
|
||||
|
||||
server.on('connection', connection => {
|
||||
connections.add(connection);
|
||||
|
||||
connection.on('close', () => {
|
||||
connections.delete(connection);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return await executeAuthFlow();
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { getExpoWebsiteBaseUrl } from '../api';
|
||||
import { getSessionUsingBrowserAuthFlowAsync } from './expoSsoLauncher';
|
||||
import { fetchUserAsync } from './fetchUser';
|
||||
|
||||
export async function fetchSessionSecretAndSsoUserAsync(): Promise<{
|
||||
sessionSecret: string;
|
||||
id: string;
|
||||
username: string;
|
||||
}> {
|
||||
const sessionSecret = await getSessionUsingBrowserAuthFlowAsync({
|
||||
expoWebsiteUrl: getExpoWebsiteBaseUrl(),
|
||||
});
|
||||
|
||||
const userData = await fetchUserAsync({ sessionSecret });
|
||||
|
||||
return {
|
||||
sessionSecret,
|
||||
id: userData.id,
|
||||
username: userData.username,
|
||||
};
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
import { ApiV2Client } from '../api';
|
||||
import { createGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
import { fetchUserAsync } from './fetchUser';
|
||||
|
||||
export async function fetchSessionSecretAndUserAsync({
|
||||
username,
|
||||
@@ -21,32 +19,10 @@ export async function fetchSessionSecretAndUserAsync({
|
||||
body: { username, password, otp },
|
||||
});
|
||||
const { sessionSecret } = body.data;
|
||||
const graphqlClient = createGraphqlClient({ accessToken: null, sessionSecret: null });
|
||||
const result = await graphqlClient
|
||||
.query(
|
||||
gql`
|
||||
query UserQuery {
|
||||
viewer {
|
||||
id
|
||||
username
|
||||
}
|
||||
}
|
||||
`,
|
||||
{},
|
||||
{
|
||||
fetchOptions: {
|
||||
headers: {
|
||||
'expo-session': sessionSecret,
|
||||
},
|
||||
},
|
||||
additionalTypenames: [] /* UserQuery has immutable fields */,
|
||||
}
|
||||
)
|
||||
.toPromise();
|
||||
const { data } = result;
|
||||
const userData = await fetchUserAsync({ sessionSecret });
|
||||
return {
|
||||
sessionSecret,
|
||||
id: data.viewer.id,
|
||||
username: data.viewer.username,
|
||||
id: userData.id,
|
||||
username: userData.username,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
import { createGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
|
||||
export async function fetchUserAsync({
|
||||
sessionSecret,
|
||||
}: {
|
||||
sessionSecret: string;
|
||||
}): Promise<{ id: string; username: string }> {
|
||||
const graphqlClient = createGraphqlClient({ accessToken: null, sessionSecret });
|
||||
const result = await graphqlClient
|
||||
.query(
|
||||
gql`
|
||||
query UserQuery {
|
||||
meUserActor {
|
||||
id
|
||||
username
|
||||
}
|
||||
}
|
||||
`,
|
||||
{},
|
||||
{
|
||||
additionalTypenames: [] /* UserQuery has immutable fields */,
|
||||
}
|
||||
)
|
||||
.toPromise();
|
||||
|
||||
const { data } = result;
|
||||
return {
|
||||
id: data.meUserActor.id,
|
||||
username: data.meUserActor.username,
|
||||
};
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import { boolish } from 'getenv';
|
||||
import resolveFrom, { silent as silentResolveFrom } from 'resolve-from';
|
||||
import semver from 'semver';
|
||||
|
||||
import Log from '../log';
|
||||
import Log, { link } from '../log';
|
||||
import { memoize } from './expodash/memoize';
|
||||
|
||||
// Aggressively returns `true` (UNVERSIONED, invalid SDK version format) to push users towards the versioned CLI.
|
||||
@@ -63,8 +63,21 @@ export async function expoCommandAsync(
|
||||
args: string[],
|
||||
{ silent = false }: { silent?: boolean } = {}
|
||||
): Promise<void> {
|
||||
const expoCliPath =
|
||||
silentResolveFrom(projectDir, 'expo/bin/cli') ?? resolveFrom(projectDir, 'expo/bin/cli.js');
|
||||
let expoCliPath;
|
||||
try {
|
||||
expoCliPath =
|
||||
silentResolveFrom(projectDir, 'expo/bin/cli') ?? resolveFrom(projectDir, 'expo/bin/cli.js');
|
||||
} catch (e: any) {
|
||||
if (e.code === 'MODULE_NOT_FOUND') {
|
||||
throw new Error(
|
||||
`The \`expo\` package was not found. Follow the installation directions at ${link(
|
||||
'https://docs.expo.dev/bare/installing-expo-modules/'
|
||||
)}`
|
||||
);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
const spawnPromise = spawnAsync(expoCliPath, args, {
|
||||
stdio: ['inherit', 'pipe', 'pipe'], // inherit stdin so user can install a missing expo-cli from inside this command
|
||||
});
|
||||
|
||||
@@ -53,7 +53,7 @@ export default class GitClient extends Client {
|
||||
}
|
||||
|
||||
Log.warn("It looks like you haven't initialized the git repository yet.");
|
||||
Log.warn('EAS Build requires you to use a git repository for your project.');
|
||||
Log.warn('EAS requires you to use a git repository for your project.');
|
||||
|
||||
const cwd = process.cwd();
|
||||
const repoRoot = PackageManagerUtils.findWorkspaceRoot(cwd) ?? cwd;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@expo/eas-json",
|
||||
"description": "A library for interacting with eas.json",
|
||||
"version": "3.13.0",
|
||||
"version": "3.15.1",
|
||||
"author": "Expo <[email protected]>",
|
||||
"bugs": "https://github.com/expo/eas-cli/issues",
|
||||
"dependencies": {
|
||||
|
||||
@@ -334,6 +334,7 @@
|
||||
"enum": [
|
||||
"default",
|
||||
"latest",
|
||||
"macos-ventura-13.4-xcode-14.3.1",
|
||||
"macos-ventura-13.3-xcode-14.3",
|
||||
"macos-monterey-12.6-xcode-14.2",
|
||||
"macos-monterey-12.6-xcode-14.1",
|
||||
@@ -345,8 +346,9 @@
|
||||
"macos-big-sur-11.4-xcode-12.5"
|
||||
],
|
||||
"markdownEnumDescriptions": [
|
||||
"`macos-monterey-12.6-xcode-14.2` for Apple silicon builders, `macos-monterey-12.6-xcode-14.1` for Intel builders",
|
||||
"`macos-ventura-13.3-xcode-14.3` for Apple silicon builders, `macos-monterey-12.6-xcode-14.2` for Intel builders",
|
||||
"`macos-ventura-13.3-xcode-14.3` for Apple silicon builders, `macos-monterey-12.6-xcode-14.1` for Intel builders",
|
||||
"`macos-ventura-13.4-xcode-14.3.1` for Apple silicon builders, `macos-monterey-12.6-xcode-14.2` for Intel builders",
|
||||
"only available for Apple silicon builders",
|
||||
"only available for Apple silicon builders"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@0no-co/graphql.web@^1.0.1":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@0no-co/graphql.web/-/graphql.web-1.0.4.tgz#9606eb651955499525d068ce0ad8bea596286ce2"
|
||||
integrity sha512-W3ezhHGfO0MS1PtGloaTpg0PbaT8aZSmmaerL7idtU5F7oCI+uu25k+MsMS31BVFlp4aMkHSrNRxiD72IlK8TA==
|
||||
|
||||
"@ampproject/remapping@^2.1.0":
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d"
|
||||
@@ -1324,10 +1329,10 @@
|
||||
minimatch "^3.1.2"
|
||||
strip-json-comments "^3.1.1"
|
||||
|
||||
"@expo/apple-utils@1.2.0":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@expo/apple-utils/-/apple-utils-1.2.0.tgz#227d118089a4645b076162f3b513dfc68763ca21"
|
||||
integrity sha512-MotvQqu8CNVlnl9nsISobXDjEzSMfT7U5Zk+1rhOFoJhaZhlEkARxumUFUgH6cYnK7J2mMd3YxM+G769arkEKQ==
|
||||
"@expo/apple-utils@1.3.1":
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@expo/apple-utils/-/apple-utils-1.3.1.tgz#99a2627c167af138722af9806a09a35f87115a39"
|
||||
integrity sha512-ADPHXIpTWlt9tIg9yhwyuxQ6UMICWMfHgoCE1v8zzyYsa3BcKvawgkAGApYNxp2IYUKiNMqRYzViEKgq+Svk3w==
|
||||
|
||||
"@expo/bunyan@^4.0.0":
|
||||
version "4.0.0"
|
||||
@@ -1347,12 +1352,12 @@
|
||||
node-forge "^1.2.1"
|
||||
nullthrows "^1.1.1"
|
||||
|
||||
"@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==
|
||||
"@expo/config-plugins@7.2.4", "@expo/config-plugins@~7.2.0":
|
||||
version "7.2.4"
|
||||
resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-7.2.4.tgz#c8d354348b746e53d70224f0bf7b87994f7c2936"
|
||||
integrity sha512-TItGwmKH1GDjA5GlMkXo1A8pqeqppSK40aSVRVQaGZraUj+nuvtpWxNgEWZxWFumiatP2ocWwyWVjfmH+rJY6g==
|
||||
dependencies:
|
||||
"@expo/config-types" "^48.0.0"
|
||||
"@expo/config-types" "^49.0.0-alpha.1"
|
||||
"@expo/json-file" "~8.2.37"
|
||||
"@expo/plist" "^0.0.20"
|
||||
"@expo/sdk-runtime-versions" "^1.0.0"
|
||||
@@ -1363,56 +1368,30 @@
|
||||
getenv "^1.0.0"
|
||||
glob "7.1.6"
|
||||
resolve-from "^5.0.0"
|
||||
semver "^7.3.5"
|
||||
semver "^7.5.3"
|
||||
slash "^3.0.0"
|
||||
xcode "^3.0.1"
|
||||
xml2js "0.4.23"
|
||||
xml2js "0.6.0"
|
||||
|
||||
"@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==
|
||||
dependencies:
|
||||
"@expo/config-types" "^47.0.0"
|
||||
"@expo/json-file" "8.2.36"
|
||||
"@expo/plist" "0.0.18"
|
||||
"@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-[email protected]", "@expo/config-types@^49.0.0-alpha.1":
|
||||
version "49.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@expo/config-types/-/config-types-49.0.0.tgz#15ffef715285c06703f6fb7ec0cda853f645cc09"
|
||||
integrity sha512-8eyREVi+K2acnMBe/rTIu1dOfyR2+AMnTLHlut+YpMV9OZPdeKV0Bs9BxAewGqBA2slslbQ9N39IS2CuTKpXkA==
|
||||
|
||||
"@expo/config[email protected]", "@expo/config-types@^47.0.0":
|
||||
version "47.0.0"
|
||||
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"
|
||||
integrity sha512-joVtB5o+NF40Tmsdp65UzryRtbnCuMbXkVO4wJnNJO4aaK0EYLdHCYSewORVqNcDfGN0LphQr8VTG2npbd9CJA==
|
||||
"@expo/config@8.1.2", "@expo/config@~8.1.0":
|
||||
version "8.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@expo/config/-/config-8.1.2.tgz#7fff28b3acefe39702e9f3ce1c9fd896a52caa80"
|
||||
integrity sha512-4e7hzPj50mQIlsrzOH6XZ36O094mPfPTIDIH4yv49bWNMc7GFLTofB/lcT+QyxiLaJuC0Wlk9yOLB8DIqmtwug==
|
||||
dependencies:
|
||||
"@babel/code-frame" "~7.10.4"
|
||||
"@expo/config-plugins" "~5.0.3"
|
||||
"@expo/config-types" "^47.0.0"
|
||||
"@expo/json-file" "8.2.36"
|
||||
"@expo/config-plugins" "~7.2.0"
|
||||
"@expo/config-types" "^49.0.0-alpha.1"
|
||||
"@expo/json-file" "^8.2.37"
|
||||
getenv "^1.0.0"
|
||||
glob "7.1.6"
|
||||
require-from-string "^2.0.2"
|
||||
resolve-from "^5.0.0"
|
||||
semver "7.3.2"
|
||||
semver "7.5.3"
|
||||
slugify "^1.3.4"
|
||||
sucrase "^3.20.0"
|
||||
|
||||
@@ -1450,7 +1429,7 @@
|
||||
json5 "^1.0.1"
|
||||
write-file-atomic "^2.3.0"
|
||||
|
||||
"@expo/[email protected]", "@expo/json-file@~8.2.37":
|
||||
"@expo/[email protected]", "@expo/json-file@^8.2.37", "@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==
|
||||
@@ -1459,12 +1438,13 @@
|
||||
json5 "^2.2.2"
|
||||
write-file-atomic "^2.3.0"
|
||||
|
||||
"@expo/[email protected]3":
|
||||
version "1.0.13"
|
||||
resolved "https://registry.yarnpkg.com/@expo/logger/-/logger-1.0.13.tgz#f9d02d76867aaaa7e33b30dc5a493202da5d5414"
|
||||
integrity sha512-x1dp47CCR/mohJcYhg1cv17nDP2ih5MqQcW4CJL02GpNYPlvWSR5V5203kmOdYdCWq2Rs1j45Yo9VmpS2dxSfw==
|
||||
"@expo/[email protected].21":
|
||||
version "1.0.21"
|
||||
resolved "https://registry.yarnpkg.com/@expo/logger/-/logger-1.0.21.tgz#9271b52b8e27159cbbe3385b9a01fca3317b37c2"
|
||||
integrity sha512-Vz+LHDGWUfowAwL10nBKqxrMYvO4qdZ8hLKcqUYc5mXBt+jmv7RP+8fcsMIejJEMWmYC2meO5eeCMLKKhEIgMA==
|
||||
dependencies:
|
||||
"@expo/bunyan" "^4.0.0"
|
||||
"@types/bunyan" "^1.8.8"
|
||||
bunyan "^1.8.15"
|
||||
|
||||
"@expo/[email protected]":
|
||||
version "1.1.0"
|
||||
@@ -1506,15 +1486,6 @@
|
||||
dependencies:
|
||||
node-forge "^1.2.1"
|
||||
|
||||
"@expo/[email protected]":
|
||||
version "0.0.18"
|
||||
resolved "https://registry.yarnpkg.com/@expo/plist/-/plist-0.0.18.tgz#9abcde78df703a88f6d9fa1a557ee2f045d178b0"
|
||||
integrity sha512-+48gRqUiz65R21CZ/IXa7RNBXgAI/uPSdvJqoN9x1hfL44DNbUoWHgHiEXTx7XelcATpDwNTz6sHLfy0iNqf+w==
|
||||
dependencies:
|
||||
"@xmldom/xmldom" "~0.7.0"
|
||||
base64-js "^1.2.3"
|
||||
xmlbuilder "^14.0.0"
|
||||
|
||||
"@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"
|
||||
@@ -1545,21 +1516,21 @@
|
||||
semver "^7.3.7"
|
||||
tslib "^2.4.0"
|
||||
|
||||
"@expo/prebuild-config@5.0.7":
|
||||
version "5.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@expo/prebuild-config/-/prebuild-config-5.0.7.tgz#4658b66126c4d32c7b6302571e458a71811b07aa"
|
||||
integrity sha512-D+TBpJUHe4+oTGFPb4o0rrw/h1xxc6wF+abJnbDHUkhnaeiHkE2O3ByS7FdiZ2FT36t0OKqeSKG/xFwWT3m1Ew==
|
||||
"@expo/prebuild-config@6.2.5":
|
||||
version "6.2.5"
|
||||
resolved "https://registry.yarnpkg.com/@expo/prebuild-config/-/prebuild-config-6.2.5.tgz#2e7fdce8ddef3ac97fa05b4542f2b62a43bcea4b"
|
||||
integrity sha512-XHgQ4OWZ03rzczD+D2ulQRjyHCVnA36cfX4q+r2x1Say4hI7lIg75ZQEsWdEMU9rZV8TbDUtZlPL4pxNWpYu7Q==
|
||||
dependencies:
|
||||
"@expo/config" "~7.0.2"
|
||||
"@expo/config-plugins" "~5.0.3"
|
||||
"@expo/config-types" "^47.0.0"
|
||||
"@expo/config" "~8.1.0"
|
||||
"@expo/config-plugins" "~7.2.0"
|
||||
"@expo/config-types" "^49.0.0-alpha.1"
|
||||
"@expo/image-utils" "0.3.22"
|
||||
"@expo/json-file" "8.2.36"
|
||||
"@expo/json-file" "^8.2.37"
|
||||
debug "^4.3.1"
|
||||
fs-extra "^9.0.0"
|
||||
resolve-from "^5.0.0"
|
||||
semver "7.3.2"
|
||||
xml2js "0.4.23"
|
||||
semver "7.5.3"
|
||||
xml2js "0.6.0"
|
||||
|
||||
"@expo/[email protected]":
|
||||
version "1.0.0"
|
||||
@@ -1605,15 +1576,16 @@
|
||||
dependencies:
|
||||
cross-spawn "^7.0.3"
|
||||
|
||||
"@expo/[email protected].13":
|
||||
version "1.0.13"
|
||||
resolved "https://registry.yarnpkg.com/@expo/steps/-/steps-1.0.13.tgz#97d448055a8fda8c1e04b2c7c95e2e9cfae3820e"
|
||||
integrity sha512-Hf8VFgwaFsvIb9/8r02/RO5eb1gDUSVyBFgBYVb3iMJvjoZXv74+mJllbh3x1EO28ai68vcEtp8uZ8Su2sLuwg==
|
||||
"@expo/[email protected].25":
|
||||
version "1.0.25"
|
||||
resolved "https://registry.yarnpkg.com/@expo/steps/-/steps-1.0.25.tgz#04f8c18bb12f2445cdca443b48497d3c2be3e133"
|
||||
integrity sha512-MBtJ/3+T5qvXxmnOVlfapKlKQsxPUyKoEUaA6lLbpmm8yCcXJEblnmQP/2ZokAG78IWjsYl5E02Ei/AnrIxB9g==
|
||||
dependencies:
|
||||
"@expo/logger" "1.0.13"
|
||||
"@expo/logger" "1.0.21"
|
||||
"@expo/spawn-async" "^1.7.0"
|
||||
arg "^5.0.2"
|
||||
joi "^17.7.0"
|
||||
lodash.get "^4.4.2"
|
||||
this-file "^2.0.3"
|
||||
uuid "^9.0.0"
|
||||
yaml "^2.2.1"
|
||||
@@ -4154,6 +4126,13 @@
|
||||
"@types/connect" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/bunyan@^1.8.8":
|
||||
version "1.8.8"
|
||||
resolved "https://registry.yarnpkg.com/@types/bunyan/-/bunyan-1.8.8.tgz#8d6d33f090f37c07e2a80af30ae728450a101008"
|
||||
integrity sha512-Cblq+Yydg3u+sGiz2mjHjC5MPmdjY+No4qvHrF+BUhblsmSfMvsHLbOG62tPbonsqBj6sbWv1LHcsoe5Jw+/Ow==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/cacheable-request@^6.0.1":
|
||||
version "6.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183"
|
||||
@@ -4563,20 +4542,30 @@
|
||||
"@typescript-eslint/types" "5.33.0"
|
||||
eslint-visitor-keys "^3.3.0"
|
||||
|
||||
"@urql/core@3.1.1", "@urql/core@>=3.0.0":
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@urql/core/-/core-3.1.1.tgz#a49cd572360d01f2469a786b294fba2269a65e53"
|
||||
integrity sha512-Mnxtq4I4QeFJsgs7Iytw+HyhiGxISR6qtyk66c9tipozLZ6QVxrCiUPF2HY4BxNIabaxcp+rivadvm8NAnXj4Q==
|
||||
"@urql/core@4.0.11", "@urql/core@>=4.0.0":
|
||||
version "4.0.11"
|
||||
resolved "https://registry.yarnpkg.com/@urql/core/-/core-4.0.11.tgz#b4e8bf3a3ff1a2519bb3aec38c7be99d2523308d"
|
||||
integrity sha512-FFdY97vF5xnUrElcGw9erOLvtu+KGMLfwrLNDfv4IPgdp2IBsiGe+Kb7Aypfd3kH//BETewVSLm3+y2sSzjX6A==
|
||||
dependencies:
|
||||
wonka "^6.1.2"
|
||||
"@0no-co/graphql.web" "^1.0.1"
|
||||
wonka "^6.3.2"
|
||||
|
||||
"@urql/exchange-[email protected]":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@urql/exchange-retry/-/exchange-retry-1.0.0.tgz#25a48ef0c2f6854f5617e2ca4ea25ae240f1fcbc"
|
||||
integrity sha512-UGyyGAMXzop9C/fIoe7Ij63DkPSy1uMw2jipB5dnB8R3kl80za7LYzVnA1HvBEt2ZPWfMuwez/VGLOQ7XX4bTA==
|
||||
"@urql/exchange-[email protected]":
|
||||
version "6.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@urql/exchange-graphcache/-/exchange-graphcache-6.1.4.tgz#5d69c838f7a1d313018f63abb8ead79f8c1ea133"
|
||||
integrity sha512-GQ1scnYjMVoUHrPoYOlw3ZfU2nXuLTEhWhKzPquhZz87GliVpZPuFMf+o64cI1dKy9xDlbU7aQnKiSaGeT248w==
|
||||
dependencies:
|
||||
"@urql/core" ">=3.0.0"
|
||||
wonka "^6.0.0"
|
||||
"@0no-co/graphql.web" "^1.0.1"
|
||||
"@urql/core" ">=4.0.0"
|
||||
wonka "^6.3.2"
|
||||
|
||||
"@urql/[email protected]":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@urql/exchange-retry/-/exchange-retry-1.2.0.tgz#23d3ec711754e3c67a843e0106f2cabddff2e5ff"
|
||||
integrity sha512-1O/biKiVhhn0EtvDF4UOvz325K4RrLupfL8rHcmqD2TBLv4qVDWQuzx4JGa1FfqjjRb+C9TNZ6w19f32Mq85Ug==
|
||||
dependencies:
|
||||
"@urql/core" ">=4.0.0"
|
||||
wonka "^6.3.2"
|
||||
|
||||
"@whatwg-node/[email protected]", "@whatwg-node/fetch@^0.5.0":
|
||||
version "0.5.4"
|
||||
@@ -4607,11 +4596,6 @@
|
||||
undici "^5.8.0"
|
||||
web-streams-polyfill "^3.2.0"
|
||||
|
||||
"@xmldom/xmldom@~0.7.0":
|
||||
version "0.7.2"
|
||||
resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.7.2.tgz#d920079e66806b2626b5311955f6a7c4bed1cba8"
|
||||
integrity sha512-t/Zqo0ewes3iq6zGqEqJNUWI27Acr3jkmSUNp6E3nl0Z2XbtqAG5XYqPNLdYonILmhcxANsIidh69tHzjXtuRg==
|
||||
|
||||
"@xmldom/xmldom@~0.7.7":
|
||||
version "0.7.9"
|
||||
resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.7.9.tgz#7f9278a50e737920e21b297b8a35286e9942c056"
|
||||
@@ -5377,6 +5361,16 @@ builtins@^5.0.0:
|
||||
dependencies:
|
||||
semver "^7.0.0"
|
||||
|
||||
bunyan@^1.8.15:
|
||||
version "1.8.15"
|
||||
resolved "https://registry.yarnpkg.com/bunyan/-/bunyan-1.8.15.tgz#8ce34ca908a17d0776576ca1b2f6cbd916e93b46"
|
||||
integrity sha512-0tECWShh6wUysgucJcBAoYegf3JJoZWibxdqhTm7OHPeT42qdjkZ29QCMcKwbgU1kiH+auSIasNRXMLWXafXig==
|
||||
optionalDependencies:
|
||||
dtrace-provider "~0.8"
|
||||
moment "^2.19.3"
|
||||
mv "~2"
|
||||
safe-json-stringify "~1"
|
||||
|
||||
busboy@^1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893"
|
||||
@@ -6529,6 +6523,13 @@ [email protected], dset@^3.1.2:
|
||||
resolved "https://registry.yarnpkg.com/dset/-/dset-3.1.2.tgz#89c436ca6450398396dc6538ea00abc0c54cd45a"
|
||||
integrity sha512-g/M9sqy3oHe477Ar4voQxWtaPIFw1jTdKZuomOjhCcBx9nHUNn0pu6NopuFFrTh/TRZIKEj+76vLWFu9BNKk+Q==
|
||||
|
||||
dtrace-provider@~0.8:
|
||||
version "0.8.8"
|
||||
resolved "https://registry.yarnpkg.com/dtrace-provider/-/dtrace-provider-0.8.8.tgz#2996d5490c37e1347be263b423ed7b297fb0d97e"
|
||||
integrity sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==
|
||||
dependencies:
|
||||
nan "^2.14.0"
|
||||
|
||||
duplexer@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1"
|
||||
@@ -9741,7 +9742,7 @@ lodash.flatten@^4.4.0:
|
||||
resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f"
|
||||
integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=
|
||||
|
||||
lodash.get@^4:
|
||||
lodash.get@^4, lodash.get@^4.4.2:
|
||||
version "4.4.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
|
||||
integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=
|
||||
@@ -10301,6 +10302,11 @@ modify-values@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022"
|
||||
integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==
|
||||
|
||||
moment@^2.19.3:
|
||||
version "2.29.4"
|
||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
|
||||
integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==
|
||||
|
||||
[email protected]:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
@@ -10350,6 +10356,11 @@ mz@^2.7.0:
|
||||
object-assign "^4.0.1"
|
||||
thenify-all "^1.0.0"
|
||||
|
||||
nan@^2.14.0:
|
||||
version "2.17.0"
|
||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb"
|
||||
integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==
|
||||
|
||||
[email protected]:
|
||||
version "3.3.4"
|
||||
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
|
||||
@@ -12073,6 +12084,13 @@ [email protected], semver@^7.0.0, semver@^7.3.8:
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
[email protected], semver@^7.5.3:
|
||||
version "7.5.3"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.3.tgz#161ce8c2c6b4b3bdca6caadc9fa3317a4c4fe88e"
|
||||
integrity sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
[email protected], semver@^7.1.1, semver@^7.1.3, semver@^7.2.1, semver@^7.3.4, semver@^7.3.5:
|
||||
version "7.3.5"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7"
|
||||
@@ -13613,15 +13631,10 @@ widest-line@^3.1.0:
|
||||
dependencies:
|
||||
string-width "^4.0.0"
|
||||
|
||||
wonka@^6.0.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/wonka/-/wonka-6.1.0.tgz#65297ebf7031ae46d4b0c56da93950fb3ae5baaa"
|
||||
integrity sha512-VgiMCz7BXOiDbgpVhf5iNhK7hurteY5Jv0fDJewUkY0s4fbxQD2iKqfGxNXNTwp2v3bgT8QVu2l5H7YdkZ5WIA==
|
||||
|
||||
wonka@^6.1.2:
|
||||
version "6.1.2"
|
||||
resolved "https://registry.yarnpkg.com/wonka/-/wonka-6.1.2.tgz#2c66fa5b26a12f002a03619b988258313d0b5352"
|
||||
integrity sha512-zNrXPMccg/7OEp9tSfFkMgTvhhowqasiSHdJ3eCZolXxVTV/aT6HUTofoZk9gwRbGoFey/Nss3JaZKUMKMbofg==
|
||||
wonka@^6.3.2:
|
||||
version "6.3.2"
|
||||
resolved "https://registry.yarnpkg.com/wonka/-/wonka-6.3.2.tgz#6f32992b332251d7b696b038990f4dc284b3b33d"
|
||||
integrity sha512-2xXbQ1LnwNS7egVm1HPhW2FyKrekolzhpM3mCwXdQr55gO+tAiY76rhb32OL9kKsW8taj++iP7C6hxlVzbnvrw==
|
||||
|
||||
word-wrap@^1.2.3:
|
||||
version "1.2.3"
|
||||
@@ -13767,10 +13780,10 @@ [email protected]:
|
||||
sax ">=0.6.0"
|
||||
xmlbuilder "~9.0.1"
|
||||
|
||||
xml2js@0.4.23:
|
||||
version "0.4.23"
|
||||
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66"
|
||||
integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==
|
||||
xml2js@0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.6.0.tgz#07afc447a97d2bd6507a1f76eeadddb09f7a8282"
|
||||
integrity sha512-eLTh0kA8uHceqesPqSE+VvO1CDDJWMwlQfB6LuN6T8w6MaDJ8Txm8P7s5cHD0miF0V+GGTZrDQfxPZQVsur33w==
|
||||
dependencies:
|
||||
sax ">=0.6.0"
|
||||
xmlbuilder "~11.0.0"
|
||||
|
||||
Reference in new issue
Block a user