Compare commits

..
Author SHA1 Message Date
Stanisław Chmiela 9b943a351c wip 2023-06-07 10:14:17 +02:00
61 changed files with 700 additions and 1677 deletions

No files matched your search

-28
View File
@@ -8,38 +8,10 @@ This is the log of notable changes to EAS CLI and related packages.
### 🎉 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))
### 🐛 Bug fixes
### 🧹 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))
- Set useClassicUpdates to false on `eas update` and `eas update:configure`. ([#1914](https://github.com/expo/eas-cli/pull/1914) by [@quinlanj](https://github.com/quinlanj))
## [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
+6 -6
View File
@@ -1,10 +1,10 @@
* @szdziedzic @khamilowicz
* @szdziedzic @wkozyra95
packages/eas-cli/src/build @szdziedzic @khamilowicz
packages/eas-cli/src/commands/build @szdziedzic @khamilowicz
packages/eas-cli/src/build @szdziedzic @wkozyra95
packages/eas-cli/src/commands/build @szdziedzic @wkozyra95
packages/eas-cli/src/submit @szdziedzic @khamilowicz
packages/eas-cli/src/commands/submit.ts @szdziedzic @khamilowicz
packages/eas-cli/src/submit @szdziedzic
packages/eas-cli/src/commands/submit.ts @szdziedzic
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 @szdziedzic @khamilowicz
packages/eas-json @szdziedzic @wkozyra95
+1 -1
View File
@@ -1,6 +1,6 @@
{
"npmClient": "yarn",
"useWorkspaces": true,
"version": "3.14.0",
"version": "3.13.3",
"$schema": "node_modules/lerna/schemas/lerna-schema.json"
}
+119 -121
View File
@@ -55,69 +55,68 @@ eas --help COMMAND
# Commands
<!-- commands -->
- [`eas account:login`](#eas-accountlogin)
- [`eas account:logout`](#eas-accountlogout)
- [`eas account:view`](#eas-accountview)
- [`eas analytics [STATUS]`](#eas-analytics-status)
- [`eas autocomplete [SHELL]`](#eas-autocomplete-shell)
- [`eas branch:create [NAME]`](#eas-branchcreate-name)
- [`eas branch:delete [NAME]`](#eas-branchdelete-name)
- [`eas branch:list`](#eas-branchlist)
- [`eas branch:rename`](#eas-branchrename)
- [`eas branch:view [NAME]`](#eas-branchview-name)
- [`eas build`](#eas-build)
- [`eas build:cancel [BUILD_ID]`](#eas-buildcancel-build_id)
- [`eas build:configure`](#eas-buildconfigure)
- [`eas build:inspect`](#eas-buildinspect)
- [`eas build:list`](#eas-buildlist)
- [`eas build:resign`](#eas-buildresign)
- [`eas build:run`](#eas-buildrun)
- [`eas build:submit`](#eas-buildsubmit)
- [`eas build:version:get`](#eas-buildversionget)
- [`eas build:version:set`](#eas-buildversionset)
- [`eas build:version:sync`](#eas-buildversionsync)
- [`eas build:view [BUILD_ID]`](#eas-buildview-build_id)
- [`eas channel:create [NAME]`](#eas-channelcreate-name)
- [`eas channel:edit [NAME]`](#eas-channeledit-name)
- [`eas channel:list`](#eas-channellist)
- [`eas channel:rollout [CHANNEL]`](#eas-channelrollout-channel)
- [`eas channel:view [NAME]`](#eas-channelview-name)
- [`eas config`](#eas-config)
- [`eas credentials`](#eas-credentials)
- [`eas device:create`](#eas-devicecreate)
- [`eas device:delete`](#eas-devicedelete)
- [`eas device:list`](#eas-devicelist)
- [`eas device:rename`](#eas-devicerename)
- [`eas device:view [UDID]`](#eas-deviceview-udid)
- [`eas diagnostics`](#eas-diagnostics)
- [`eas help [COMMAND]`](#eas-help-command)
- [`eas init`](#eas-init)
- [`eas login`](#eas-login)
- [`eas logout`](#eas-logout)
- [`eas metadata:lint`](#eas-metadatalint)
- [`eas metadata:pull`](#eas-metadatapull)
- [`eas metadata:push`](#eas-metadatapush)
- [`eas open`](#eas-open)
- [`eas project:info`](#eas-projectinfo)
- [`eas project:init`](#eas-projectinit)
- [`eas secret:create`](#eas-secretcreate)
- [`eas secret:delete`](#eas-secretdelete)
- [`eas secret:list`](#eas-secretlist)
- [`eas secret:push`](#eas-secretpush)
- [`eas submit`](#eas-submit)
- [`eas update`](#eas-update)
- [`eas update:configure`](#eas-updateconfigure)
- [`eas update:delete GROUPID`](#eas-updatedelete-groupid)
- [`eas update:list`](#eas-updatelist)
- [`eas update:republish`](#eas-updaterepublish)
- [`eas update:view GROUPID`](#eas-updateview-groupid)
- [`eas webhook:create`](#eas-webhookcreate)
- [`eas webhook:delete [ID]`](#eas-webhookdelete-id)
- [`eas webhook:list`](#eas-webhooklist)
- [`eas webhook:update`](#eas-webhookupdate)
- [`eas webhook:view ID`](#eas-webhookview-id)
- [`eas whoami`](#eas-whoami)
* [`eas account:login`](#eas-accountlogin)
* [`eas account:logout`](#eas-accountlogout)
* [`eas account:view`](#eas-accountview)
* [`eas analytics [STATUS]`](#eas-analytics-status)
* [`eas autocomplete [SHELL]`](#eas-autocomplete-shell)
* [`eas branch:create [NAME]`](#eas-branchcreate-name)
* [`eas branch:delete [NAME]`](#eas-branchdelete-name)
* [`eas branch:list`](#eas-branchlist)
* [`eas branch:rename`](#eas-branchrename)
* [`eas branch:view [NAME]`](#eas-branchview-name)
* [`eas build`](#eas-build)
* [`eas build:cancel [BUILD_ID]`](#eas-buildcancel-build_id)
* [`eas build:configure`](#eas-buildconfigure)
* [`eas build:inspect`](#eas-buildinspect)
* [`eas build:list`](#eas-buildlist)
* [`eas build:resign`](#eas-buildresign)
* [`eas build:run`](#eas-buildrun)
* [`eas build:submit`](#eas-buildsubmit)
* [`eas build:version:get`](#eas-buildversionget)
* [`eas build:version:set`](#eas-buildversionset)
* [`eas build:version:sync`](#eas-buildversionsync)
* [`eas build:view [BUILD_ID]`](#eas-buildview-build_id)
* [`eas channel:create [NAME]`](#eas-channelcreate-name)
* [`eas channel:edit [NAME]`](#eas-channeledit-name)
* [`eas channel:list`](#eas-channellist)
* [`eas channel:rollout [CHANNEL]`](#eas-channelrollout-channel)
* [`eas channel:view [NAME]`](#eas-channelview-name)
* [`eas config`](#eas-config)
* [`eas credentials`](#eas-credentials)
* [`eas device:create`](#eas-devicecreate)
* [`eas device:delete`](#eas-devicedelete)
* [`eas device:list`](#eas-devicelist)
* [`eas device:rename`](#eas-devicerename)
* [`eas device:view [UDID]`](#eas-deviceview-udid)
* [`eas diagnostics`](#eas-diagnostics)
* [`eas help [COMMAND]`](#eas-help-command)
* [`eas init`](#eas-init)
* [`eas login`](#eas-login)
* [`eas logout`](#eas-logout)
* [`eas metadata:lint`](#eas-metadatalint)
* [`eas metadata:pull`](#eas-metadatapull)
* [`eas metadata:push`](#eas-metadatapush)
* [`eas open`](#eas-open)
* [`eas project:info`](#eas-projectinfo)
* [`eas project:init`](#eas-projectinit)
* [`eas secret:create`](#eas-secretcreate)
* [`eas secret:delete`](#eas-secretdelete)
* [`eas secret:list`](#eas-secretlist)
* [`eas secret:push`](#eas-secretpush)
* [`eas submit`](#eas-submit)
* [`eas update`](#eas-update)
* [`eas update:configure`](#eas-updateconfigure)
* [`eas update:delete GROUPID`](#eas-updatedelete-groupid)
* [`eas update:list`](#eas-updatelist)
* [`eas update:republish`](#eas-updaterepublish)
* [`eas update:view GROUPID`](#eas-updateview-groupid)
* [`eas webhook:create`](#eas-webhookcreate)
* [`eas webhook:delete [ID]`](#eas-webhookdelete-id)
* [`eas webhook:list`](#eas-webhooklist)
* [`eas webhook:update`](#eas-webhookupdate)
* [`eas webhook:view ID`](#eas-webhookview-id)
* [`eas whoami`](#eas-whoami)
## `eas account:login`
@@ -134,7 +133,7 @@ ALIASES
$ eas login
```
_See code: [src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/account/login.ts)_
_See code: [src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/account/login.ts)_
## `eas account:logout`
@@ -151,7 +150,7 @@ ALIASES
$ eas logout
```
_See code: [src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/account/logout.ts)_
_See code: [src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/account/logout.ts)_
## `eas account:view`
@@ -168,7 +167,7 @@ ALIASES
$ eas whoami
```
_See code: [src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/account/view.ts)_
_See code: [src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/account/view.ts)_
## `eas analytics [STATUS]`
@@ -182,7 +181,7 @@ DESCRIPTION
display or change analytics settings
```
_See code: [src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/analytics.ts)_
_See code: [src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/analytics.ts)_
## `eas autocomplete [SHELL]`
@@ -232,7 +231,7 @@ DESCRIPTION
create a branch
```
_See code: [src/commands/branch/create.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/branch/create.ts)_
_See code: [src/commands/branch/create.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/branch/create.ts)_
## `eas branch:delete [NAME]`
@@ -253,7 +252,7 @@ DESCRIPTION
delete a branch
```
_See code: [src/commands/branch/delete.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/branch/delete.ts)_
_See code: [src/commands/branch/delete.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/branch/delete.ts)_
## `eas branch:list`
@@ -273,7 +272,7 @@ DESCRIPTION
list all branches
```
_See code: [src/commands/branch/list.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/branch/list.ts)_
_See code: [src/commands/branch/list.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/branch/list.ts)_
## `eas branch:rename`
@@ -293,7 +292,7 @@ DESCRIPTION
rename a branch
```
_See code: [src/commands/branch/rename.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/branch/rename.ts)_
_See code: [src/commands/branch/rename.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/branch/rename.ts)_
## `eas branch:view [NAME]`
@@ -316,7 +315,7 @@ DESCRIPTION
view a branch
```
_See code: [src/commands/branch/view.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/branch/view.ts)_
_See code: [src/commands/branch/view.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/branch/view.ts)_
## `eas build`
@@ -346,7 +345,7 @@ DESCRIPTION
start a build
```
_See code: [src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/build/index.ts)_
_See code: [src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/build/index.ts)_
## `eas build:cancel [BUILD_ID]`
@@ -363,7 +362,7 @@ DESCRIPTION
cancel a build
```
_See code: [src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/build/cancel.ts)_
_See code: [src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/build/cancel.ts)_
## `eas build:configure`
@@ -380,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.14.0/packages/eas-cli/src/commands/build/configure.ts)_
_See code: [src/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/build/configure.ts)_
## `eas build:inspect`
@@ -415,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.14.0/packages/eas-cli/src/commands/build/inspect.ts)_
_See code: [src/commands/build/inspect.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/build/inspect.ts)_
## `eas build:list`
@@ -453,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.14.0/packages/eas-cli/src/commands/build/list.ts)_
_See code: [src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/build/list.ts)_
## `eas build:resign`
@@ -479,7 +478,7 @@ DESCRIPTION
re-sign a build archive
```
_See code: [src/commands/build/resign.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/build/resign.ts)_
_See code: [src/commands/build/resign.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/build/resign.ts)_
## `eas build:run`
@@ -503,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.14.0/packages/eas-cli/src/commands/build/run.ts)_
_See code: [src/commands/build/run.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/build/run.ts)_
## `eas build:submit`
@@ -552,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.14.0/packages/eas-cli/src/commands/build/version/get.ts)_
_See code: [src/commands/build/version/get.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/build/version/get.ts)_
## `eas build:version:set`
@@ -571,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.14.0/packages/eas-cli/src/commands/build/version/set.ts)_
_See code: [src/commands/build/version/set.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/build/version/set.ts)_
## `eas build:version:sync`
@@ -590,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.14.0/packages/eas-cli/src/commands/build/version/sync.ts)_
_See code: [src/commands/build/version/sync.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/build/version/sync.ts)_
## `eas build:view [BUILD_ID]`
@@ -607,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.14.0/packages/eas-cli/src/commands/build/view.ts)_
_See code: [src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/build/view.ts)_
## `eas channel:create [NAME]`
@@ -628,7 +627,7 @@ DESCRIPTION
create a channel
```
_See code: [src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/channel/create.ts)_
_See code: [src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/channel/create.ts)_
## `eas channel:edit [NAME]`
@@ -650,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.14.0/packages/eas-cli/src/commands/channel/edit.ts)_
_See code: [src/commands/channel/edit.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/channel/edit.ts)_
## `eas channel:list`
@@ -670,7 +669,7 @@ DESCRIPTION
list all channels
```
_See code: [src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/channel/list.ts)_
_See code: [src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/channel/list.ts)_
## `eas channel:rollout [CHANNEL]`
@@ -694,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.14.0/packages/eas-cli/src/commands/channel/rollout.ts)_
_See code: [src/commands/channel/rollout.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/channel/rollout.ts)_
## `eas channel:view [NAME]`
@@ -717,7 +716,7 @@ DESCRIPTION
view a channel
```
_See code: [src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/channel/view.ts)_
_See code: [src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/channel/view.ts)_
## `eas config`
@@ -738,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.14.0/packages/eas-cli/src/commands/config.ts)_
_See code: [src/commands/config.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/config.ts)_
## `eas credentials`
@@ -755,7 +754,7 @@ DESCRIPTION
manage credentials
```
_See code: [src/commands/credentials.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/credentials.ts)_
_See code: [src/commands/credentials.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/credentials.ts)_
## `eas device:create`
@@ -769,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.14.0/packages/eas-cli/src/commands/device/create.ts)_
_See code: [src/commands/device/create.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/device/create.ts)_
## `eas device:delete`
@@ -789,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.14.0/packages/eas-cli/src/commands/device/delete.ts)_
_See code: [src/commands/device/delete.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/device/delete.ts)_
## `eas device:list`
@@ -810,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.14.0/packages/eas-cli/src/commands/device/list.ts)_
_See code: [src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/device/list.ts)_
## `eas device:rename`
@@ -831,7 +830,7 @@ DESCRIPTION
rename a registered device
```
_See code: [src/commands/device/rename.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/device/rename.ts)_
_See code: [src/commands/device/rename.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/device/rename.ts)_
## `eas device:view [UDID]`
@@ -845,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.14.0/packages/eas-cli/src/commands/device/view.ts)_
_See code: [src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/device/view.ts)_
## `eas diagnostics`
@@ -859,7 +858,7 @@ DESCRIPTION
display environment info
```
_See code: [src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/diagnostics.ts)_
_See code: [src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/diagnostics.ts)_
## `eas help [COMMAND]`
@@ -947,7 +946,7 @@ DESCRIPTION
validate the local store configuration
```
_See code: [src/commands/metadata/lint.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/metadata/lint.ts)_
_See code: [src/commands/metadata/lint.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/metadata/lint.ts)_
## `eas metadata:pull`
@@ -964,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.14.0/packages/eas-cli/src/commands/metadata/pull.ts)_
_See code: [src/commands/metadata/pull.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/metadata/pull.ts)_
## `eas metadata:push`
@@ -981,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.14.0/packages/eas-cli/src/commands/metadata/push.ts)_
_See code: [src/commands/metadata/push.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/metadata/push.ts)_
## `eas open`
@@ -995,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.14.0/packages/eas-cli/src/commands/open.ts)_
_See code: [src/commands/open.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/open.ts)_
## `eas project:info`
@@ -1009,7 +1008,7 @@ DESCRIPTION
information about the current project
```
_See code: [src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/project/info.ts)_
_See code: [src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/project/info.ts)_
## `eas project:init`
@@ -1031,7 +1030,7 @@ ALIASES
$ eas init
```
_See code: [src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/project/init.ts)_
_See code: [src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/project/init.ts)_
## `eas secret:create`
@@ -1054,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.14.0/packages/eas-cli/src/commands/secret/create.ts)_
_See code: [src/commands/secret/create.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/secret/create.ts)_
## `eas secret:delete`
@@ -1072,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.14.0/packages/eas-cli/src/commands/secret/delete.ts)_
_See code: [src/commands/secret/delete.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/secret/delete.ts)_
## `eas secret:list`
@@ -1086,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.14.0/packages/eas-cli/src/commands/secret/list.ts)_
_See code: [src/commands/secret/list.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/secret/list.ts)_
## `eas secret:push`
@@ -1106,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.14.0/packages/eas-cli/src/commands/secret/push.ts)_
_See code: [src/commands/secret/push.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/secret/push.ts)_
## `eas submit`
@@ -1136,7 +1135,7 @@ ALIASES
$ eas build:submit
```
_See code: [src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/submit.ts)_
_See code: [src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/submit.ts)_
## `eas update`
@@ -1157,7 +1156,7 @@ 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
--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
@@ -1169,7 +1168,7 @@ DESCRIPTION
publish an update group
```
_See code: [src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/update/index.ts)_
_See code: [src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/update/index.ts)_
## `eas update:configure`
@@ -1187,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.14.0/packages/eas-cli/src/commands/update/configure.ts)_
_See code: [src/commands/update/configure.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/update/configure.ts)_
## `eas update:delete GROUPID`
@@ -1208,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.14.0/packages/eas-cli/src/commands/update/delete.ts)_
_See code: [src/commands/update/delete.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/update/delete.ts)_
## `eas update:list`
@@ -1230,7 +1229,7 @@ DESCRIPTION
view the recent updates
```
_See code: [src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/update/list.ts)_
_See code: [src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/update/list.ts)_
## `eas update:republish`
@@ -1247,14 +1246,14 @@ FLAGS
--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
--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.14.0/packages/eas-cli/src/commands/update/republish.ts)_
_See code: [src/commands/update/republish.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/update/republish.ts)_
## `eas update:view GROUPID`
@@ -1274,7 +1273,7 @@ DESCRIPTION
update group details
```
_See code: [src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/update/view.ts)_
_See code: [src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/update/view.ts)_
## `eas webhook:create`
@@ -1295,7 +1294,7 @@ DESCRIPTION
create a webhook
```
_See code: [src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/webhook/create.ts)_
_See code: [src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/webhook/create.ts)_
## `eas webhook:delete [ID]`
@@ -1315,7 +1314,7 @@ DESCRIPTION
delete a webhook
```
_See code: [src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/webhook/delete.ts)_
_See code: [src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/webhook/delete.ts)_
## `eas webhook:list`
@@ -1333,7 +1332,7 @@ DESCRIPTION
list webhooks
```
_See code: [src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/webhook/list.ts)_
_See code: [src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/webhook/list.ts)_
## `eas webhook:update`
@@ -1355,7 +1354,7 @@ DESCRIPTION
update a webhook
```
_See code: [src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/webhook/update.ts)_
_See code: [src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/webhook/update.ts)_
## `eas webhook:view ID`
@@ -1372,7 +1371,7 @@ DESCRIPTION
view a webhook
```
_See code: [src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/webhook/view.ts)_
_See code: [src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v3.13.3/packages/eas-cli/src/commands/webhook/view.ts)_
## `eas whoami`
@@ -1388,5 +1387,4 @@ DESCRIPTION
ALIASES
$ eas whoami
```
<!-- commandsstop -->
+142 -404
View File
@@ -7252,18 +7252,6 @@
"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,
@@ -9262,22 +9250,6 @@
"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,
@@ -13497,277 +13469,6 @@
],
"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",
@@ -17336,29 +17037,6 @@
"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",
@@ -21008,7 +20686,7 @@
"fields": [
{
"name": "createGitHubBuild",
"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.",
"description": "Create a GitHub build for an app",
"args": [
{
"name": "buildInput",
@@ -21031,8 +20709,8 @@
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "BackgroundJobReceipt",
"kind": "SCALAR",
"name": "Boolean",
"ofType": null
}
},
@@ -29001,22 +28679,6 @@
"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,
@@ -29652,8 +29314,8 @@
"name": "String",
"ofType": null
},
"isDeprecated": true,
"deprecationReason": "No longer supported"
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "apps",
@@ -29862,8 +29524,8 @@
"name": "String",
"ofType": null
},
"isDeprecated": true,
"deprecationReason": "No longer supported"
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "id",
@@ -29890,8 +29552,8 @@
"name": "String",
"ofType": null
},
"isDeprecated": true,
"deprecationReason": "No longer supported"
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "isExpoAdmin",
@@ -29930,8 +29592,8 @@
"name": "String",
"ofType": null
},
"isDeprecated": true,
"deprecationReason": "No longer supported"
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "notificationSubscriptions",
@@ -30068,8 +29730,8 @@
"name": "String",
"ofType": null
},
"isDeprecated": true,
"deprecationReason": "No longer supported"
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "username",
@@ -30122,6 +29784,30 @@
"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,
@@ -30133,6 +29819,30 @@
"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,
@@ -33245,22 +32955,6 @@
"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,
@@ -33673,22 +33367,6 @@
"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,
@@ -34735,8 +34413,8 @@
"name": "String",
"ofType": null
},
"isDeprecated": true,
"deprecationReason": "No longer supported"
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "apps",
@@ -34973,8 +34651,8 @@
"name": "String",
"ofType": null
},
"isDeprecated": true,
"deprecationReason": "No longer supported"
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "hasPendingUserInvitations",
@@ -35017,8 +34695,8 @@
"name": "String",
"ofType": null
},
"isDeprecated": true,
"deprecationReason": "No longer supported"
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "isExpoAdmin",
@@ -35050,7 +34728,7 @@
}
},
"isDeprecated": true,
"deprecationReason": "No longer supported"
"deprecationReason": "This field no longer exists"
},
{
"name": "isSecondFactorAuthenticationEnabled",
@@ -35089,8 +34767,8 @@
"name": "String",
"ofType": null
},
"isDeprecated": true,
"deprecationReason": "No longer supported"
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "notificationSubscriptions",
@@ -35275,8 +34953,8 @@
"name": "String",
"ofType": null
},
"isDeprecated": true,
"deprecationReason": "No longer supported"
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "username",
@@ -35462,8 +35140,8 @@
"name": "String",
"ofType": null
},
"isDeprecated": true,
"deprecationReason": "No longer supported"
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "apps",
@@ -35672,8 +35350,8 @@
"name": "String",
"ofType": null
},
"isDeprecated": true,
"deprecationReason": "No longer supported"
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "id",
@@ -35700,8 +35378,8 @@
"name": "String",
"ofType": null
},
"isDeprecated": true,
"deprecationReason": "No longer supported"
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "isExpoAdmin",
@@ -35740,8 +35418,8 @@
"name": "String",
"ofType": null
},
"isDeprecated": true,
"deprecationReason": "No longer supported"
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "notificationSubscriptions",
@@ -35878,8 +35556,8 @@
"name": "String",
"ofType": null
},
"isDeprecated": true,
"deprecationReason": "No longer supported"
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "username",
@@ -36003,6 +35681,18 @@
"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,
@@ -36039,6 +35729,18 @@
"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,
@@ -36051,6 +35753,18 @@
"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,
@@ -36063,6 +35777,18 @@
"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,
@@ -36075,6 +35801,18 @@
"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,
+6 -7
View File
@@ -1,18 +1,18 @@
{
"name": "eas-cli",
"description": "EAS command line tool",
"version": "3.14.0",
"version": "3.13.3",
"author": "Expo <[email protected]>",
"bin": {
"eas": "./bin/run"
},
"bugs": "https://github.com/expo/eas-cli/issues",
"dependencies": {
"@expo/apple-utils": "1.3.1",
"@expo/apple-utils": "1.2.0",
"@expo/code-signing-certificates": "0.0.5",
"@expo/config": "8.1.2",
"@expo/config-plugins": "7.2.3",
"@expo/config-types": "49.0.0",
"@expo/config": "7.0.3",
"@expo/config-plugins": "6.0.2",
"@expo/config-types": "47.0.0",
"@expo/eas-build-job": "1.0.13",
"@expo/eas-json": "3.13.0",
"@expo/json-file": "8.2.37",
@@ -27,7 +27,7 @@
"@expo/results": "1.0.0",
"@expo/rudder-sdk-node": "1.1.1",
"@expo/spawn-async": "1.7.0",
"@expo/steps": "1.0.23",
"@expo/steps": "1.0.13",
"@expo/timeago.js": "1.0.0",
"@oclif/core": "1.23.2",
"@oclif/plugin-autocomplete": "1.3.10",
@@ -47,7 +47,6 @@
"fast-glob": "3.2.12",
"figures": "3.2.0",
"form-data": "4.0.0",
"freeport-async": "2.0.0",
"fs-extra": "10.1.0",
"getenv": "1.0.0",
"gradle-to-js": "2.0.1",
-12
View File
@@ -2,7 +2,6 @@ import { JSONValue } from '@expo/json-file';
import { ApiV2Error } from './ApiV2Error';
import fetch, { RequestError, RequestInit } from './fetch';
import { getFreePortAsync } from './utils/port';
interface RequestOptions {
body: JSONValue;
@@ -105,14 +104,3 @@ export function getEASUpdateURL(projectId: string): string {
return new URL(projectId, `https://u.expo.dev`).href;
}
}
export async function getSsoLocalServerPortAsync(): Promise<number> {
let startPort: number;
if (process.env.SSO_LOCAL_SERVER_PORT) {
startPort = Number(process.env.SSO_LOCAL_SERVER_PORT);
} else {
startPort = 19300;
}
const port = await getFreePortAsync(startPort);
return port;
}
-7
View File
@@ -42,7 +42,6 @@ import {
EasBuildFreeTierDisabledAndroidError,
EasBuildFreeTierDisabledError,
EasBuildFreeTierDisabledIOSError,
EasBuildProjectArchiveUploadError,
EasBuildResourceClassNotAvailableInFreeTierError,
EasBuildTooManyPendingBuildsError,
RequestValidationError,
@@ -270,12 +269,6 @@ 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 -11
View File
@@ -3,7 +3,7 @@ import { EasJson, EasJsonAccessor } from '@expo/eas-json';
import chalk from 'chalk';
import fs from 'fs-extra';
import Log, { learnMore } from '../log';
import Log from '../log';
import { resolveWorkflowAsync } from '../project/workflow';
import { easCliVersion } from '../utils/easCli';
import { getVcsClient } from '../vcs';
@@ -14,10 +14,6 @@ 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.
*
@@ -28,7 +24,7 @@ export async function easJsonExistsAsync(projectDir: string): Promise<boolean> {
export async function ensureProjectConfiguredAsync(
configureParams: ConfigureParams
): Promise<boolean> {
if (await easJsonExistsAsync(configureParams.projectDir)) {
if (await fs.pathExists(EasJsonAccessor.formatEasJsonPath(configureParams.projectDir))) {
return false;
}
@@ -106,9 +102,5 @@ 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')}. ${learnMore(
'https://docs.expo.dev/build-reference/eas-json/'
)}`
);
Log.withTick(`Generated ${chalk.bold('eas.json')}`);
}
-2
View File
@@ -15,5 +15,3 @@ export class RequestValidationError extends EasCommandError {}
export class EasBuildDownForMaintenanceError extends EasCommandError {}
export class EasBuildTooManyPendingBuildsError extends EasCommandError {}
export class EasBuildProjectArchiveUploadError extends EasCommandError {}
+1 -1
View File
@@ -6,7 +6,7 @@ import semver from 'semver';
import { ora } from '../ora';
const PLUGIN_PACKAGE_NAME = 'eas-cli-local-build-plugin';
const PLUGIN_PACKAGE_VERSION = '1.0.24';
const PLUGIN_PACKAGE_VERSION = '1.0.18';
export enum LocalBuildMode {
/**
-1
View File
@@ -132,7 +132,6 @@ 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
@@ -37,12 +37,7 @@ import {
} from '../project/customBuildConfig';
import { checkExpoSdkIsSupportedAsync } from '../project/expoSdk';
import { validateMetroConfigForManagedWorkflowAsync } from '../project/metroConfig';
import {
installExpoUpdatesAsync,
isExpoUpdatesInstalledAsDevDependency,
isExpoUpdatesInstalledOrAvailable,
validateAppVersionRuntimePolicySupportAsync,
} from '../project/projectUtils';
import { validateAppVersionRuntimePolicySupportAsync } from '../project/projectUtils';
import {
validateAppConfigForRemoteVersionSource,
validateBuildProfileVersionSettings,
@@ -311,14 +306,6 @@ 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) {
@@ -438,40 +425,3 @@ 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');
}
}
}
@@ -203,8 +203,6 @@ export default abstract class EasCommand extends Command {
Log.error(err.message);
}
Log.debug(err);
const sanitizedError = new Error(baseMessage);
sanitizedError.stack = err.stack;
throw sanitizedError;
throw new Error(baseMessage);
}
}
@@ -1,4 +1,4 @@
import { getProjectConfigDescription } from '@expo/config';
import { getProjectConfigDescription, modifyConfigAsync } 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 { createOrModifyExpoConfigAsync, getPrivateExpoConfig } from '../../../project/expoConfig';
import { 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 createOrModifyExpoConfigAsync(
const result = await modifyConfigAsync(
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 -17
View File
@@ -1,5 +1,3 @@
import { Flags } from '@oclif/core';
import EasCommand from '../../commandUtils/EasCommand';
import Log from '../../log';
@@ -7,27 +5,13 @@ 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({ sso });
await sessionManager.showLoginPromptAsync();
Log.log('Logged in');
}
}
@@ -7,11 +7,10 @@ import { ensureProjectConfiguredAsync } from '../../build/configure';
import EasCommand from '../../commandUtils/EasCommand';
import Log, { learnMore } from '../../log';
import { RequestedPlatform } from '../../platform';
import { isExpoUpdatesInstalled, isUsingEASUpdate } from '../../project/projectUtils';
import { isExpoUpdatesInstalled } from '../../project/projectUtils';
import { resolveWorkflowAsync } from '../../project/workflow';
import { promptAsync } from '../../prompts';
import { syncUpdatesConfigurationAsync as syncAndroidUpdatesConfigurationAsync } from '../../update/android/UpdatesModule';
import { ensureEASUpdateIsConfiguredInEasJsonAsync } from '../../update/configure';
import { syncUpdatesConfigurationAsync as syncIosUpdatesConfigurationAsync } from '../../update/ios/UpdatesModule';
import { getVcsClient } from '../../vcs';
@@ -58,13 +57,10 @@ export default class BuildConfigure extends EasCommand {
// ensure eas.json exists
Log.newLine();
const didCreateEasJson = await ensureProjectConfiguredAsync({
await ensureProjectConfiguredAsync({
projectDir,
nonInteractive: false,
});
if (didCreateEasJson && isUsingEASUpdate(exp, projectId)) {
await ensureEASUpdateIsConfiguredInEasJsonAsync(projectDir);
}
// configure expo-updates
if (expoUpdatesIsInstalled) {
+2 -3
View File
@@ -210,9 +210,8 @@ async function maybeGetBuildAsync(
},
paginatedQueryOptions,
selectPromptDisabledFunction: build => !isRunnableOnSimulatorOrEmulator(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.`,
selectPromptWarningMessage:
'Artifacts for this build have expired and are no longer available, or this is not a simulator/emulator build.',
});
return validateChosenBuild(build, flags.selectedPlatform);
} else if (flags.runArchiveFlags.latest) {
@@ -1,4 +1,4 @@
import { AppJSONConfig, PackageJSONConfig, getConfig } from '@expo/config';
import { AppJSONConfig, PackageJSONConfig, getConfig, modifyConfigAsync } from '@expo/config';
import chalk from 'chalk';
import { vol } from 'memfs';
import { instance, mock } from 'ts-mockito';
@@ -12,17 +12,12 @@ 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');
@@ -148,16 +143,13 @@ describe(ProjectInit.name, () => {
});
describe('force', () => {
beforeEach(() => {
it('does not prompt to overwrite when different', async () => {
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();
@@ -191,7 +183,7 @@ describe(ProjectInit.name, () => {
});
await new ProjectInit(['--id', '1234'], commandOptions).run();
expect(createOrModifyExpoConfigAsync).not.toHaveBeenCalled();
expect(modifyConfigAsync).not.toHaveBeenCalled();
});
it('prompts to configure if not consistent', async () => {
@@ -203,20 +195,14 @@ describe(ProjectInit.name, () => {
});
jest.mocked(confirmAsync).mockResolvedValue(true);
jest
.mocked(createOrModifyExpoConfigAsync)
.mockResolvedValue({ type: 'success', config: {} as any });
jest.mocked(modifyConfigAsync).mockResolvedValue({ type: 'success', config: {} as any });
await new ProjectInit(['--id', '1234'], commandOptions).run();
expect(confirmAsync).toHaveBeenCalled();
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledTimes(2);
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledWith('/test-project', {
owner: 'jester2',
});
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledWith('/test-project', {
slug: 'testing-124',
});
expect(modifyConfigAsync).toHaveBeenCalledTimes(2);
expect(modifyConfigAsync).toHaveBeenCalledWith('/test-project', { owner: 'jester2' });
expect(modifyConfigAsync).toHaveBeenCalledWith('/test-project', { slug: 'testing-124' });
});
it('overrides if force flag is present and it is not consistent', async () => {
@@ -227,20 +213,14 @@ describe(ProjectInit.name, () => {
ownerAccount: jester2.accounts[0],
});
jest
.mocked(createOrModifyExpoConfigAsync)
.mockResolvedValue({ type: 'success', config: {} as any });
jest.mocked(modifyConfigAsync).mockResolvedValue({ type: 'success', config: {} as any });
await new ProjectInit(['--id', '1234', '--force'], commandOptions).run();
expect(confirmAsync).not.toHaveBeenCalled();
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledTimes(2);
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledWith('/test-project', {
owner: 'jester2',
});
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledWith('/test-project', {
slug: 'testing-124',
});
expect(modifyConfigAsync).toHaveBeenCalledTimes(2);
expect(modifyConfigAsync).toHaveBeenCalledWith('/test-project', { owner: 'jester2' });
expect(modifyConfigAsync).toHaveBeenCalledWith('/test-project', { slug: 'testing-124' });
});
it('throws if non-interactive is present and it is not consistent', async () => {
@@ -251,9 +231,7 @@ describe(ProjectInit.name, () => {
ownerAccount: jester2.accounts[0],
});
jest
.mocked(createOrModifyExpoConfigAsync)
.mockResolvedValue({ type: 'success', config: {} as any });
jest.mocked(modifyConfigAsync).mockResolvedValue({ type: 'success', config: {} as any });
await expect(
new ProjectInit(['--id', '1234', '--non-interactive'], commandOptions).run()
@@ -262,7 +240,7 @@ describe(ProjectInit.name, () => {
);
expect(confirmAsync).not.toHaveBeenCalled();
expect(createOrModifyExpoConfigAsync).not.toHaveBeenCalled();
expect(modifyConfigAsync).not.toHaveBeenCalled();
});
});
});
@@ -293,7 +271,7 @@ describe(ProjectInit.name, () => {
});
await new ProjectInit(['--id', '1234'], commandOptions).run();
expect(createOrModifyExpoConfigAsync).not.toHaveBeenCalled();
expect(modifyConfigAsync).not.toHaveBeenCalled();
});
it('prompts to configure if not consistent', async () => {
@@ -307,20 +285,14 @@ describe(ProjectInit.name, () => {
});
jest.mocked(confirmAsync).mockResolvedValue(true);
jest
.mocked(createOrModifyExpoConfigAsync)
.mockResolvedValue({ type: 'success', config: {} as any });
jest.mocked(modifyConfigAsync).mockResolvedValue({ type: 'success', config: {} as any });
await new ProjectInit(['--id', '1234'], commandOptions).run();
expect(confirmAsync).toHaveBeenCalled();
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledTimes(2);
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledWith('/test-project', {
owner: 'jester2',
});
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledWith('/test-project', {
slug: 'testing-124',
});
expect(modifyConfigAsync).toHaveBeenCalledTimes(2);
expect(modifyConfigAsync).toHaveBeenCalledWith('/test-project', { owner: 'jester2' });
expect(modifyConfigAsync).toHaveBeenCalledWith('/test-project', { slug: 'testing-124' });
});
it('overrides if force flag is present and it is not consistent', async () => {
@@ -333,20 +305,14 @@ describe(ProjectInit.name, () => {
ownerAccount: jester2.accounts[0],
});
jest
.mocked(createOrModifyExpoConfigAsync)
.mockResolvedValue({ type: 'success', config: {} as any });
jest.mocked(modifyConfigAsync).mockResolvedValue({ type: 'success', config: {} as any });
await new ProjectInit(['--id', '1234', '--force'], commandOptions).run();
expect(confirmAsync).not.toHaveBeenCalled();
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledTimes(2);
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledWith('/test-project', {
owner: 'jester2',
});
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledWith('/test-project', {
slug: 'testing-124',
});
expect(modifyConfigAsync).toHaveBeenCalledTimes(2);
expect(modifyConfigAsync).toHaveBeenCalledWith('/test-project', { owner: 'jester2' });
expect(modifyConfigAsync).toHaveBeenCalledWith('/test-project', { slug: 'testing-124' });
});
it('throws if non-interactive is present and it is not consistent', async () => {
@@ -359,9 +325,7 @@ describe(ProjectInit.name, () => {
ownerAccount: jester2.accounts[0],
});
jest
.mocked(createOrModifyExpoConfigAsync)
.mockResolvedValue({ type: 'success', config: {} as any });
jest.mocked(modifyConfigAsync).mockResolvedValue({ type: 'success', config: {} as any });
await expect(
new ProjectInit(['--id', '1234', '--non-interactive'], commandOptions).run()
@@ -370,7 +334,7 @@ describe(ProjectInit.name, () => {
);
expect(confirmAsync).not.toHaveBeenCalled();
expect(createOrModifyExpoConfigAsync).not.toHaveBeenCalled();
expect(modifyConfigAsync).not.toHaveBeenCalled();
});
});
});
@@ -403,20 +367,14 @@ describe(ProjectInit.name, () => {
});
jest.mocked(confirmAsync).mockResolvedValue(true);
jest
.mocked(createOrModifyExpoConfigAsync)
.mockResolvedValue({ type: 'success', config: {} as any });
jest.mocked(modifyConfigAsync).mockResolvedValue({ type: 'success', config: {} as any });
await new ProjectInit([], commandOptions).run();
expect(confirmAsync).toHaveBeenCalled();
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledTimes(2);
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledWith('/test-project', {
owner: 'jester2',
});
expect(createOrModifyExpoConfigAsync).toHaveBeenCalledWith('/test-project', {
slug: 'testing-124',
});
expect(modifyConfigAsync).toHaveBeenCalledTimes(2);
expect(modifyConfigAsync).toHaveBeenCalledWith('/test-project', { owner: 'jester2' });
expect(modifyConfigAsync).toHaveBeenCalledWith('/test-project', { slug: 'testing-124' });
});
});
@@ -1,4 +1,4 @@
import { getProjectConfigDescription } from '@expo/config';
import { getProjectConfigDescription, modifyConfigAsync } 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 { createOrModifyExpoConfigAsync, getPrivateExpoConfig } from '../../project/expoConfig';
import { 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 createOrModifyExpoConfigAsync(projectDir, modifications);
const result = await modifyConfigAsync(projectDir, modifications);
switch (result.type) {
case 'success':
break;
@@ -1,16 +1,14 @@
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, { learnMore } from '../../log';
import Log 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';
@@ -44,8 +42,6 @@ export default class UpdateConfigure extends EasCommand {
'💡 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.'
);
await getVcsClient().ensureRepoExistsAsync();
await ensureEASUpdateIsConfiguredAsync(graphqlClient, {
exp,
projectId,
@@ -58,14 +54,21 @@ export default class UpdateConfigure extends EasCommand {
Log.addNewLineIfNone();
Log.log(`🎉 Your app is configured with EAS Update!`);
Log.newLine();
const easJsonExists = await easJsonExistsAsync(projectDir);
if (!easJsonExists) {
Log.log(`- Run ${chalk.bold('eas build:configure')} to complete your installation`);
}
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:');
Log.log(
`- ${learnMore('https://docs.expo.dev/eas-update/introduction/', {
learnMoreMessage: 'Learn more about other capabilities of EAS Update',
})}`
`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.'
);
}
}
@@ -98,7 +98,6 @@ export default class UpdatePublish extends EasCommand {
required: false,
}),
message: Flags.string({
char: 'm',
description: 'A short message describing the update',
required: false,
}),
@@ -72,7 +72,6 @@ export default class UpdateRepublish extends EasCommand {
exclusive: ['branch', 'channel'],
}),
message: Flags.string({
char: 'm',
description: 'Short message describing the republished update',
required: false,
}),
@@ -151,7 +151,6 @@ 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,16 +146,6 @@ 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,
@@ -174,6 +164,14 @@ 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,
@@ -5,7 +5,6 @@ import gql from 'graphql-tag';
import { ExpoGraphqlClient } from '../../../../../commandUtils/context/contextUtils/createGraphqlClient';
import { withErrorHandlingAsync } from '../../../../../graphql/client';
import {
AndroidAppBuildCredentials,
AndroidAppBuildCredentialsFragment,
AndroidAppBuildCredentialsInput,
CreateAndroidAppBuildCredentialsMutation,
@@ -56,37 +55,6 @@ 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,
@@ -14,6 +14,7 @@ import {
} from '../../__tests__/fixtures-ios';
import IosCredentialsProvider from '../IosCredentialsProvider';
import { getAppLookupParamsFromContextAsync } from '../actions/BuildCredentialsUtils';
import { MissingCredentialsNonInteractiveError } from '../../errors';
jest.mock('fs');
jest.mock('../validators/validateProvisioningProfile', () => ({
@@ -76,7 +77,7 @@ describe(IosCredentialsProvider, () => {
distribution: 'store',
});
await expect(provider.getCredentialsAsync(CredentialsSource.REMOTE)).rejects.toThrowError(
/Credentials are not set up/
MissingCredentialsNonInteractiveError
);
});
@@ -23,6 +23,7 @@ export class CreateProvisioningProfile {
) {}
async runAsync(ctx: CredentialsContext): Promise<AppleProvisioningProfileMutationResult> {
// TODO: Remove this
if (ctx.nonInteractive) {
throw new MissingCredentialsNonInteractiveError(
'Creating Provisioning Profiles is only supported in interactive mode.'
@@ -2,11 +2,13 @@ import assert from 'assert';
import chalk from 'chalk';
import dateformat from 'dateformat';
import { formatAppleTeam } from './AppleTeamFormatting';
import { AccountFragment, AppleDistributionCertificateFragment } from '../../../graphql/generated';
import Log, { learnMore } from '../../../log';
import { promptAsync } from '../../../prompts';
import { fromNow } from '../../../utils/date';
import { CredentialsContext } from '../../context';
import { MissingCredentialsNonInteractiveError } from '../../errors';
import { askForUserProvidedAsync } from '../../utils/promptForCredentials';
import { AppLookupParams } from '../api/graphql/types/AppLookupParams';
import {
@@ -17,7 +19,6 @@ import { filterRevokedDistributionCertsFromEasServers } from '../appstore/Creden
import { AppleTooManyCertsError } from '../appstore/distributionCertificate';
import { distributionCertificateSchema } from '../credentials';
import { validateDistributionCertificateAsync } from '../validators/validateDistributionCertificate';
import { formatAppleTeam } from './AppleTeamFormatting';
export function formatDistributionCertificate(
distributionCertificate: AppleDistributionCertificateFragment,
@@ -212,7 +213,7 @@ async function generateDistributionCertificateAsync(
Log.warn(APPLE_DIST_CERTS_TOO_MANY_GENERATED_ERROR);
if (ctx.nonInteractive) {
throw new Error(
throw new MissingCredentialsNonInteractiveError(
"Start the CLI without the '--non-interactive' flag to revoke existing certificates."
);
}
@@ -48,14 +48,14 @@ export class SetUpDistributionCertificate {
}
private async runNonInteractiveAsync(
_ctx: CredentialsContext,
ctx: CredentialsContext,
currentCertificate: AppleDistributionCertificateFragment | null
): Promise<AppleDistributionCertificateFragment> {
// TODO: implement validation
Log.addNewLineIfNone();
Log.warn('Distribution Certificate is not validated for non-interactive builds.');
if (!currentCertificate) {
throw new MissingCredentialsNonInteractiveError();
return await this.createNewDistCertAsync(ctx);
}
return currentCertificate;
}
@@ -1,19 +1,5 @@
import nullthrows from 'nullthrows';
import {
AppleDistributionCertificateFragment,
AppleProvisioningProfileFragment,
IosAppBuildCredentialsFragment,
IosDistributionType,
} from '../../../graphql/generated';
import { getApplePlatformFromTarget } from '../../../project/ios/target';
import { confirmAsync } from '../../../prompts';
import { CredentialsContext } from '../../context';
import { MissingCredentialsNonInteractiveError } from '../../errors';
import { AppLookupParams } from '../api/graphql/types/AppLookupParams';
import { ProvisioningProfileStoreInfo } from '../appstore/Credentials.types';
import { Target } from '../types';
import { validateProvisioningProfileAsync } from '../validators/validateProvisioningProfile';
import {
assignBuildCredentialsAsync,
getBuildCredentialsAsync,
@@ -23,6 +9,20 @@ import { ConfigureProvisioningProfile } from './ConfigureProvisioningProfile';
import { CreateProvisioningProfile } from './CreateProvisioningProfile';
import { formatProvisioningProfileFromApple } from './ProvisioningProfileUtils';
import { SetUpDistributionCertificate } from './SetUpDistributionCertificate';
import {
AppleDistributionCertificateFragment,
AppleProvisioningProfileFragment,
AppleTeamFragment,
IosAppBuildCredentialsFragment,
IosDistributionType,
} from '../../../graphql/generated';
import { getApplePlatformFromTarget } from '../../../project/ios/target';
import { confirmAsync } from '../../../prompts';
import { CredentialsContext } from '../../context';
import { AppLookupParams } from '../api/graphql/types/AppLookupParams';
import { ProvisioningProfileStoreInfo } from '../appstore/Credentials.types';
import { Target } from '../types';
import { validateProvisioningProfileAsync } from '../validators/validateProvisioningProfile';
/**
* Sets up either APP_STORE or ENTERPRISE provisioning profiles
@@ -47,6 +47,7 @@ export class SetUpProvisioningProfile {
const buildCredentials = await this.createAndAssignProfileAsync(ctx, distCert);
// delete 'currentProfile' since its no longer valid
await ctx.ios.deleteProvisioningProfilesAsync(ctx.graphqlClient, [currentProfile.id]);
await ctx.appStore.revokeProvisioningProfileAsync(this.app.bundleIdentifier, currentProfile.id);
return buildCredentials;
}
@@ -59,12 +60,17 @@ export class SetUpProvisioningProfile {
this.target,
distCert
).runAsync(ctx);
const appleTeam: AppleTeamFragment = nullthrows(
distCert.appleTeam ?? provisioningProfile.appleTeam ?? null
);
return await assignBuildCredentialsAsync(
ctx,
this.app,
this.distributionType,
distCert,
provisioningProfile
provisioningProfile,
appleTeam ?? undefined
);
}
@@ -102,11 +108,6 @@ export class SetUpProvisioningProfile {
if (areBuildCredentialsSetup) {
return nullthrows(await getBuildCredentialsAsync(ctx, this.app, this.distributionType));
}
if (ctx.nonInteractive) {
throw new MissingCredentialsNonInteractiveError(
'Provisioning profile is not configured correctly. Run this command again in interactive mode.'
);
}
const currentProfile = await getProvisioningProfileAsync(ctx, this.app, this.distributionType);
if (!currentProfile) {
@@ -114,7 +115,8 @@ export class SetUpProvisioningProfile {
}
// See if the profile we have exists on the Apple Servers
const applePlatform = await getApplePlatformFromTarget(this.target);
const applePlatform = getApplePlatformFromTarget(this.target);
// TODO: Could it ask for login in non-interactive mode?
const existingProfiles = await ctx.appStore.listProvisioningProfilesAsync(
this.app.bundleIdentifier,
applePlatform
@@ -127,6 +129,11 @@ export class SetUpProvisioningProfile {
return await this.assignNewAndDeleteOldProfileAsync(ctx, distCert, currentProfile);
}
// TODO: Should we instead reuse original profile?
if (ctx.nonInteractive) {
return await this.assignNewAndDeleteOldProfileAsync(ctx, distCert, currentProfile);
}
const confirm = await confirmAsync({
message: `${formatProvisioningProfileFromApple(
currentProfileFromServer
@@ -12,14 +12,24 @@ import {
testAppleAppIdentifierFragment,
testCommonIosAppCredentialsFragment,
testIosAppBuildCredentialsFragment,
testProvisioningProfileFragment,
testTarget,
testTargets,
} from '../../../__tests__/fixtures-ios';
import { MissingCredentialsNonInteractiveError } from '../../../errors';
// import { MissingCredentialsNonInteractiveError } from '../../../errors';
import { validateProvisioningProfileAsync } from '../../validators/validateProvisioningProfile';
import { getAppLookupParamsFromContextAsync } from '../BuildCredentialsUtils';
import * as BuildCredentialsUtils from '../BuildCredentialsUtils';
import {
getAppLookupParamsFromContextAsync,
// getProvisioningProfileAsync,
} from '../BuildCredentialsUtils';
import { SetUpProvisioningProfile } from '../SetUpProvisioningProfile';
import { MissingCredentialsNonInteractiveError } from '../../../errors';
const getProvisioningProfileAsync = jest.spyOn(
BuildCredentialsUtils,
'getProvisioningProfileAsync'
);
jest.mock('../../../../prompts');
jest.mocked(confirmAsync).mockImplementation(async () => true);
jest.mock('../SetUpDistributionCertificate');
@@ -181,10 +191,172 @@ describe('SetUpProvisioningProfile', () => {
// expect provisioning profile not to be deleted on expo servers
expect(jest.mocked(ctx.ios.deleteProvisioningProfilesAsync).mock.calls.length).toBe(0);
});
it('errors in Non Interactive Mode', async () => {
it('repairs existing Provisioning Profile with bad build credentials in Non Interactive Mode', async () => {
jest.mocked(validateProvisioningProfileAsync).mockImplementation(async () => false);
const ctx = createCtxMock({
nonInteractive: true,
appStore: {
...getAppstoreMock(),
ensureAuthenticatedAsync: jest.fn(() => testAuthCtx),
authCtx: testAuthCtx,
listProvisioningProfilesAsync: jest.fn(() => [
{
provisioningProfileId: nullthrows(
testCommonIosAppCredentialsFragment.iosAppBuildCredentialsList[0].provisioningProfile
).developerPortalIdentifier,
},
]),
},
ios: {
...getNewIosApiMock(),
getIosAppCredentialsWithBuildCredentialsAsync: jest.fn(
() => testCommonIosAppCredentialsFragment
),
createOrGetExistingAppleAppIdentifierAsync: jest.fn(() => testAppleAppIdentifierFragment),
createOrUpdateIosAppBuildCredentialsAsync: jest.fn(
() => testIosAppBuildCredentialsFragment
),
},
});
const appLookupParams = await getAppLookupParamsFromContextAsync(
ctx,
findApplicationTarget(testTargets)
);
const setupProvisioningProfileAction = new SetUpProvisioningProfile(
appLookupParams,
testTarget,
IosDistributionType.AppStore
);
await setupProvisioningProfileAction.runAsync(ctx);
// expect build credentials to be created or updated on expo servers
expect(jest.mocked(ctx.ios.createOrUpdateIosAppBuildCredentialsAsync).mock.calls.length).toBe(
1
);
// expect provisioning profile to be deleted from expo servers
expect(jest.mocked(ctx.ios.deleteProvisioningProfilesAsync).mock.calls.length).toBe(1);
});
it('sets up a new Provisioning Profile with bad build credentials in Non Interactive Mode', async () => {
jest.mocked(validateProvisioningProfileAsync).mockImplementation(async () => false);
const ctx = createCtxMock({
nonInteractive: true,
appStore: {
...getAppstoreMock(),
ensureAuthenticatedAsync: jest.fn(() => testAuthCtx),
authCtx: testAuthCtx,
listProvisioningProfilesAsync: jest.fn(() => []),
},
ios: {
...getNewIosApiMock(),
getIosAppCredentialsWithBuildCredentialsAsync: jest.fn(
() => testCommonIosAppCredentialsFragment
),
createOrGetExistingAppleAppIdentifierAsync: jest.fn(() => testAppleAppIdentifierFragment),
},
});
const appLookupParams = await getAppLookupParamsFromContextAsync(
ctx,
findApplicationTarget(testTargets)
);
const setupProvisioningProfileAction = new SetUpProvisioningProfile(
appLookupParams,
testTarget,
IosDistributionType.AppStore
);
await setupProvisioningProfileAction.runAsync(ctx);
// expect build credentials to be created or updated on expo servers
expect(jest.mocked(ctx.ios.createOrUpdateIosAppBuildCredentialsAsync).mock.calls.length).toBe(
1
);
// expect provisioning profile to be deleted on expo servers
expect(jest.mocked(ctx.ios.deleteProvisioningProfilesAsync).mock.calls.length).toBe(1);
});
it('skips setting up a Provisioning Profile with prior build credentials configured properly in Non Interactive Mode', async () => {
jest.mocked(validateProvisioningProfileAsync).mockImplementation(async () => true);
const ctx = createCtxMock({
nonInteractive: true,
appStore: {
...getAppstoreMock(),
ensureAuthenticatedAsync: jest.fn(() => testAuthCtx),
authCtx: testAuthCtx,
//listProvisioningProfilesAsync: jest.fn(() => []),
},
ios: {
...getNewIosApiMock(),
getIosAppCredentialsWithBuildCredentialsAsync: jest.fn(
() => testCommonIosAppCredentialsFragment
),
createOrGetExistingAppleAppIdentifierAsync: jest.fn(() => testAppleAppIdentifierFragment),
},
});
const appLookupParams = await getAppLookupParamsFromContextAsync(
ctx,
findApplicationTarget(testTargets)
);
const setupProvisioningProfileAction = new SetUpProvisioningProfile(
appLookupParams,
testTarget,
IosDistributionType.AppStore
);
await setupProvisioningProfileAction.runAsync(ctx);
// expect build credentials not to be created or updated on expo servers
expect(jest.mocked(ctx.ios.createOrUpdateIosAppBuildCredentialsAsync).mock.calls.length).toBe(
0
);
// expect provisioning profile not to be deleted on expo servers
expect(jest.mocked(ctx.ios.deleteProvisioningProfilesAsync).mock.calls.length).toBe(0);
});
it('sets up a Provisioning Profile with no prior build credentials configured in Non Interactive Mode', async () => {
jest.mocked(validateProvisioningProfileAsync).mockImplementation(async () => false);
const ctx = createCtxMock({
nonInteractive: true,
appStore: {
...getAppstoreMock(),
ensureAuthenticatedAsync: jest.fn(() => testAuthCtx),
authCtx: testAuthCtx,
},
ios: {
...getNewIosApiMock(),
createOrGetExistingAppleAppIdentifierAsync: jest.fn(() => testAppleAppIdentifierFragment),
},
});
const appLookupParams = await getAppLookupParamsFromContextAsync(
ctx,
findApplicationTarget(testTargets)
);
const setupProvisioningProfileAction = new SetUpProvisioningProfile(
appLookupParams,
testTarget,
IosDistributionType.AppStore
);
await setupProvisioningProfileAction.runAsync(ctx);
// expect build credentials to be created or updated on expo servers
expect(jest.mocked(ctx.ios.createOrUpdateIosAppBuildCredentialsAsync).mock.calls.length).toBe(
1
);
// expect provisioning profile not to be deleted on expo servers
expect(jest.mocked(ctx.ios.deleteProvisioningProfilesAsync).mock.calls.length).toBe(0);
});
it.only('errors in Non Interactive Mode if not authenticated with App Store', async () => {
jest.mocked(validateProvisioningProfileAsync).mockImplementation(async () => false);
jest
.mocked(getProvisioningProfileAsync)
.mockImplementation(async () => testProvisioningProfileFragment);
const ctx = createCtxMock({
nonInteractive: true,
appStore: {
...getAppstoreMock(),
ensureAuthenticatedAsync: jest.fn(() => null),
authCtx: null,
},
ios: {
...getNewIosApiMock(),
createOrGetExistingAppleAppIdentifierAsync: jest.fn(() => testAppleAppIdentifierFragment),
},
});
const appLookupParams = await getAppLookupParamsFromContextAsync(
ctx,
@@ -198,12 +370,5 @@ describe('SetUpProvisioningProfile', () => {
await expect(setupProvisioningProfileAction.runAsync(ctx)).rejects.toThrowError(
MissingCredentialsNonInteractiveError
);
// expect build credentials not to be created or updated on expo servers
expect(jest.mocked(ctx.ios.createOrUpdateIosAppBuildCredentialsAsync).mock.calls.length).toBe(
0
);
// expect provisioning profile not to be deleted on expo servers
expect(jest.mocked(ctx.ios.deleteProvisioningProfilesAsync).mock.calls.length).toBe(0);
});
});
@@ -160,11 +160,10 @@ export default class AppStoreApi {
public async revokeProvisioningProfileAsync(
bundleIdentifier: string,
applePlatform: ApplePlatform,
profileClass?: ProfileClass
profileId: string
): Promise<void> {
const ctx = await this.ensureAuthenticatedAsync();
return await revokeProvisioningProfileAsync(ctx, bundleIdentifier, applePlatform, profileClass);
return await revokeProvisioningProfileAsync(ctx, bundleIdentifier, profileId);
}
public async createOrReuseAdhocProvisioningProfileAsync(
@@ -513,20 +513,6 @@ 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
@@ -712,36 +698,6 @@ 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?
@@ -243,20 +243,18 @@ export async function createProvisioningProfileAsync(
export async function revokeProvisioningProfileAsync(
authCtx: AuthCtx,
bundleIdentifier: string,
applePlatform: ApplePlatform,
profileClass: ProfileClass = ProfileClass.General
profileId: string
): Promise<void> {
const spinner = ora(`Revoking Apple provisioning profile`).start();
try {
const context = getRequestContext(authCtx);
const profiles = await getProfilesForBundleIdAsync(context, bundleIdentifier);
const profileType = resolveProfileType(applePlatform, profileClass, authCtx.team.inHouse);
await Promise.all(
profiles
.filter(profile => profile.attributes.profileType === profileType)
.map(profile => Profile.deleteAsync(context, { id: profile.id }))
);
const profile = profiles.find(profile => profile.id === profileId);
// TODO: See if we can just deleteAsync
if (profile) {
await Profile.deleteAsync(context, { id: profile.id });
}
spinner.succeed('Revoked Apple provisioning profile');
} catch (error) {
spinner.fail('Failed to revoke Apple provisioning profile');
@@ -18,7 +18,6 @@ export enum AndroidActionType {
GoBackToCaller,
GoBackToHighLevelActions,
CreateKeystore,
SetDefaultKeystore,
DownloadKeystore,
RemoveKeystore,
CreateFcm,
@@ -52,11 +52,6 @@ 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',
@@ -1,42 +0,0 @@
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,6 +14,7 @@ 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';
@@ -35,11 +36,13 @@ import {
gsaKeyActions,
highLevelActions,
} from './AndroidActions';
import { CreateAndroidBuildCredentials } from './CreateAndroidBuildCredentials';
import { Action, PressAnyKeyToContinue } from './HelperActions';
import { SelectExistingAndroidBuildCredentials } from './SelectAndroidBuildCredentials';
import {
SelectAndroidBuildCredentials,
SelectAndroidBuildCredentialsResultType,
SelectExistingAndroidBuildCredentials,
} from './SelectAndroidBuildCredentials';
import { SelectBuildProfileFromEasJson } from './SelectBuildProfileFromEasJson';
import { SetDefaultAndroidKeystore } from './SetDefaultAndroidKeystore';
export class ManageAndroid {
constructor(private callingAction: Action, private projectDir: string) {}
@@ -160,9 +163,31 @@ export class ManageAndroid {
);
const appLookupParams = await getAppLookupParamsFromContextAsync(ctx, gradleContext);
if (action === AndroidActionType.CreateKeystore) {
await new CreateAndroidBuildCredentials(appLookupParams).runAsync(ctx);
} else if (action === AndroidActionType.SetDefaultKeystore) {
await new SetDefaultAndroidKeystore(appLookupParams).runAsync(ctx);
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,
}
);
}
} else if (action === AndroidActionType.DownloadKeystore) {
const buildCredentials = await new SelectExistingAndroidBuildCredentials(
appLookupParams
@@ -1,45 +0,0 @@
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,
});
}
}
+13 -65
View File
@@ -1164,7 +1164,6 @@ 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']>;
};
@@ -1364,7 +1363,6 @@ export type AppInput = {
export type AppInsights = {
__typename?: 'AppInsights';
hasEventsFromExpoInsightsClientModule: Scalars['Boolean'];
totalUniqueUsers?: Maybe<Scalars['Int']>;
uniqueUsersByAppVersionOverTime: UniqueUsersOverTimeData;
uniqueUsersByPlatformOverTime: UniqueUsersOverTimeData;
@@ -1982,43 +1980,6 @@ 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 */
@@ -2519,10 +2480,6 @@ export type Card = {
last4?: Maybe<Scalars['String']>;
};
export type ChannelFilterInput = {
searchTerm?: InputMaybe<Scalars['String']>;
};
export type Charge = {
__typename?: 'Charge';
amount: Scalars['Int'];
@@ -3054,8 +3011,8 @@ export enum GitHubAppInstallationStatus {
export type GitHubAppMutation = {
__typename?: 'GitHubAppMutation';
/** 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;
/** Create a GitHub build for an app */
createGitHubBuild: Scalars['Boolean'];
};
@@ -4165,7 +4122,6 @@ 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. */
@@ -4265,7 +4221,6 @@ 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>;
@@ -4283,14 +4238,11 @@ 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 */
@@ -4298,7 +4250,6 @@ 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'];
};
@@ -4340,7 +4291,11 @@ 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 = {
@@ -4793,7 +4748,6 @@ export type Update = ActivityTimelineProjectActivity & {
export type UpdateBranch = {
__typename?: 'UpdateBranch';
app: App;
appId: Scalars['ID'];
createdAt: Scalars['DateTime'];
id: Scalars['ID'];
@@ -4855,7 +4809,6 @@ export type UpdateBranchMutationPublishUpdateGroupsArgs = {
export type UpdateChannel = {
__typename?: 'UpdateChannel';
app: App;
appId: Scalars['ID'];
branchMapping: Scalars['String'];
createdAt: Scalars['DateTime'];
@@ -5007,7 +4960,6 @@ 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>;
@@ -5027,19 +4979,16 @@ 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 No longer supported */
/** @deprecated This field no longer exists */
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. */
@@ -5051,7 +5000,6 @@ 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'];
};
@@ -5102,7 +5050,6 @@ 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>;
@@ -5124,14 +5071,11 @@ 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 */
@@ -5139,7 +5083,6 @@ 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'];
};
@@ -5198,12 +5141,17 @@ 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']>;
};
@@ -6208,7 +6156,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, 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 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 WebhooksByAppIdQueryVariables = Exact<{
appId: Scalars['String'];
@@ -16,7 +16,7 @@ export const UserQuery = {
meActor {
__typename
id
... on UserActor {
... on User {
username
primaryAccount {
id
@@ -26,6 +26,9 @@ export const UserQuery = {
... on Robot {
firstName
}
... on SSOUser {
username
}
accounts {
id
...AccountFragment
@@ -38,7 +41,7 @@ export const UserQuery = {
`,
{},
{
additionalTypenames: ['User', 'SSOUser'],
additionalTypenames: ['User'],
}
)
.toPromise()
@@ -1,62 +0,0 @@
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' });
});
});
});
+1 -66
View File
@@ -1,9 +1,5 @@
import { ExpoConfig, getConfig, getConfigFilePaths, modifyConfigAsync } from '@expo/config';
import { ExpoConfig, getConfig } 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 path from 'path';
export type PublicExpoConfig = Omit<
ExpoConfig,
@@ -23,21 +19,6 @@ 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 = {}
@@ -52,65 +33,19 @@ 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> {
const paths = getConfigFilePaths(projectDir);
if (paths?.staticConfigPath?.endsWith('app.json') && !paths?.dynamicConfigPath) {
const staticConfig = await JsonFile.readAsync(paths.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(paths.staticConfigPath, staticConfig);
}
}
}
export function getPublicExpoConfig(
projectDir: string,
opts: ExpoConfigOptions = {}
): PublicExpoConfig {
ensureExpoConfigExists(projectDir);
return getExpoConfigInternal(projectDir, { ...opts, isPublicConfig: true });
}
+2 -19
View File
@@ -5,7 +5,6 @@ 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';
@@ -17,8 +16,6 @@ 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) {
@@ -28,6 +25,8 @@ 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.');
}
}
@@ -67,11 +66,6 @@ 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
@@ -84,17 +78,6 @@ export function isExpoUpdatesInstalledOrAvailable(
return isExpoUpdatesInstalled(projectDir);
}
/**
* Projects on SDK 49 are required to set `updates.useClassicUpdates` to `true` to use Classic Updates.
*/
export function isDefinitelyUsingClassicUpdates(exp: ExpoConfig): boolean {
return !!exp.updates?.useClassicUpdates;
}
export function isUsingEASUpdate(exp: ExpoConfig, projectId: string): boolean {
return exp.updates?.url === getEASUpdateURL(projectId);
}
export async function validateAppVersionRuntimePolicySupportAsync(
projectDir: string,
exp: ExpoConfig
@@ -94,7 +94,6 @@ 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',
@@ -110,7 +109,6 @@ 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',
@@ -142,7 +140,6 @@ 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',
+20 -43
View File
@@ -1,3 +1,4 @@
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';
@@ -9,11 +10,8 @@ import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGr
import { AppPlatform } from '../graphql/generated';
import Log, { learnMore } from '../log';
import { RequestedPlatform, appPlatformDisplayNames } from '../platform';
import { createOrModifyExpoConfigAsync } from '../project/expoConfig';
import {
installExpoUpdatesAsync,
isDefinitelyUsingClassicUpdates,
isExpoUpdatesInstalledAsDevDependency,
isExpoUpdatesInstalledOrAvailable,
} from '../project/projectUtils';
import { resolveWorkflowPerPlatformAsync } from '../project/workflow';
@@ -97,10 +95,6 @@ async function ensureEASUpdatesIsConfiguredInExpoConfigAsync({
}): Promise<{ projectChanged: boolean; exp: ExpoConfig }> {
const modifyConfig: Partial<ExpoConfig> = {};
if (isDefinitelyUsingClassicUpdates(exp)) {
modifyConfig.updates = { useClassicUpdates: false };
}
if (exp.updates?.url !== getEASUpdateURL(projectId)) {
modifyConfig.updates = { url: getEASUpdateURL(projectId) };
}
@@ -134,7 +128,7 @@ async function ensureEASUpdatesIsConfiguredInExpoConfigAsync({
}
const mergedExp = mergeExpoConfig(exp, modifyConfig);
const result = await createOrModifyExpoConfigAsync(projectDir, mergedExp);
const result = await modifyConfigAsync(projectDir, mergedExp);
switch (result.type) {
case 'success':
@@ -166,12 +160,6 @@ function logEasUpdatesAutoConfig({
modifyConfig: Partial<ExpoConfig>;
exp: ExpoConfig;
}): void {
if (modifyConfig.updates?.useClassicUpdates === false) {
Log.withTick(
`Configured updates.useClassicUpdates to "${modifyConfig.updates?.useClassicUpdates}". You cannot use EAS Update and Classic Updates at the same time.`
);
}
if (modifyConfig.updates?.url) {
Log.withTick(
exp.updates?.url
@@ -180,29 +168,22 @@ function logEasUpdatesAutoConfig({
);
}
const androidRuntime = modifyConfig.android?.runtimeVersion ?? modifyConfig.runtimeVersion;
const iosRuntime = modifyConfig.ios?.runtimeVersion ?? modifyConfig.runtimeVersion;
if (androidRuntime && iosRuntime && androidRuntime === iosRuntime) {
if (modifyConfig.android?.runtimeVersion ?? modifyConfig.runtimeVersion) {
Log.withTick(
`Configured runtimeVersion for ${appPlatformDisplayNames[AppPlatform.Android]} and ${
`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 ${
appPlatformDisplayNames[AppPlatform.Ios]
} with "${modifyConfig.android?.runtimeVersion ?? modifyConfig.runtimeVersion}"`
} with "${JSON.stringify(modifyConfig.ios?.runtimeVersion ?? modifyConfig.runtimeVersion)}"`
);
} else {
if (androidRuntime) {
Log.withTick(
`Configured runtimeVersion for ${appPlatformDisplayNames[AppPlatform.Android]} with "${
modifyConfig.android?.runtimeVersion ?? modifyConfig.runtimeVersion
}"`
);
}
if (iosRuntime) {
Log.withTick(
`Configured runtimeVersion for ${appPlatformDisplayNames[AppPlatform.Ios]} with "${
modifyConfig.ios?.runtimeVersion ?? modifyConfig.runtimeVersion
}"`
);
}
}
}
@@ -284,7 +265,9 @@ 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;
}
@@ -337,7 +320,6 @@ export async function ensureEASUpdateIsConfiguredInEasJsonAsync(projectDir: stri
* This goes over a checklist and performs the following checks or changes:
* - Enure the `expo-updates` package is currently installed.
* - Ensure `app.json` is configured for EAS Updates
* - Sets `useClassicUpdates` to false if set
* - Sets `runtimeVersion` if not set
* - Sets `updates.url` if not set
* - Ensure latest changes are reflected in the native config, if any
@@ -360,14 +342,9 @@ export async function ensureEASUpdateIsConfiguredAsync(
projectDir,
expWithoutUpdates.sdkVersion
);
const hasExpoUpdatesInDevDependencies = isExpoUpdatesInstalledAsDevDependency(projectDir);
if (!hasExpoUpdates && !hasExpoUpdatesInDevDependencies) {
if (!hasExpoUpdates) {
await installExpoUpdatesAsync(projectDir, { silent: false });
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.`
);
Log.withTick('Installed expo updates');
}
// Bail out if using a platform that doesn't require runtime versions
+2 -23
View File
@@ -13,7 +13,6 @@ 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 = {
@@ -26,7 +25,7 @@ type SessionData = {
// These fields are potentially used by Expo CLI.
userId: string;
username: string;
currentConnection: 'Username-Password-Authentication' | 'Browser-Flow-Authentication';
currentConnection: 'Username-Password-Authentication';
};
export enum UserSecondFactorDeviceMethod {
@@ -148,7 +147,6 @@ export default class SessionManager {
public async showLoginPromptAsync({
nonInteractive = false,
printNewLine = false,
sso = false,
} = {}): Promise<void> {
if (nonInteractive) {
Errors.error(
@@ -164,16 +162,7 @@ export default class SessionManager {
Log.newLine();
}
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)`
);
Log.log('Log in to EAS');
const { username, password } = await promptAsync([
{
@@ -205,16 +194,6 @@ 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;
+1 -1
View File
@@ -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, sso user or robot user.
* Resolve the name of the actor, either normal 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,7 +9,6 @@ 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');
@@ -25,7 +24,6 @@ jest.mock('../../graphql/queries/UserQuery', () => ({
},
}));
jest.mock('../fetchSessionSecretAndUser');
jest.mock('../fetchSessionSecretAndSsoUser');
jest.mock('../../api');
const authStub: any = {
@@ -156,29 +154,6 @@ 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({
@@ -255,45 +230,6 @@ 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,26 +21,6 @@ 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',
@@ -55,14 +35,10 @@ describe('getActorDisplayName', () => {
expect(getActorDisplayName()).toBe('unknown');
});
it('returns username for regular user actors', () => {
it('returns username for 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)`);
});
+1 -1
View File
@@ -2,7 +2,7 @@ import { AccountFragment } from '../graphql/generated';
import { Actor } from './User';
export function ensureActorHasPrimaryAccount(user: Actor): AccountFragment {
if (user.__typename === 'User' || user.__typename === 'SSOUser') {
if (user.__typename === 'User') {
return user.primaryAccount;
}
throw new Error('This action is not supported for robot users.');
@@ -1,80 +0,0 @@
import openBrowserAsync from 'better-opn';
import http from 'http';
import { Socket } from 'node:net';
import querystring from 'querystring';
import Log from '../log';
export async function getSessionUsingBrowserAuthFlowAsync(options: {
expoWebsiteUrl: string;
serverPort: number;
}): Promise<string> {
const { expoWebsiteUrl, serverPort } = options;
if (!expoWebsiteUrl || !serverPort) {
throw new Error('Expo website URL and local server port are required.');
}
const scheme = 'http';
const hostname = 'localhost';
const path = '/auth/callback';
const redirectUri = `${scheme}://${hostname}:${serverPort}${path}`;
const buildExpoSsoLoginUrl = (): string => {
const data = {
app_redirect_uri: redirectUri,
};
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/plain' });
response.write(`Website login has completed. You can now close this tab.`);
response.end();
} catch (error) {
reject(error);
} finally {
server.close();
// Ensure that the server shuts down
for (const connection of connections) {
connection.destroy();
}
}
}
);
server.listen(serverPort, hostname, () => {
Log.log('Waiting for browser login...');
});
server.on('connection', connection => {
connections.add(connection);
connection.on('close', () => {
connections.delete(connection);
});
});
const authorizeUrl = buildExpoSsoLoginUrl();
openBrowserAsync(authorizeUrl);
});
};
return await executeAuthFlow();
}
@@ -1,23 +0,0 @@
import { getExpoWebsiteBaseUrl, getSsoLocalServerPortAsync } from '../api';
import { getSessionUsingBrowserAuthFlowAsync } from './expoSsoLauncher';
import { fetchUserAsync } from './fetchUser';
export async function fetchSessionSecretAndSsoUserAsync(): Promise<{
sessionSecret: string;
id: string;
username: string;
}> {
const config = {
expoWebsiteUrl: getExpoWebsiteBaseUrl(),
serverPort: await getSsoLocalServerPortAsync(),
};
const sessionSecret = await getSessionUsingBrowserAuthFlowAsync(config);
const userData = await fetchUserAsync({ sessionSecret });
return {
sessionSecret,
id: userData.id,
username: userData.username,
};
}
@@ -1,5 +1,7 @@
import gql from 'graphql-tag';
import { ApiV2Client } from '../api';
import { fetchUserAsync } from './fetchUser';
import { createGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
export async function fetchSessionSecretAndUserAsync({
username,
@@ -19,10 +21,32 @@ export async function fetchSessionSecretAndUserAsync({
body: { username, password, otp },
});
const { sessionSecret } = body.data;
const userData = await fetchUserAsync({ sessionSecret });
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;
return {
sessionSecret,
id: userData.id,
username: userData.username,
id: data.viewer.id,
username: data.viewer.username,
};
}
-33
View File
@@ -1,33 +0,0 @@
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,
};
}
+3 -16
View File
@@ -5,7 +5,7 @@ import { boolish } from 'getenv';
import resolveFrom, { silent as silentResolveFrom } from 'resolve-from';
import semver from 'semver';
import Log, { link } from '../log';
import Log from '../log';
import { memoize } from './expodash/memoize';
// Aggressively returns `true` (UNVERSIONED, invalid SDK version format) to push users towards the versioned CLI.
@@ -63,21 +63,8 @@ export async function expoCommandAsync(
args: string[],
{ silent = false }: { silent?: boolean } = {}
): Promise<void> {
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 expoCliPath =
silentResolveFrom(projectDir, 'expo/bin/cli') ?? resolveFrom(projectDir, 'expo/bin/cli.js');
const spawnPromise = spawnAsync(expoCliPath, args, {
stdio: ['inherit', 'pipe', 'pipe'], // inherit stdin so user can install a missing expo-cli from inside this command
});
-11
View File
@@ -1,11 +0,0 @@
import freeportAsync from 'freeport-async';
/** Get a free port or throw an error. */
export async function getFreePortAsync(rangeStart: number): Promise<number> {
const port = await freeportAsync(rangeStart, { hostnames: [null, 'localhost'] });
if (!port) {
throw new Error('No available port found');
}
return port;
}
+1 -1
View File
@@ -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 requires you to use a git repository for your project.');
Log.warn('EAS Build requires you to use a git repository for your project.');
const cwd = process.cwd();
const repoRoot = PackageManagerUtils.findWorkspaceRoot(cwd) ?? cwd;
-8
View File
@@ -1,8 +0,0 @@
declare module 'freeport-async' {
interface FreePortOptions {
hostnames?: (string | null)[];
}
function freePortAsync(rangeStart: number, options?: FreePortOptions): Promise<number>;
export = freePortAsync;
}
Generated
+28 -121
View File
@@ -1324,10 +1324,10 @@
minimatch "^3.1.2"
strip-json-comments "^3.1.1"
"@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/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/bunyan@^4.0.0":
version "4.0.0"
@@ -1347,12 +1347,12 @@
node-forge "^1.2.1"
nullthrows "^1.1.1"
"@expo/config-plugins@7.2.3":
version "7.2.3"
resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-7.2.3.tgz#982800bf1aec3811f3e087a1e8784c82f0853672"
integrity sha512-8wBR4HH2PhPbupUNXCB1aslMD4vNYEnew26os1nCZ4vaUwcp0LeI9Zl2ycOCBVwGSdd5RNHFzK2R/OFE9P13tA==
"@expo/config-plugins@6.0.2":
version "6.0.2"
resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-6.0.2.tgz#cf07319515022ba94d9aa9fa30e0cff43a14256f"
integrity sha512-Cn01fXMHwjU042EgO9oO3Mna0o/UCrW91MQLMbJa4pXM41CYGjNgVy1EVXiuRRx/upegHhvltBw5D+JaUm8aZQ==
dependencies:
"@expo/config-types" "^49.0.0-alpha.1"
"@expo/config-types" "^48.0.0"
"@expo/json-file" "~8.2.37"
"@expo/plist" "^0.0.20"
"@expo/sdk-runtime-versions" "^1.0.0"
@@ -1363,10 +1363,10 @@
getenv "^1.0.0"
glob "7.1.6"
resolve-from "^5.0.0"
semver "^7.5.3"
semver "^7.3.5"
slash "^3.0.0"
xcode "^3.0.1"
xml2js "0.6.0"
xml2js "0.4.23"
"@expo/config-plugins@~5.0.3":
version "5.0.4"
@@ -1389,55 +1389,17 @@
xcode "^3.0.1"
xml2js "0.4.23"
"@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" "^49.0.0-alpha.1"
"@expo/json-file" "~8.2.37"
"@expo/plist" "^0.0.20"
"@expo/sdk-runtime-versions" "^1.0.0"
"@react-native/normalize-color" "^2.0.0"
chalk "^4.1.2"
debug "^4.3.1"
find-up "~5.0.0"
getenv "^1.0.0"
glob "7.1.6"
resolve-from "^5.0.0"
semver "^7.5.3"
slash "^3.0.0"
xcode "^3.0.1"
xml2js "0.6.0"
"@expo/[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-types@^47.0.0":
"@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@8.1.2":
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" "~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.5.3"
slugify "^1.3.4"
sucrase "^3.20.0"
"@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/config@~7.0.2":
"@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==
@@ -1488,7 +1450,7 @@
json5 "^1.0.1"
write-file-atomic "^2.3.0"
"@expo/[email protected]", "@expo/json-file@^8.2.37", "@expo/json-file@~8.2.37":
"@expo/[email protected]", "@expo/json-file@~8.2.37":
version "8.2.37"
resolved "https://registry.yarnpkg.com/@expo/json-file/-/json-file-8.2.37.tgz#9c02d3b42134907c69cc0a027b18671b69344049"
integrity sha512-YaH6rVg11JoTS2P6LsW7ybS2CULjf40AbnAHw2F1eDPuheprNjARZMnyHFPkKv7GuxCy+B9GPcbOKgc4cgA80Q==
@@ -1497,13 +1459,12 @@
json5 "^2.2.2"
write-file-atomic "^2.3.0"
"@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==
"@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==
dependencies:
"@types/bunyan" "^1.8.8"
bunyan "^1.8.15"
"@expo/bunyan" "^4.0.0"
"@expo/[email protected]":
version "1.1.0"
@@ -1644,12 +1605,12 @@
dependencies:
cross-spawn "^7.0.3"
"@expo/[email protected].23":
version "1.0.23"
resolved "https://registry.yarnpkg.com/@expo/steps/-/steps-1.0.23.tgz#a996244be55ae939636a00fdc27c9922bb4f0c42"
integrity sha512-H6rW49Dje0O/EDamhpbiYwpVltWM+057Exd7RFz8pzmPnkIAYHMXOErIftl3P79LM+ydWe5WWLX92cYU5uCFgA==
"@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==
dependencies:
"@expo/logger" "1.0.21"
"@expo/logger" "1.0.13"
"@expo/spawn-async" "^1.7.0"
arg "^5.0.2"
joi "^17.7.0"
@@ -4193,13 +4154,6 @@
"@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"
@@ -5423,16 +5377,6 @@ 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"
@@ -6585,13 +6529,6 @@ [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"
@@ -7518,11 +7455,6 @@ [email protected]:
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
[email protected]:
version "2.0.0"
resolved "https://registry.yarnpkg.com/freeport-async/-/freeport-async-2.0.0.tgz#6adf2ec0c629d11abff92836acd04b399135bab4"
integrity sha512-K7od3Uw45AJg00XUmy15+Hae2hOcgKcmN3/EF6Y7i01O0gaqiRx8sUSpsb9+BRNL8RPBrhzPsVfy8q9ADlJuWQ==
[email protected]:
version "0.5.2"
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
@@ -10369,11 +10301,6 @@ 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"
@@ -10423,11 +10350,6 @@ 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"
@@ -12151,13 +12073,6 @@ [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"
@@ -13860,14 +13775,6 @@ [email protected]:
sax ">=0.6.0"
xmlbuilder "~11.0.0"
[email protected]:
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"
xmlbuilder@^14.0.0:
version "14.0.0"
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-14.0.0.tgz#876b5aec4f05ffd5feb97b0a871c855d16fbeb8c"