mirror of
https://github.com/expo/eas-cli.git
synced 2026-11-13 20:28:08 -10:00
Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2889571fe | ||
|
|
224a5b288c | ||
|
|
16629e1ab5 | ||
|
|
d5a744b938 | ||
|
|
8f39b303c9 |
No files matched your search
@@ -29,7 +29,7 @@ jobs:
|
||||
with:
|
||||
node-version: 18
|
||||
- run: yarn install --frozen-lockfile --check-files
|
||||
- run: yarn build-ci
|
||||
- run: yarn build
|
||||
- name: Build tarballs
|
||||
working-directory: ${{ github.workspace }}/packages/eas-cli
|
||||
run: |
|
||||
@@ -70,7 +70,7 @@ jobs:
|
||||
with:
|
||||
node-version: 18
|
||||
- run: yarn install --frozen-lockfile --check-files
|
||||
- run: yarn build-ci
|
||||
- run: yarn build
|
||||
- name: Build tarballs
|
||||
working-directory: ${{ github.workspace }}/packages/eas-cli
|
||||
run: |
|
||||
@@ -99,7 +99,7 @@ jobs:
|
||||
node-version: 18
|
||||
- run: yarn install --frozen-lockfile --check-files
|
||||
- run: sudo apt-get install nsis
|
||||
- run: yarn build-ci
|
||||
- run: yarn build
|
||||
- run: |
|
||||
yarn pretarball-ci
|
||||
yarn oclif pack:win
|
||||
@@ -142,7 +142,7 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile --check-files
|
||||
- name: Build
|
||||
run: yarn build-ci
|
||||
run: yarn build
|
||||
- name: Publish packages to npm
|
||||
run: yarn lerna publish from-package --yes --no-verify-access
|
||||
env:
|
||||
|
||||
+3
-68
@@ -8,81 +8,16 @@ This is the log of notable changes to EAS CLI and related packages.
|
||||
|
||||
### 🎉 New features
|
||||
|
||||
- .nvmrc support for setting node version. ([#1954](https://github.com/expo/eas-cli/pull/1954) by [@khamilowicz](https://github.com/khamilowicz))
|
||||
- Provide credentials for custom Android builds. ([#1969](https://github.com/expo/eas-cli/pull/1969) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- More branch mapping utility. ([#1957](https://github.com/expo/eas-cli/pull/1957) by [@quinlanj](https://github.com/quinlanj))
|
||||
- Utility classes to select existing rollouts and channels. ([#1958](https://github.com/expo/eas-cli/pull/1958) by [@quinlanj](https://github.com/quinlanj))
|
||||
|
||||
## [3.17.1](https://github.com/expo/eas-cli/releases/tag/v3.17.1) - 2023-07-27
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Unify channel graphql query types. ([#1949](https://github.com/expo/eas-cli/pull/1949) by [@quinlanj](https://github.com/quinlanj))
|
||||
- Revert UpdateBranchWithCurrentGroupFragment. ([#1952](https://github.com/expo/eas-cli/pull/1952) by [@quinlanj](https://github.com/quinlanj))
|
||||
- Fetch entire relay compliant dataset. ([#1953](https://github.com/expo/eas-cli/pull/1953) by [@quinlanj](https://github.com/quinlanj))
|
||||
|
||||
## [3.17.0](https://github.com/expo/eas-cli/releases/tag/v3.17.0) - 2023-07-24
|
||||
|
||||
### 🎉 New features
|
||||
|
||||
- Add `rollout` option for configuring Android submissions. ([#1938](https://github.com/expo/eas-cli/pull/1938) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Added branch mapping utility functions. ([#1944](https://github.com/expo/eas-cli/pull/1944) by [@quinlanj](https://github.com/quinlanj))
|
||||
- Amend branch mapping utility functions. ([#1945](https://github.com/expo/eas-cli/pull/1945) by [@quinlanj](https://github.com/quinlanj))
|
||||
- Handle error thrown when `intel-medium` resource class is not available as server-side defined error. ([#1947](https://github.com/expo/eas-cli/pull/1947) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
- Remove `intel-medium` from `eas.schema.json`, so it's not suggested as a valid value by our VSCode plugin. ([#1947](https://github.com/expo/eas-cli/pull/1947) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
|
||||
## [3.16.0](https://github.com/expo/eas-cli/releases/tag/v3.16.0) - 2023-07-18
|
||||
|
||||
### 🎉 New features
|
||||
|
||||
- Add styling to SSO auth redirect completion page. ([#1929](https://github.com/expo/eas-cli/pull/1929) by [@wschurman](https://github.com/wschurman))
|
||||
- Ignore entitlements from native template when `/ios` is gitignored. ([#1906](https://github.com/expo/eas-cli/pull/1906) by [@byCedric](https://github.com/byCedric))
|
||||
- Use node server default port selection for SSO login server. ([#1930](https://github.com/expo/eas-cli/pull/1930) by [@wschurman](https://github.com/wschurman))
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
- Fix incorrect handling of valid `inProgress` Android submission release status. ([#1934](https://github.com/expo/eas-cli/pull/1934) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Print friendly error msg in case account doesn't have required permission. ([#1867](https://github.com/expo/eas-cli/pull/1867) by [@firasrg](https://github.com/firasrg))
|
||||
- Limit project file upload size to 2GB. ([#1928](https://github.com/expo/eas-cli/pull/1928) by [@khamilowicz](https://github.com/khamilowicz))
|
||||
- Bump urql graphql client major version. ([#1936](https://github.com/expo/eas-cli/pull/1936) by [@quinlanj](https://github.com/quinlanj))
|
||||
|
||||
## [3.15.1](https://github.com/expo/eas-cli/releases/tag/v3.15.1) - 2023-07-11
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
- Ensure useClassicUpdates is not set when using EAS Update commands. ([#1915](https://github.com/expo/eas-cli/pull/1915) by [@ide](https://github.com/ide))
|
||||
- Handle multiple GraphQLErrors when receiving a CombinedError. ([#1924](https://github.com/expo/eas-cli/pull/1924) by [@radoslawkrzemien](https://github.com/radoslawkrzemien))
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Bump Expo package dependencies. ([#1911](https://github.com/expo/eas-cli/pull/1911) by [@brentvatne](https://github.com/brentvatne))
|
||||
- Better bare workflow runtimeVersion error. ([#1910](https://github.com/expo/eas-cli/pull/1910) by [@quinlanj](https://github.com/quinlanj))
|
||||
- Fix runtime version print logs. ([#1925](https://github.com/expo/eas-cli/pull/1925) by [@quinlanj](https://github.com/quinlanj))
|
||||
- Add info about new `macos-ventura-13.4-xcode-14.3.1` image to `eas.schema.json`. ([#1920](https://github.com/expo/eas-cli/pull/1920) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
|
||||
## [3.15.0](https://github.com/expo/eas-cli/releases/tag/v3.15.0) - 2023-06-30
|
||||
|
||||
### 🎉 New features
|
||||
|
||||
- Show build profile when selecting a build for eas build:run. ([#1901](https://github.com/expo/eas-cli/pull/1901) by [@keith-kurak](https://github.com/keith-kurak))
|
||||
- Adds -m alias to --message in update/republish and removed README comment. ([#1905](https://github.com/expo/eas-cli/pull/1905) by [@pusongqi](https://github.com/pusongqi))
|
||||
|
||||
### 🐛 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))
|
||||
- Adds support for 2 new server-side errors related to build limits. ([#1921](https://github.com/expo/eas-cli/pull/1921) by [@sundeeppeswani](https://github.com/sundeeppeswani))
|
||||
- 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
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true,
|
||||
"version": "3.18.0",
|
||||
"version": "3.14.0",
|
||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json"
|
||||
}
|
||||
@@ -6,7 +6,6 @@
|
||||
],
|
||||
"scripts": {
|
||||
"build": "lerna run build",
|
||||
"build-ci": "lerna run build-ci",
|
||||
"build:tarballs:linux": "yarn build-for-size-check",
|
||||
"build-for-size-check": "yarn build && yarn workspace eas-cli pretarball-ci && CLI_SIZE_CHECK=1 yarn workspace eas-cli oclif pack:tarballs --no-xz --targets linux-x64",
|
||||
"typecheck": "lerna run typecheck",
|
||||
|
||||
+125
-123
@@ -55,68 +55,69 @@ 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`
|
||||
|
||||
@@ -133,7 +134,7 @@ ALIASES
|
||||
$ eas login
|
||||
```
|
||||
|
||||
_See code: [src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/account/login.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas account:logout`
|
||||
|
||||
@@ -150,7 +151,7 @@ ALIASES
|
||||
$ eas logout
|
||||
```
|
||||
|
||||
_See code: [src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/account/logout.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas account:view`
|
||||
|
||||
@@ -167,7 +168,7 @@ ALIASES
|
||||
$ eas whoami
|
||||
```
|
||||
|
||||
_See code: [src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/account/view.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas analytics [STATUS]`
|
||||
|
||||
@@ -181,7 +182,7 @@ DESCRIPTION
|
||||
display or change analytics settings
|
||||
```
|
||||
|
||||
_See code: [src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/analytics.ts)_
|
||||
_See code: [src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/analytics.ts)_
|
||||
|
||||
## `eas autocomplete [SHELL]`
|
||||
|
||||
@@ -231,7 +232,7 @@ DESCRIPTION
|
||||
create a branch
|
||||
```
|
||||
|
||||
_See code: [src/commands/branch/create.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/branch/create.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas branch:delete [NAME]`
|
||||
|
||||
@@ -252,7 +253,7 @@ DESCRIPTION
|
||||
delete a branch
|
||||
```
|
||||
|
||||
_See code: [src/commands/branch/delete.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/branch/delete.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas branch:list`
|
||||
|
||||
@@ -272,7 +273,7 @@ DESCRIPTION
|
||||
list all branches
|
||||
```
|
||||
|
||||
_See code: [src/commands/branch/list.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/branch/list.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas branch:rename`
|
||||
|
||||
@@ -292,7 +293,7 @@ DESCRIPTION
|
||||
rename a branch
|
||||
```
|
||||
|
||||
_See code: [src/commands/branch/rename.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/branch/rename.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas branch:view [NAME]`
|
||||
|
||||
@@ -315,7 +316,7 @@ DESCRIPTION
|
||||
view a branch
|
||||
```
|
||||
|
||||
_See code: [src/commands/branch/view.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/branch/view.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas build`
|
||||
|
||||
@@ -345,7 +346,7 @@ DESCRIPTION
|
||||
start a build
|
||||
```
|
||||
|
||||
_See code: [src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/build/index.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas build:cancel [BUILD_ID]`
|
||||
|
||||
@@ -362,7 +363,7 @@ DESCRIPTION
|
||||
cancel a build
|
||||
```
|
||||
|
||||
_See code: [src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/build/cancel.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas build:configure`
|
||||
|
||||
@@ -379,7 +380,7 @@ DESCRIPTION
|
||||
configure the project to support EAS Build
|
||||
```
|
||||
|
||||
_See code: [src/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/build/configure.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas build:inspect`
|
||||
|
||||
@@ -414,7 +415,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.18.0/packages/eas-cli/src/commands/build/inspect.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas build:list`
|
||||
|
||||
@@ -452,7 +453,7 @@ DESCRIPTION
|
||||
list all builds for your project
|
||||
```
|
||||
|
||||
_See code: [src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/build/list.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas build:resign`
|
||||
|
||||
@@ -478,7 +479,7 @@ DESCRIPTION
|
||||
re-sign a build archive
|
||||
```
|
||||
|
||||
_See code: [src/commands/build/resign.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/build/resign.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas build:run`
|
||||
|
||||
@@ -502,7 +503,7 @@ DESCRIPTION
|
||||
run simulator/emulator builds from eas-cli
|
||||
```
|
||||
|
||||
_See code: [src/commands/build/run.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/build/run.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas build:submit`
|
||||
|
||||
@@ -551,7 +552,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.18.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.14.0/packages/eas-cli/src/commands/build/version/get.ts)_
|
||||
|
||||
## `eas build:version:set`
|
||||
|
||||
@@ -570,7 +571,7 @@ DESCRIPTION
|
||||
update version of an app
|
||||
```
|
||||
|
||||
_See code: [src/commands/build/version/set.ts](https://github.com/expo/eas-cli/blob/v3.18.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.14.0/packages/eas-cli/src/commands/build/version/set.ts)_
|
||||
|
||||
## `eas build:version:sync`
|
||||
|
||||
@@ -589,7 +590,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.18.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.14.0/packages/eas-cli/src/commands/build/version/sync.ts)_
|
||||
|
||||
## `eas build:view [BUILD_ID]`
|
||||
|
||||
@@ -606,7 +607,7 @@ DESCRIPTION
|
||||
view a build for your project
|
||||
```
|
||||
|
||||
_See code: [src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/build/view.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas channel:create [NAME]`
|
||||
|
||||
@@ -627,7 +628,7 @@ DESCRIPTION
|
||||
create a channel
|
||||
```
|
||||
|
||||
_See code: [src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/channel/create.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas channel:edit [NAME]`
|
||||
|
||||
@@ -649,7 +650,7 @@ DESCRIPTION
|
||||
point a channel at a new branch
|
||||
```
|
||||
|
||||
_See code: [src/commands/channel/edit.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/channel/edit.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas channel:list`
|
||||
|
||||
@@ -669,7 +670,7 @@ DESCRIPTION
|
||||
list all channels
|
||||
```
|
||||
|
||||
_See code: [src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/channel/list.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas channel:rollout [CHANNEL]`
|
||||
|
||||
@@ -693,7 +694,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.18.0/packages/eas-cli/src/commands/channel/rollout.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas channel:view [NAME]`
|
||||
|
||||
@@ -716,7 +717,7 @@ DESCRIPTION
|
||||
view a channel
|
||||
```
|
||||
|
||||
_See code: [src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/channel/view.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas config`
|
||||
|
||||
@@ -737,7 +738,7 @@ DESCRIPTION
|
||||
display project configuration (app.json + eas.json)
|
||||
```
|
||||
|
||||
_See code: [src/commands/config.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/config.ts)_
|
||||
_See code: [src/commands/config.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/config.ts)_
|
||||
|
||||
## `eas credentials`
|
||||
|
||||
@@ -754,7 +755,7 @@ DESCRIPTION
|
||||
manage credentials
|
||||
```
|
||||
|
||||
_See code: [src/commands/credentials.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/credentials.ts)_
|
||||
_See code: [src/commands/credentials.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/credentials.ts)_
|
||||
|
||||
## `eas device:create`
|
||||
|
||||
@@ -768,7 +769,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.18.0/packages/eas-cli/src/commands/device/create.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas device:delete`
|
||||
|
||||
@@ -788,7 +789,7 @@ DESCRIPTION
|
||||
remove a registered device from your account
|
||||
```
|
||||
|
||||
_See code: [src/commands/device/delete.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/device/delete.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas device:list`
|
||||
|
||||
@@ -809,7 +810,7 @@ DESCRIPTION
|
||||
list all registered devices for your account
|
||||
```
|
||||
|
||||
_See code: [src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/device/list.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas device:rename`
|
||||
|
||||
@@ -830,7 +831,7 @@ DESCRIPTION
|
||||
rename a registered device
|
||||
```
|
||||
|
||||
_See code: [src/commands/device/rename.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/device/rename.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas device:view [UDID]`
|
||||
|
||||
@@ -844,7 +845,7 @@ DESCRIPTION
|
||||
view a device for your project
|
||||
```
|
||||
|
||||
_See code: [src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/device/view.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas diagnostics`
|
||||
|
||||
@@ -858,7 +859,7 @@ DESCRIPTION
|
||||
display environment info
|
||||
```
|
||||
|
||||
_See code: [src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/diagnostics.ts)_
|
||||
_See code: [src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/diagnostics.ts)_
|
||||
|
||||
## `eas help [COMMAND]`
|
||||
|
||||
@@ -946,7 +947,7 @@ DESCRIPTION
|
||||
validate the local store configuration
|
||||
```
|
||||
|
||||
_See code: [src/commands/metadata/lint.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/metadata/lint.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas metadata:pull`
|
||||
|
||||
@@ -963,7 +964,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.18.0/packages/eas-cli/src/commands/metadata/pull.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas metadata:push`
|
||||
|
||||
@@ -980,7 +981,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.18.0/packages/eas-cli/src/commands/metadata/push.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas open`
|
||||
|
||||
@@ -994,7 +995,7 @@ DESCRIPTION
|
||||
open the project page in a web browser
|
||||
```
|
||||
|
||||
_See code: [src/commands/open.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/open.ts)_
|
||||
_See code: [src/commands/open.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/open.ts)_
|
||||
|
||||
## `eas project:info`
|
||||
|
||||
@@ -1008,7 +1009,7 @@ DESCRIPTION
|
||||
information about the current project
|
||||
```
|
||||
|
||||
_See code: [src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/project/info.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas project:init`
|
||||
|
||||
@@ -1030,7 +1031,7 @@ ALIASES
|
||||
$ eas init
|
||||
```
|
||||
|
||||
_See code: [src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/project/init.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas secret:create`
|
||||
|
||||
@@ -1053,7 +1054,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.18.0/packages/eas-cli/src/commands/secret/create.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas secret:delete`
|
||||
|
||||
@@ -1071,7 +1072,7 @@ DESCRIPTION
|
||||
delete an environment secret by ID
|
||||
```
|
||||
|
||||
_See code: [src/commands/secret/delete.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/secret/delete.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas secret:list`
|
||||
|
||||
@@ -1085,7 +1086,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.18.0/packages/eas-cli/src/commands/secret/list.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas secret:push`
|
||||
|
||||
@@ -1105,7 +1106,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.18.0/packages/eas-cli/src/commands/secret/push.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas submit`
|
||||
|
||||
@@ -1135,7 +1136,7 @@ ALIASES
|
||||
$ eas build:submit
|
||||
```
|
||||
|
||||
_See code: [src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/submit.ts)_
|
||||
_See code: [src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v3.14.0/packages/eas-cli/src/commands/submit.ts)_
|
||||
|
||||
## `eas update`
|
||||
|
||||
@@ -1143,12 +1144,11 @@ publish an update group
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ eas update [--branch <value>] [--channel <value>] [-m <value>] [--republish | --input-dir <value> |
|
||||
--skip-bundler] [--group <value> | | ] [--clear-cache] [-p android|ios|all] [--auto] [--private-key-path <value>]
|
||||
$ eas update [--branch <value>] [--channel <value>] [--message <value>] [--republish | --input-dir <value>
|
||||
| --skip-bundler] [--group <value> | | ] [--clear-cache] [-p android|ios|all] [--auto] [--private-key-path <value>]
|
||||
[--json --non-interactive]
|
||||
|
||||
FLAGS
|
||||
-m, --message=<value> A short message describing the update
|
||||
-p, --platform=(android|ios|all) [default: all]
|
||||
--auto Use the current git branch and commit message for the EAS branch and update message
|
||||
--branch=<value> Branch to publish the update group on
|
||||
@@ -1157,6 +1157,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
|
||||
--non-interactive Run the command in non-interactive mode.
|
||||
--private-key-path=<value> File containing the PEM-encoded private key corresponding to the certificate in
|
||||
expo-updates' configuration. Defaults to a file named "private-key.pem" in the
|
||||
@@ -1168,7 +1169,7 @@ DESCRIPTION
|
||||
publish an update group
|
||||
```
|
||||
|
||||
_See code: [src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/update/index.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas update:configure`
|
||||
|
||||
@@ -1186,7 +1187,7 @@ DESCRIPTION
|
||||
configure the project to support EAS Update
|
||||
```
|
||||
|
||||
_See code: [src/commands/update/configure.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/update/configure.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas update:delete GROUPID`
|
||||
|
||||
@@ -1207,7 +1208,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.18.0/packages/eas-cli/src/commands/update/delete.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas update:list`
|
||||
|
||||
@@ -1229,7 +1230,7 @@ DESCRIPTION
|
||||
view the recent updates
|
||||
```
|
||||
|
||||
_See code: [src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/update/list.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas update:republish`
|
||||
|
||||
@@ -1237,23 +1238,23 @@ roll back to an existing update
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ eas update:republish [--channel <value> | --branch <value> | --group <value>] [-m <value>] [-p android|ios|all]
|
||||
[--json --non-interactive]
|
||||
$ eas update:republish [--channel <value> | --branch <value> | --group <value>] [--message <value>] [-p
|
||||
android|ios|all] [--json --non-interactive]
|
||||
|
||||
FLAGS
|
||||
-m, --message=<value> Short message describing the republished update
|
||||
-p, --platform=(android|ios|all) [default: all]
|
||||
--branch=<value> Branch name to select an update to republish from
|
||||
--channel=<value> Channel name to select an update to republish from
|
||||
--group=<value> Update group ID to republish
|
||||
--json Enable JSON output, non-JSON messages will be printed to stderr.
|
||||
--message=<value> Short message describing the republished update
|
||||
--non-interactive Run the command in non-interactive mode.
|
||||
|
||||
DESCRIPTION
|
||||
roll back to an existing update
|
||||
```
|
||||
|
||||
_See code: [src/commands/update/republish.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/update/republish.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas update:view GROUPID`
|
||||
|
||||
@@ -1273,7 +1274,7 @@ DESCRIPTION
|
||||
update group details
|
||||
```
|
||||
|
||||
_See code: [src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/update/view.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas webhook:create`
|
||||
|
||||
@@ -1294,7 +1295,7 @@ DESCRIPTION
|
||||
create a webhook
|
||||
```
|
||||
|
||||
_See code: [src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/webhook/create.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas webhook:delete [ID]`
|
||||
|
||||
@@ -1314,7 +1315,7 @@ DESCRIPTION
|
||||
delete a webhook
|
||||
```
|
||||
|
||||
_See code: [src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/webhook/delete.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas webhook:list`
|
||||
|
||||
@@ -1332,7 +1333,7 @@ DESCRIPTION
|
||||
list webhooks
|
||||
```
|
||||
|
||||
_See code: [src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/webhook/list.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas webhook:update`
|
||||
|
||||
@@ -1354,7 +1355,7 @@ DESCRIPTION
|
||||
update a webhook
|
||||
```
|
||||
|
||||
_See code: [src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/webhook/update.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas webhook:view ID`
|
||||
|
||||
@@ -1371,7 +1372,7 @@ DESCRIPTION
|
||||
view a webhook
|
||||
```
|
||||
|
||||
_See code: [src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v3.18.0/packages/eas-cli/src/commands/webhook/view.ts)_
|
||||
_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)_
|
||||
|
||||
## `eas whoami`
|
||||
|
||||
@@ -1387,4 +1388,5 @@ DESCRIPTION
|
||||
ALIASES
|
||||
$ eas whoami
|
||||
```
|
||||
|
||||
<!-- commandsstop -->
|
||||
Generated
+163
-876
File diff suppressed because it is too large.
Load diff
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "eas-cli",
|
||||
"description": "EAS command line tool",
|
||||
"version": "3.18.0",
|
||||
"version": "3.14.0",
|
||||
"author": "Expo <[email protected]>",
|
||||
"bin": {
|
||||
"eas": "./bin/run"
|
||||
@@ -11,10 +11,10 @@
|
||||
"@expo/apple-utils": "1.3.1",
|
||||
"@expo/code-signing-certificates": "0.0.5",
|
||||
"@expo/config": "8.1.2",
|
||||
"@expo/config-plugins": "7.2.4",
|
||||
"@expo/config-plugins": "7.2.3",
|
||||
"@expo/config-types": "49.0.0",
|
||||
"@expo/eas-build-job": "1.0.30",
|
||||
"@expo/eas-json": "3.18.0",
|
||||
"@expo/eas-build-job": "1.0.13",
|
||||
"@expo/eas-json": "3.13.0",
|
||||
"@expo/json-file": "8.2.37",
|
||||
"@expo/multipart-body-parser": "1.1.0",
|
||||
"@expo/osascript": "2.0.33",
|
||||
@@ -23,17 +23,17 @@
|
||||
"@expo/plist": "0.0.20",
|
||||
"@expo/plugin-help": "5.1.22",
|
||||
"@expo/plugin-warn-if-update-available": "2.5.0",
|
||||
"@expo/prebuild-config": "6.2.5",
|
||||
"@expo/prebuild-config": "5.0.7",
|
||||
"@expo/results": "1.0.0",
|
||||
"@expo/rudder-sdk-node": "1.1.1",
|
||||
"@expo/spawn-async": "1.7.0",
|
||||
"@expo/steps": "1.0.31",
|
||||
"@expo/steps": "1.0.23",
|
||||
"@expo/timeago.js": "1.0.0",
|
||||
"@oclif/core": "1.23.2",
|
||||
"@oclif/plugin-autocomplete": "1.3.10",
|
||||
"@segment/ajv-human-errors": "^2.1.2",
|
||||
"@urql/core": "4.0.11",
|
||||
"@urql/exchange-retry": "1.2.0",
|
||||
"@urql/core": "3.1.1",
|
||||
"@urql/exchange-retry": "1.0.0",
|
||||
"ajv": "8.11.0",
|
||||
"ajv-formats": "2.1.1",
|
||||
"better-opn": "3.0.2",
|
||||
@@ -47,6 +47,7 @@
|
||||
"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",
|
||||
@@ -204,12 +205,11 @@
|
||||
"scripts": {
|
||||
"postpack": "rimraf oclif.manifest.json",
|
||||
"prepack": "yarn rebuild && node ./scripts/prepack.js",
|
||||
"rebuild": "rimraf build && yarn build-ci",
|
||||
"rebuild": "rimraf build && yarn build",
|
||||
"pretarball-ci": "./scripts/pretarball-ci.sh",
|
||||
"build": "tsc --project tsconfig.build.json",
|
||||
"build-ci": "tsc --project tsconfig.build-ci.json",
|
||||
"watch": "yarn build --watch --preserveWatchOutput",
|
||||
"typecheck": "tsc --project tsconfig.build-ci.json",
|
||||
"typecheck": "tsc",
|
||||
"test": "jest",
|
||||
"version": "yarn oclif readme && node scripts/patch-readme && git add README.md",
|
||||
"generate-graphql-code": "graphql-codegen --config graphql-codegen.yml",
|
||||
|
||||
@@ -2,6 +2,7 @@ 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;
|
||||
@@ -104,3 +105,14 @@ 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;
|
||||
}
|
||||
@@ -13,8 +13,6 @@ import {
|
||||
EasBuildFreeTierDisabledAndroidError,
|
||||
EasBuildFreeTierDisabledError,
|
||||
EasBuildFreeTierDisabledIOSError,
|
||||
EasBuildFreeTierIosLimitExceededError,
|
||||
EasBuildFreeTierLimitExceededError,
|
||||
EasBuildResourceClassNotAvailableInFreeTierError,
|
||||
EasBuildTooManyPendingBuildsError,
|
||||
RequestValidationError,
|
||||
@@ -27,18 +25,12 @@ beforeEach(() => {
|
||||
|
||||
const EXPECTED_STRINGIFIED_GRAPHQL_ERROR_JSON = `[
|
||||
{
|
||||
"name": "GraphQLError",
|
||||
"extensions": {},
|
||||
"message": "Error 1"
|
||||
},
|
||||
{
|
||||
"name": "GraphQLError",
|
||||
"extensions": {},
|
||||
"message": "Error 2"
|
||||
},
|
||||
{
|
||||
"name": "GraphQLError",
|
||||
"extensions": {},
|
||||
"message": "Error 3"
|
||||
}
|
||||
]`;
|
||||
@@ -288,45 +280,6 @@ describe(Build.name, () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('for EAS_BUILD_FREE_TIER_LIMIT_EXCEEDED', () => {
|
||||
it('throws correct EasCommandError subclass', async () => {
|
||||
const platform = Platform.ANDROID;
|
||||
const graphQLError = getGraphQLError('Error 1', 'EAS_BUILD_FREE_TIER_LIMIT_EXCEEDED');
|
||||
const graphQLErrors = [graphQLError];
|
||||
const error = new CombinedError({ graphQLErrors });
|
||||
|
||||
const handleBuildRequestErrorThrownError = getError<EasBuildFreeTierLimitExceededError>(
|
||||
() => {
|
||||
handleBuildRequestError(error, platform);
|
||||
}
|
||||
);
|
||||
|
||||
assertReThrownError(
|
||||
handleBuildRequestErrorThrownError,
|
||||
EasBuildFreeTierLimitExceededError,
|
||||
'Error 1'
|
||||
);
|
||||
});
|
||||
});
|
||||
describe('for EAS_BUILD_FREE_TIER_IOS_LIMIT_EXCEEDED', () => {
|
||||
it('throws correct EasCommandError subclass', async () => {
|
||||
const platform = Platform.ANDROID;
|
||||
const graphQLError = getGraphQLError('Error 1', 'EAS_BUILD_FREE_TIER_IOS_LIMIT_EXCEEDED');
|
||||
const graphQLErrors = [graphQLError];
|
||||
const error = new CombinedError({ graphQLErrors });
|
||||
|
||||
const handleBuildRequestErrorThrownError =
|
||||
getError<EasBuildFreeTierIosLimitExceededError>(() => {
|
||||
handleBuildRequestError(error, platform);
|
||||
});
|
||||
|
||||
assertReThrownError(
|
||||
handleBuildRequestErrorThrownError,
|
||||
EasBuildFreeTierIosLimitExceededError,
|
||||
'Error 1'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('for VALIDATION_ERROR', () => {
|
||||
describe('with Android', () => {
|
||||
@@ -471,29 +424,6 @@ describe(Build.name, () => {
|
||||
|
||||
assertReThrownError(handleBuildRequestErrorThrownError, Error, expectedMessage);
|
||||
});
|
||||
it('throws base Error class with message including all error messages if combined error has multiple GraphQL errors', async () => {
|
||||
const platform = Platform.ANDROID;
|
||||
const graphQLErrors = [
|
||||
getGraphQLError('Error 1', 'UNKNOWN_GRAPHQL_ERROR'),
|
||||
getGraphQLError('Error 2', 'OTHER_GRAPHQL_ERROR'),
|
||||
getGraphQLError('Error 3', 'YET_ANOTHER_GRAPHQL_ERROR'),
|
||||
];
|
||||
const error = new CombinedError({ graphQLErrors });
|
||||
const expectedMessage =
|
||||
`${EXPECTED_GENERIC_MESSAGE}\n` +
|
||||
`Request ID: ${mockRequestId}\n` +
|
||||
'Error message: Error 1\n' +
|
||||
`Request ID: ${mockRequestId}\n` +
|
||||
'Error message: Error 2\n' +
|
||||
`Request ID: ${mockRequestId}\n` +
|
||||
'Error message: Error 3';
|
||||
|
||||
const handleBuildRequestErrorThrownError = getError<Error>(() => {
|
||||
handleBuildRequestError(error, platform);
|
||||
});
|
||||
|
||||
assertReThrownError(handleBuildRequestErrorThrownError, Error, expectedMessage);
|
||||
});
|
||||
describe('without request ID', () => {
|
||||
it('throws base Error class with custom message without request ID line', async () => {
|
||||
const platform = Platform.ANDROID;
|
||||
@@ -525,29 +455,6 @@ describe(Build.name, () => {
|
||||
|
||||
assertReThrownError(handleBuildRequestErrorThrownError, Error, expectedMessage);
|
||||
});
|
||||
it('throws base Error class with message including all error messages if combined error has multiple GraphQL errors', async () => {
|
||||
const platform = Platform.IOS;
|
||||
const graphQLErrors = [
|
||||
getGraphQLError('Error 1', 'UNKNOWN_GRAPHQL_ERROR'),
|
||||
getGraphQLError('Error 2', 'OTHER_GRAPHQL_ERROR'),
|
||||
getGraphQLError('Error 3', 'YET_ANOTHER_GRAPHQL_ERROR'),
|
||||
];
|
||||
const error = new CombinedError({ graphQLErrors });
|
||||
const expectedMessage =
|
||||
`${EXPECTED_GENERIC_MESSAGE}\n` +
|
||||
`Request ID: ${mockRequestId}\n` +
|
||||
'Error message: Error 1\n' +
|
||||
`Request ID: ${mockRequestId}\n` +
|
||||
'Error message: Error 2\n' +
|
||||
`Request ID: ${mockRequestId}\n` +
|
||||
'Error message: Error 3';
|
||||
|
||||
const handleBuildRequestErrorThrownError = getError<Error>(() => {
|
||||
handleBuildRequestError(error, platform);
|
||||
});
|
||||
|
||||
assertReThrownError(handleBuildRequestErrorThrownError, Error, expectedMessage);
|
||||
});
|
||||
describe('without request ID', () => {
|
||||
it('throws base Error class with custom message without request ID line', async () => {
|
||||
const platform = Platform.IOS;
|
||||
|
||||
@@ -124,7 +124,8 @@ export async function prepareAndroidBuildAsync(
|
||||
}
|
||||
|
||||
function shouldProvideCredentials(ctx: BuildContext<Platform.ANDROID>): boolean {
|
||||
return !ctx.buildProfile.withoutCredentials;
|
||||
const isCustomBuild = ctx.buildProfile.config !== undefined;
|
||||
return !ctx.buildProfile.withoutCredentials && !isCustomBuild;
|
||||
}
|
||||
|
||||
async function ensureAndroidCredentialsAsync(
|
||||
|
||||
@@ -4,7 +4,6 @@ import assert from 'assert';
|
||||
import chalk from 'chalk';
|
||||
import cliProgress from 'cli-progress';
|
||||
import fs from 'fs-extra';
|
||||
import { GraphQLError } from 'graphql/error';
|
||||
import nullthrows from 'nullthrows';
|
||||
|
||||
import { BuildEvent } from '../analytics/AnalyticsManager';
|
||||
@@ -43,9 +42,6 @@ import {
|
||||
EasBuildFreeTierDisabledAndroidError,
|
||||
EasBuildFreeTierDisabledError,
|
||||
EasBuildFreeTierDisabledIOSError,
|
||||
EasBuildFreeTierIosLimitExceededError,
|
||||
EasBuildFreeTierLimitExceededError,
|
||||
EasBuildLegacyResourceClassNotAvailableError,
|
||||
EasBuildProjectArchiveUploadError,
|
||||
EasBuildResourceClassNotAvailableInFreeTierError,
|
||||
EasBuildTooManyPendingBuildsError,
|
||||
@@ -187,11 +183,8 @@ const SERVER_SIDE_DEFINED_ERRORS: Record<string, typeof EasCommandError> = {
|
||||
EAS_BUILD_FREE_TIER_DISABLED: EasBuildFreeTierDisabledError,
|
||||
EAS_BUILD_FREE_TIER_DISABLED_IOS: EasBuildFreeTierDisabledIOSError,
|
||||
EAS_BUILD_FREE_TIER_DISABLED_ANDROID: EasBuildFreeTierDisabledAndroidError,
|
||||
EAS_BUILD_FREE_TIER_LIMIT_EXCEEDED: EasBuildFreeTierLimitExceededError,
|
||||
EAS_BUILD_FREE_TIER_IOS_LIMIT_EXCEEDED: EasBuildFreeTierIosLimitExceededError,
|
||||
EAS_BUILD_RESOURCE_CLASS_NOT_AVAILABLE_IN_FREE_TIER:
|
||||
EasBuildResourceClassNotAvailableInFreeTierError,
|
||||
EAS_BUILD_LEGACY_RESOURCE_CLASS_NOT_AVAILABLE: EasBuildLegacyResourceClassNotAvailableError,
|
||||
VALIDATION_ERROR: RequestValidationError,
|
||||
};
|
||||
|
||||
@@ -213,19 +206,15 @@ export function handleBuildRequestError(error: any, platform: Platform): never {
|
||||
`You have already reached the maximum number of pending ${requestedPlatformDisplayNames[platform]} builds for your account. Try again later.`
|
||||
);
|
||||
} else if (error?.graphQLErrors) {
|
||||
const errorMessage = error.graphQLErrors
|
||||
.map((graphQLError: GraphQLError) => {
|
||||
const requestIdLine = graphQLError?.extensions?.requestId
|
||||
? `\nRequest ID: ${graphQLError.extensions.requestId}`
|
||||
: '';
|
||||
const errorMessageLine = graphQLError?.message
|
||||
? `\nError message: ${graphQLError.message}`
|
||||
: '';
|
||||
return `${requestIdLine}${errorMessageLine}`;
|
||||
})
|
||||
.join('');
|
||||
const graphQLError = error.graphQLErrors[0];
|
||||
const requestIdLine = graphQLError?.extensions?.requestId
|
||||
? `\nRequest ID: ${graphQLError.extensions.requestId}`
|
||||
: '';
|
||||
const originalErrorMessage = graphQLError?.message
|
||||
? `\nError message: ${graphQLError.message}`
|
||||
: '';
|
||||
throw new Error(
|
||||
`Build request failed. Make sure you are using the latest eas-cli version. If the problem persists, report the issue.${errorMessage}`
|
||||
`Build request failed. Make sure you are using the latest eas-cli version. If the problem persists, report the issue.${requestIdLine}${originalErrorMessage}`
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
@@ -257,10 +246,6 @@ async function uploadProjectAsync<TPlatform extends Platform>(
|
||||
);
|
||||
}
|
||||
|
||||
if (projectTarball.size > 2 * 1024 * 1024 * 1024) {
|
||||
throw new Error('Project archive is too big. Maximum allowed size is 2GB.');
|
||||
}
|
||||
|
||||
projectTarballPath = projectTarball.path;
|
||||
|
||||
const bucketKey = await uploadFileAtPathToGCSAsync(
|
||||
|
||||
@@ -8,14 +8,8 @@ export class EasBuildFreeTierDisabledIOSError extends EasCommandError {}
|
||||
|
||||
export class EasBuildFreeTierDisabledAndroidError extends EasCommandError {}
|
||||
|
||||
export class EasBuildFreeTierLimitExceededError extends EasCommandError {}
|
||||
|
||||
export class EasBuildFreeTierIosLimitExceededError extends EasCommandError {}
|
||||
|
||||
export class EasBuildResourceClassNotAvailableInFreeTierError extends EasCommandError {}
|
||||
|
||||
export class EasBuildLegacyResourceClassNotAvailableError extends EasCommandError {}
|
||||
|
||||
export class RequestValidationError extends EasCommandError {}
|
||||
|
||||
export class EasBuildDownForMaintenanceError extends EasCommandError {}
|
||||
|
||||
@@ -6,7 +6,7 @@ import semver from 'semver';
|
||||
import { ora } from '../ora';
|
||||
|
||||
const PLUGIN_PACKAGE_NAME = 'eas-cli-local-build-plugin';
|
||||
const PLUGIN_PACKAGE_VERSION = '1.0.31';
|
||||
const PLUGIN_PACKAGE_VERSION = '1.0.24';
|
||||
|
||||
export enum LocalBuildMode {
|
||||
/**
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
} from '../graphql/generated';
|
||||
import { BuildQuery } from '../graphql/queries/BuildQuery';
|
||||
import { toAppPlatform, toPlatform } from '../graphql/types/AppPlatform';
|
||||
import Log, { learnMore } from '../log';
|
||||
import Log from '../log';
|
||||
import {
|
||||
RequestedPlatform,
|
||||
appPlatformDisplayNames,
|
||||
@@ -117,15 +117,7 @@ export async function runBuildAndSubmitAsync(
|
||||
easJsonAccessor,
|
||||
platforms,
|
||||
profileName: flags.profile ?? undefined,
|
||||
projectDir,
|
||||
});
|
||||
Log.log(
|
||||
`Loaded "env" configuration for the "${buildProfiles[0].profileName}" profile: ${
|
||||
buildProfiles[0].profile.env
|
||||
? Object.keys(buildProfiles[0].profile.env).join(', ')
|
||||
: 'no environment variables specified'
|
||||
}. ${learnMore('https://docs.expo.dev/build-reference/variables/')}`
|
||||
);
|
||||
|
||||
await ensureExpoDevClientInstalledForDevClientBuildsAsync({
|
||||
projectDir,
|
||||
@@ -184,7 +176,6 @@ export async function runBuildAndSubmitAsync(
|
||||
platforms,
|
||||
profileName: flags.submitProfile,
|
||||
type: 'submit',
|
||||
projectDir,
|
||||
});
|
||||
for (const startedBuild of startedBuilds) {
|
||||
const submitProfile = nullthrows(
|
||||
|
||||
@@ -1,184 +0,0 @@
|
||||
import {
|
||||
UpdateChannelBasicInfoFragment,
|
||||
ViewUpdateChannelsPaginatedOnAppQuery,
|
||||
} from '../../graphql/generated';
|
||||
import { UpdateBranchObject, UpdateChannelObject } from '../../graphql/queries/ChannelQuery';
|
||||
|
||||
export const testUpdateBranch1: UpdateBranchObject = {
|
||||
id: '754bf17f-efc0-46ab-8a59-a03f20e53e9b',
|
||||
name: 'wrong-channel',
|
||||
updateGroups: [
|
||||
[
|
||||
{
|
||||
id: 'bbe3e63a-f620-4603-8c4d-258f3e51590d',
|
||||
group: '16ca6dba-e63b-48b0-baa3-15a894ee9434',
|
||||
message: 'fix bug',
|
||||
createdAt: '2023-07-17T22:48:59.278Z',
|
||||
runtimeVersion: 'exposdk:48.0.0',
|
||||
platform: 'ios',
|
||||
manifestFragment:
|
||||
'{"extra":{"expoClient":{"ios":{"supportsTablet":true,"bundleIdentifier":"com.quintest113.updatestest4"},"web":{"favicon":"./assets/favicon.png"},"icon":"./assets/icon.png","name":"updates-test-4","slug":"updates-test-4","extra":{"eas":{"projectId":"789a8784-0186-4f41-8bd2-7f219291a2b8"}},"splash":{"image":"./assets/splash.png","resizeMode":"contain","backgroundColor":"#ffffff"},"android":{"package":"com.quintest113.updatestest4","adaptiveIcon":{"backgroundColor":"#ffffff","foregroundImage":"./assets/adaptive-icon.png"}},"updates":{"url":"https://u.expo.dev/789a8784-0186-4f41-8bd2-7f219291a2b8"},"version":"1.0.0","platforms":["ios","android"],"sdkVersion":"48.0.0","orientation":"portrait","runtimeVersion":{"policy":"sdkVersion"},"currentFullName":"@quintest113/updates-test-4","originalFullName":"@quintest113/updates-test-4","userInterfaceStyle":"light","assetBundlePatterns":["**/*"]}},"assets":[{"bundleKey":"7d40544b395c5949f4646f5e150fe020","fileSHA256":"LN_rjlzN55dvcBL7jM5zryIpAp7iHU8VCf7RFIccbNg","storageKey":"Pi65ns2w9xLI5G_m9aGrJ5wK5FpWcGcInSSFwnA_0aA","contentType":"image/png","fileExtension":".png"},{"bundleKey":"cdd04e13d4ec83ff0cd13ec8dabdc341","fileSHA256":"irHji01LPI9giDYxtJo9bTPHaEHzuUcCMTlb4xn90Ks","storageKey":"oJZ9JX1m8IKNDgnIqcKOo5KUFOoa_NCaxruigZu65E0","contentType":"image/png","fileExtension":".png"},{"bundleKey":"a132ecc4ba5c1517ff83c0fb321bc7fc","fileSHA256":"K3RDqaWOksoRpXW9wRWYYVpX3eMFzYznDWAmBrMCzZg","storageKey":"X3OAkUu5P_LqyKFx1bNkA_qDQFLlSjCYNAlVEaOamHE","contentType":"image/png","fileExtension":".png"},{"bundleKey":"0ea69b5077e7c4696db85dbcba75b0e1","fileSHA256":"Pd0Hc-0n4j0leJ8wFzGzrEVa2L5aonoKG4OPicbSciU","storageKey":"FwJkAbrRNahBGX1KXnTAgiiwyzENu3D7DeEzCwmInyo","contentType":"image/png","fileExtension":".png"},{"bundleKey":"f5b790e2ac193b3d41015edb3551f9b8","fileSHA256":"vCfIss7SLYKt1AAi0hxjsgOMEDceLJB6ZWjQf6gTU4k","storageKey":"GQtYm7r0G9N3WJyrymjZ26p8eNMIb7rzqwSVgGco5EU","contentType":"image/png","fileExtension":".png"},{"bundleKey":"5223c8d9b0d08b82a5670fb5f71faf78","fileSHA256":"LJXowmdeeZM1_QBGuwfb2gbLfs_1HtN5IsYwnWGcxNM","storageKey":"jeqOrdQBNY4hgl04B3wtGs8QNWMDmjvbjIMUXPtOBpw","contentType":"image/png","fileExtension":".png"},{"bundleKey":"02d5848f62ade9617cf96894727d32e7","fileSHA256":"u1-8zHOj9oxS8maH-7JbShJIq1-KEV7FXnrGpEUcR-4","storageKey":"LMUvUZZpdGFb7KqaB_l9N4TXTkFn1Pw92ws9fWDNZPw","contentType":"model/gltf-binary","fileExtension":".glb"},{"bundleKey":"6013c27e421ab23c826713af3ebec891","fileSHA256":"dutQNnvzTCS4NgwvbeMbvhro5QnW0GJUeY_4rrvlcLY","storageKey":"85KB9Jr7eqz1Jwt1mYQGRzTy6ZXyO0j7ZcaLImCbzkU","contentType":"image/jpeg","fileExtension":".jpg"}],"launchAsset":{"bundleKey":"3d0ac172fe41ab941a8c68cd7e3a17ee","fileSHA256":"jjnar-ZPrb_g0Bx5tcFfjJrP3v8HdeAlXMk__xN7I1U","storageKey":"bimf-UXq5IFH5nNHCIHdcQ2MyJwTnwDVBb-P8hr2CZw","contentType":"application/javascript","fileExtension":".bundle"}}',
|
||||
isRollBackToEmbedded: false,
|
||||
manifestPermalink: 'https://u.expo.dev/update/bbe3e63a-f620-4603-8c4d-258f3e51590d',
|
||||
gitCommitHash: 'e91c5bb733eff675dd8a3722ed5d4f885a4b10ce',
|
||||
actor: {
|
||||
__typename: 'User',
|
||||
id: '026ace2b-c1f8-4a02-818d-6b52c100bdf2',
|
||||
username: 'quintest113',
|
||||
},
|
||||
branch: {
|
||||
id: '754bf17f-efc0-46ab-8a59-a03f20e53e9b',
|
||||
name: 'wrong-channel',
|
||||
__typename: 'UpdateBranch',
|
||||
},
|
||||
codeSigningInfo: null,
|
||||
__typename: 'Update',
|
||||
},
|
||||
{
|
||||
id: 'db22401b-d321-4629-a068-21d6d1f19c02',
|
||||
group: '16ca6dba-e63b-48b0-baa3-15a894ee9434',
|
||||
message: 'fix bug',
|
||||
createdAt: '2023-07-17T22:48:59.278Z',
|
||||
runtimeVersion: 'exposdk:48.0.0',
|
||||
platform: 'android',
|
||||
manifestFragment:
|
||||
'{"extra":{"expoClient":{"ios":{"supportsTablet":true,"bundleIdentifier":"com.quintest113.updatestest4"},"web":{"favicon":"./assets/favicon.png"},"icon":"./assets/icon.png","name":"updates-test-4","slug":"updates-test-4","extra":{"eas":{"projectId":"789a8784-0186-4f41-8bd2-7f219291a2b8"}},"splash":{"image":"./assets/splash.png","resizeMode":"contain","backgroundColor":"#ffffff"},"android":{"package":"com.quintest113.updatestest4","adaptiveIcon":{"backgroundColor":"#ffffff","foregroundImage":"./assets/adaptive-icon.png"}},"updates":{"url":"https://u.expo.dev/789a8784-0186-4f41-8bd2-7f219291a2b8"},"version":"1.0.0","platforms":["ios","android"],"sdkVersion":"48.0.0","orientation":"portrait","runtimeVersion":{"policy":"sdkVersion"},"currentFullName":"@quintest113/updates-test-4","originalFullName":"@quintest113/updates-test-4","userInterfaceStyle":"light","assetBundlePatterns":["**/*"]}},"assets":[{"bundleKey":"778ffc9fe8773a878e9c30a6304784de","fileSHA256":"i2Gkx-9w3JJ1PwSUl2SC9m_UFQ7CPfx3KrZeEDc6-lU","storageKey":"idnX8z03q4vGLzhYMPaQGBADjhqvWe67_afPqJ1vGzM","contentType":"image/png","fileExtension":".png"},{"bundleKey":"376d6a4c7f622917c39feb23671ef71d","fileSHA256":"QJsG0VpGM-5viirUgoKq0M4zQ_TYyPfLhAhN5mrM54I","storageKey":"46DQ95-UdSKiRkQgt5FyXkE1FrKOT9tBZP3nS7auKlg","contentType":"image/png","fileExtension":".png"},{"bundleKey":"c79c3606a1cf168006ad3979763c7e0c","fileSHA256":"kGZm3WiTRq2iMs42ia3vkHtCV_obWT8DY40rlJf2SIQ","storageKey":"k-3xHp3vP8mR36WdccUZVPTRJKpP-zlyboWdkXCIQpQ","contentType":"image/png","fileExtension":".png"},{"bundleKey":"02bc1fa7c0313217bde2d65ccbff40c9","fileSHA256":"_6fuRbdkBbpzkhSVAI99aMneY5X0tpQdsGNGX244IyA","storageKey":"lfqeUjiWFXwowhxVDBEzxsbTOEzYxMLebljy5Bh1mpU","contentType":"image/png","fileExtension":".png"},{"bundleKey":"35ba0eaec5a4f5ed12ca16fabeae451d","fileSHA256":"hM9es7ICUPaeDkczvrTaX0F_BoKJKlrRteYlcHU8IbE","storageKey":"fMoMrsUeB5xWw_Ugn8FqGJf-M2pld2hkXKR704z0MM8","contentType":"image/png","fileExtension":".png"},{"bundleKey":"5223c8d9b0d08b82a5670fb5f71faf78","fileSHA256":"LJXowmdeeZM1_QBGuwfb2gbLfs_1HtN5IsYwnWGcxNM","storageKey":"jeqOrdQBNY4hgl04B3wtGs8QNWMDmjvbjIMUXPtOBpw","contentType":"image/png","fileExtension":".png"},{"bundleKey":"02d5848f62ade9617cf96894727d32e7","fileSHA256":"u1-8zHOj9oxS8maH-7JbShJIq1-KEV7FXnrGpEUcR-4","storageKey":"LMUvUZZpdGFb7KqaB_l9N4TXTkFn1Pw92ws9fWDNZPw","contentType":"model/gltf-binary","fileExtension":".glb"},{"bundleKey":"6013c27e421ab23c826713af3ebec891","fileSHA256":"dutQNnvzTCS4NgwvbeMbvhro5QnW0GJUeY_4rrvlcLY","storageKey":"85KB9Jr7eqz1Jwt1mYQGRzTy6ZXyO0j7ZcaLImCbzkU","contentType":"image/jpeg","fileExtension":".jpg"}],"launchAsset":{"bundleKey":"4cc2ee49988e438ac066827b809721de","fileSHA256":"ctfK72f8EdS1IQmDvJLya38RMSma16beJcMoQToZIe0","storageKey":"QdEoKuCQPvVPA71gY52wqJ9vmtV4ObnCcPE2FP4SIdo","contentType":"application/javascript","fileExtension":".bundle"}}',
|
||||
isRollBackToEmbedded: false,
|
||||
manifestPermalink: 'https://u.expo.dev/update/db22401b-d321-4629-a068-21d6d1f19c02',
|
||||
gitCommitHash: 'e91c5bb733eff675dd8a3722ed5d4f885a4b10ce',
|
||||
actor: {
|
||||
__typename: 'User',
|
||||
id: '026ace2b-c1f8-4a02-818d-6b52c100bdf2',
|
||||
username: 'quintest113',
|
||||
},
|
||||
branch: {
|
||||
id: '754bf17f-efc0-46ab-8a59-a03f20e53e9b',
|
||||
name: 'wrong-channel',
|
||||
__typename: 'UpdateBranch',
|
||||
},
|
||||
codeSigningInfo: null,
|
||||
__typename: 'Update',
|
||||
},
|
||||
],
|
||||
],
|
||||
__typename: 'UpdateBranch',
|
||||
};
|
||||
|
||||
export const testUpdateBranch2: UpdateBranchObject = {
|
||||
id: '6941a8dd-5c0a-48bc-8876-f49c88ed419f',
|
||||
name: 'production',
|
||||
updateGroups: [
|
||||
[
|
||||
{
|
||||
id: 'f04aafc1-0bf5-4548-8c35-726b467e7c40',
|
||||
group: 'e40ad156-e9af-4cc2-8e9d-c7b5c328db48',
|
||||
message: 'fix bug',
|
||||
createdAt: '2023-06-23T23:37:10.004Z',
|
||||
runtimeVersion: 'exposdk:48.0.0',
|
||||
platform: 'ios',
|
||||
manifestFragment:
|
||||
'{"extra":{"expoClient":{"ios":{"supportsTablet":true,"bundleIdentifier":"com.quintest113.updatestest4"},"web":{"favicon":"./assets/favicon.png"},"icon":"./assets/icon.png","name":"updates-test-4","slug":"updates-test-4","extra":{"eas":{"projectId":"789a8784-0186-4f41-8bd2-7f219291a2b8"}},"splash":{"image":"./assets/splash.png","resizeMode":"contain","backgroundColor":"#ffffff"},"android":{"package":"com.quintest113.updatestest4","adaptiveIcon":{"backgroundColor":"#ffffff","foregroundImage":"./assets/adaptive-icon.png"}},"updates":{"url":"https://u.expo.dev/789a8784-0186-4f41-8bd2-7f219291a2b8"},"version":"1.0.0","platforms":["ios","android"],"sdkVersion":"48.0.0","orientation":"portrait","runtimeVersion":{"policy":"sdkVersion"},"currentFullName":"@quintest113/updates-test-4","originalFullName":"@quintest113/updates-test-4","userInterfaceStyle":"light","assetBundlePatterns":["**/*"]}},"assets":[{"bundleKey":"7d40544b395c5949f4646f5e150fe020","fileSHA256":"LN_rjlzN55dvcBL7jM5zryIpAp7iHU8VCf7RFIccbNg","storageKey":"Pi65ns2w9xLI5G_m9aGrJ5wK5FpWcGcInSSFwnA_0aA","contentType":"image/png","fileExtension":".png"},{"bundleKey":"cdd04e13d4ec83ff0cd13ec8dabdc341","fileSHA256":"irHji01LPI9giDYxtJo9bTPHaEHzuUcCMTlb4xn90Ks","storageKey":"oJZ9JX1m8IKNDgnIqcKOo5KUFOoa_NCaxruigZu65E0","contentType":"image/png","fileExtension":".png"},{"bundleKey":"a132ecc4ba5c1517ff83c0fb321bc7fc","fileSHA256":"K3RDqaWOksoRpXW9wRWYYVpX3eMFzYznDWAmBrMCzZg","storageKey":"X3OAkUu5P_LqyKFx1bNkA_qDQFLlSjCYNAlVEaOamHE","contentType":"image/png","fileExtension":".png"},{"bundleKey":"0ea69b5077e7c4696db85dbcba75b0e1","fileSHA256":"Pd0Hc-0n4j0leJ8wFzGzrEVa2L5aonoKG4OPicbSciU","storageKey":"FwJkAbrRNahBGX1KXnTAgiiwyzENu3D7DeEzCwmInyo","contentType":"image/png","fileExtension":".png"},{"bundleKey":"f5b790e2ac193b3d41015edb3551f9b8","fileSHA256":"vCfIss7SLYKt1AAi0hxjsgOMEDceLJB6ZWjQf6gTU4k","storageKey":"GQtYm7r0G9N3WJyrymjZ26p8eNMIb7rzqwSVgGco5EU","contentType":"image/png","fileExtension":".png"},{"bundleKey":"5223c8d9b0d08b82a5670fb5f71faf78","fileSHA256":"LJXowmdeeZM1_QBGuwfb2gbLfs_1HtN5IsYwnWGcxNM","storageKey":"jeqOrdQBNY4hgl04B3wtGs8QNWMDmjvbjIMUXPtOBpw","contentType":"image/png","fileExtension":".png"},{"bundleKey":"02d5848f62ade9617cf96894727d32e7","fileSHA256":"u1-8zHOj9oxS8maH-7JbShJIq1-KEV7FXnrGpEUcR-4","storageKey":"LMUvUZZpdGFb7KqaB_l9N4TXTkFn1Pw92ws9fWDNZPw","contentType":"model/gltf-binary","fileExtension":".glb"},{"bundleKey":"6013c27e421ab23c826713af3ebec891","fileSHA256":"dutQNnvzTCS4NgwvbeMbvhro5QnW0GJUeY_4rrvlcLY","storageKey":"85KB9Jr7eqz1Jwt1mYQGRzTy6ZXyO0j7ZcaLImCbzkU","contentType":"image/jpeg","fileExtension":".jpg"}],"launchAsset":{"bundleKey":"76ec49faddaef30ba78fe50edc5ab3d6","fileSHA256":"OLUdgP-fZI2shwGS5qlIk7nWnybL_13RJl5xR85CDBU","storageKey":"OCvI0-34zApbdo3eSGfIaQUbWdZeLeKH-nJSeedKTFs","contentType":"application/javascript","fileExtension":".bundle"}}',
|
||||
isRollBackToEmbedded: false,
|
||||
manifestPermalink: 'https://u.expo.dev/update/f04aafc1-0bf5-4548-8c35-726b467e7c40',
|
||||
gitCommitHash: 'e91c5bb733eff675dd8a3722ed5d4f885a4b10ce',
|
||||
actor: {
|
||||
__typename: 'User',
|
||||
id: '026ace2b-c1f8-4a02-818d-6b52c100bdf2',
|
||||
username: 'quintest113',
|
||||
},
|
||||
branch: {
|
||||
id: '6941a8dd-5c0a-48bc-8876-f49c88ed419f',
|
||||
name: 'production',
|
||||
__typename: 'UpdateBranch',
|
||||
},
|
||||
codeSigningInfo: null,
|
||||
__typename: 'Update',
|
||||
},
|
||||
{
|
||||
id: 'd8d15786-2727-407f-bf3e-f4bda7e397d9',
|
||||
group: 'e40ad156-e9af-4cc2-8e9d-c7b5c328db48',
|
||||
message: 'fix bug',
|
||||
createdAt: '2023-06-23T23:37:10.004Z',
|
||||
runtimeVersion: 'exposdk:48.0.0',
|
||||
platform: 'android',
|
||||
manifestFragment:
|
||||
'{"extra":{"expoClient":{"ios":{"supportsTablet":true,"bundleIdentifier":"com.quintest113.updatestest4"},"web":{"favicon":"./assets/favicon.png"},"icon":"./assets/icon.png","name":"updates-test-4","slug":"updates-test-4","extra":{"eas":{"projectId":"789a8784-0186-4f41-8bd2-7f219291a2b8"}},"splash":{"image":"./assets/splash.png","resizeMode":"contain","backgroundColor":"#ffffff"},"android":{"package":"com.quintest113.updatestest4","adaptiveIcon":{"backgroundColor":"#ffffff","foregroundImage":"./assets/adaptive-icon.png"}},"updates":{"url":"https://u.expo.dev/789a8784-0186-4f41-8bd2-7f219291a2b8"},"version":"1.0.0","platforms":["ios","android"],"sdkVersion":"48.0.0","orientation":"portrait","runtimeVersion":{"policy":"sdkVersion"},"currentFullName":"@quintest113/updates-test-4","originalFullName":"@quintest113/updates-test-4","userInterfaceStyle":"light","assetBundlePatterns":["**/*"]}},"assets":[{"bundleKey":"778ffc9fe8773a878e9c30a6304784de","fileSHA256":"i2Gkx-9w3JJ1PwSUl2SC9m_UFQ7CPfx3KrZeEDc6-lU","storageKey":"idnX8z03q4vGLzhYMPaQGBADjhqvWe67_afPqJ1vGzM","contentType":"image/png","fileExtension":".png"},{"bundleKey":"376d6a4c7f622917c39feb23671ef71d","fileSHA256":"QJsG0VpGM-5viirUgoKq0M4zQ_TYyPfLhAhN5mrM54I","storageKey":"46DQ95-UdSKiRkQgt5FyXkE1FrKOT9tBZP3nS7auKlg","contentType":"image/png","fileExtension":".png"},{"bundleKey":"c79c3606a1cf168006ad3979763c7e0c","fileSHA256":"kGZm3WiTRq2iMs42ia3vkHtCV_obWT8DY40rlJf2SIQ","storageKey":"k-3xHp3vP8mR36WdccUZVPTRJKpP-zlyboWdkXCIQpQ","contentType":"image/png","fileExtension":".png"},{"bundleKey":"02bc1fa7c0313217bde2d65ccbff40c9","fileSHA256":"_6fuRbdkBbpzkhSVAI99aMneY5X0tpQdsGNGX244IyA","storageKey":"lfqeUjiWFXwowhxVDBEzxsbTOEzYxMLebljy5Bh1mpU","contentType":"image/png","fileExtension":".png"},{"bundleKey":"35ba0eaec5a4f5ed12ca16fabeae451d","fileSHA256":"hM9es7ICUPaeDkczvrTaX0F_BoKJKlrRteYlcHU8IbE","storageKey":"fMoMrsUeB5xWw_Ugn8FqGJf-M2pld2hkXKR704z0MM8","contentType":"image/png","fileExtension":".png"},{"bundleKey":"5223c8d9b0d08b82a5670fb5f71faf78","fileSHA256":"LJXowmdeeZM1_QBGuwfb2gbLfs_1HtN5IsYwnWGcxNM","storageKey":"jeqOrdQBNY4hgl04B3wtGs8QNWMDmjvbjIMUXPtOBpw","contentType":"image/png","fileExtension":".png"},{"bundleKey":"02d5848f62ade9617cf96894727d32e7","fileSHA256":"u1-8zHOj9oxS8maH-7JbShJIq1-KEV7FXnrGpEUcR-4","storageKey":"LMUvUZZpdGFb7KqaB_l9N4TXTkFn1Pw92ws9fWDNZPw","contentType":"model/gltf-binary","fileExtension":".glb"},{"bundleKey":"6013c27e421ab23c826713af3ebec891","fileSHA256":"dutQNnvzTCS4NgwvbeMbvhro5QnW0GJUeY_4rrvlcLY","storageKey":"85KB9Jr7eqz1Jwt1mYQGRzTy6ZXyO0j7ZcaLImCbzkU","contentType":"image/jpeg","fileExtension":".jpg"}],"launchAsset":{"bundleKey":"f4c6981626dbabcf51078d07a1611f4e","fileSHA256":"q-k1hSWl49aXpSg4jOSaVVnYFSFL6xf7HVl_TQE-ObM","storageKey":"FwK1PaZqtpL0QZIgaHsxU1AV93JhMdu9K1wZizXROAc","contentType":"application/javascript","fileExtension":".bundle"}}',
|
||||
isRollBackToEmbedded: false,
|
||||
manifestPermalink: 'https://u.expo.dev/update/d8d15786-2727-407f-bf3e-f4bda7e397d9',
|
||||
gitCommitHash: 'e91c5bb733eff675dd8a3722ed5d4f885a4b10ce',
|
||||
actor: {
|
||||
__typename: 'User',
|
||||
id: '026ace2b-c1f8-4a02-818d-6b52c100bdf2',
|
||||
username: 'quintest113',
|
||||
},
|
||||
branch: {
|
||||
id: '6941a8dd-5c0a-48bc-8876-f49c88ed419f',
|
||||
name: 'production',
|
||||
__typename: 'UpdateBranch',
|
||||
},
|
||||
codeSigningInfo: null,
|
||||
__typename: 'Update',
|
||||
},
|
||||
],
|
||||
],
|
||||
__typename: 'UpdateBranch',
|
||||
};
|
||||
export const testChannelObject: UpdateChannelObject = {
|
||||
id: '9309afc2-9752-40db-8ef7-4abc10744c61',
|
||||
name: 'production',
|
||||
createdAt: '2023-05-16T21:26:16.946Z',
|
||||
branchMapping:
|
||||
'{"data":[{"branchId":"754bf17f-efc0-46ab-8a59-a03f20e53e9b","branchMappingLogic":{"operand":0.15,"clientKey":"rolloutToken","branchMappingOperator":"hash_lt"}},{"branchId":"6941a8dd-5c0a-48bc-8876-f49c88ed419f","branchMappingLogic":"true"}],"version":0}',
|
||||
updateBranches: [testUpdateBranch1, testUpdateBranch2],
|
||||
__typename: 'UpdateChannel',
|
||||
};
|
||||
|
||||
export const testBasicChannelInfo: UpdateChannelBasicInfoFragment = {
|
||||
id: '9309afc2-9752-40db-8ef7-4abc10744c61',
|
||||
name: 'production',
|
||||
branchMapping:
|
||||
'{"data":[{"branchId":"754bf17f-efc0-46ab-8a59-a03f20e53e9b","branchMappingLogic":{"operand":0.1,"clientKey":"rolloutToken","branchMappingOperator":"hash_lt"}},{"branchId":"6941a8dd-5c0a-48bc-8876-f49c88ed419f","branchMappingLogic":"true"}],"version":0}',
|
||||
__typename: 'UpdateChannel',
|
||||
};
|
||||
|
||||
export const testBasicChannelInfo2: UpdateChannelBasicInfoFragment = {
|
||||
id: '9d5c7bf0-d52d-474c-9140-c1bad7f0de9d',
|
||||
name: 'staging',
|
||||
branchMapping:
|
||||
'{"data":[{"branchId":"d7d68e32-d9c9-4a8d-8d1b-21e53100a5e8","branchMappingLogic":{"operand":0.1,"clientKey":"rolloutToken","branchMappingOperator":"hash_lt"}},{"branchId":"f9f708c2-0c91-4360-b2a4-0b61834aef4a","branchMappingLogic":"true"}],"version":0}',
|
||||
__typename: 'UpdateChannel',
|
||||
};
|
||||
|
||||
export const paginatedChannels: ViewUpdateChannelsPaginatedOnAppQuery['app']['byId']['channelsPaginated'] =
|
||||
{
|
||||
edges: [
|
||||
{
|
||||
node: {
|
||||
id: '9d5c7bf0-d52d-474c-9140-c1bad7f0de9d',
|
||||
name: 'staging',
|
||||
branchMapping:
|
||||
'{"data":[{"branchId":"d7d68e32-d9c9-4a8d-8d1b-21e53100a5e8","branchMappingLogic":{"operand":0.1,"clientKey":"rolloutToken","branchMappingOperator":"hash_lt"}},{"branchId":"f9f708c2-0c91-4360-b2a4-0b61834aef4a","branchMappingLogic":"true"}],"version":0}',
|
||||
__typename: 'UpdateChannel',
|
||||
},
|
||||
__typename: 'AppChannelEdge',
|
||||
},
|
||||
{
|
||||
node: {
|
||||
id: '95630b3c-5b91-48cb-bd31-a84315a13246',
|
||||
name: 'gh/quinlanj/3/orig',
|
||||
branchMapping:
|
||||
'{"data":[{"branchId":"d7d68e32-d9c9-4a8d-8d1b-21e53100a5e8","branchMappingLogic":"true"}],"version":0}',
|
||||
__typename: 'UpdateChannel',
|
||||
},
|
||||
__typename: 'AppChannelEdge',
|
||||
},
|
||||
],
|
||||
pageInfo: {
|
||||
hasNextPage: false,
|
||||
hasPreviousPage: false,
|
||||
startCursor: 'IjlkNWM3YmYwLWQ1MmQtNDc0Yy05MTQwLWMxYmFkN2YwZGU5ZCI',
|
||||
endCursor: 'ImE4Y2M5ZWVmLTFkZjMtNDNmZi05YTZkLTRmYTZjMTFlYmEwYiI',
|
||||
__typename: 'PageInfo',
|
||||
},
|
||||
__typename: 'AppChannelsConnection',
|
||||
};
|
||||
@@ -1,11 +0,0 @@
|
||||
import { getUpdateBranch } from '../utils';
|
||||
import { testChannelObject, testUpdateBranch1 } from './fixtures';
|
||||
|
||||
describe(getUpdateBranch, () => {
|
||||
it('gets the update branch', () => {
|
||||
expect(getUpdateBranch(testChannelObject, '754bf17f-efc0-46ab-8a59-a03f20e53e9b')).toBe(
|
||||
testUpdateBranch1
|
||||
);
|
||||
expect(() => getUpdateBranch(testChannelObject, 'not-a-branch-ID')).toThrow();
|
||||
});
|
||||
});
|
||||
@@ -1,53 +0,0 @@
|
||||
import { EASUpdateAction, EASUpdateContext, NonInteractiveError } from '../../eas-update/utils';
|
||||
import { UpdateChannelBasicInfoFragment } from '../../graphql/generated';
|
||||
import { promptAsync } from '../../prompts';
|
||||
import { getChannelsDatasetAsync } from '../queries';
|
||||
|
||||
/**
|
||||
* Select a channel for the project.
|
||||
*
|
||||
* @constructor
|
||||
* @param {function} options.filterPredicate - A predicate to filter the channels that are shown to the user. It takes a channelInfo object as a parameter and returns a boolean.
|
||||
* @param {string} options.printedType - The type of channel printed to the user. Defaults to 'channel'.
|
||||
*/
|
||||
export class SelectChannel implements EASUpdateAction<UpdateChannelBasicInfoFragment | null> {
|
||||
constructor(
|
||||
private options: {
|
||||
filterPredicate?: (channelInfo: UpdateChannelBasicInfoFragment) => boolean;
|
||||
printedType?: string;
|
||||
} = {}
|
||||
) {}
|
||||
public async runAsync(ctx: EASUpdateContext): Promise<UpdateChannelBasicInfoFragment | null> {
|
||||
const { nonInteractive, graphqlClient, app } = ctx;
|
||||
const { projectId } = app;
|
||||
const { filterPredicate } = this.options;
|
||||
const printedType = this.options.printedType ?? 'channel';
|
||||
if (nonInteractive) {
|
||||
throw new NonInteractiveError(
|
||||
`${printedType} selection cannot be run in non-interactive mode.`
|
||||
);
|
||||
}
|
||||
|
||||
const channels = await getChannelsDatasetAsync(graphqlClient, {
|
||||
appId: projectId,
|
||||
filterPredicate,
|
||||
});
|
||||
|
||||
if (channels.length === 0) {
|
||||
return null;
|
||||
} else if (channels.length === 1) {
|
||||
return channels[0];
|
||||
}
|
||||
|
||||
const { channel: selectedChannel } = await promptAsync({
|
||||
type: 'select',
|
||||
name: 'channel',
|
||||
message: `Select a ${printedType}`,
|
||||
choices: channels.map(channel => ({
|
||||
value: channel,
|
||||
title: channel.name,
|
||||
})),
|
||||
});
|
||||
return selectedChannel;
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
import { createCtxMock } from '../../../eas-update/__tests__/fixtures';
|
||||
import { NonInteractiveError } from '../../../eas-update/utils';
|
||||
import { promptAsync } from '../../../prompts';
|
||||
import { testBasicChannelInfo, testBasicChannelInfo2 } from '../../__tests__/fixtures';
|
||||
import { getChannelsDatasetAsync } from '../../queries';
|
||||
import { SelectChannel } from '../SelectChannel';
|
||||
|
||||
jest.mock('../../queries');
|
||||
jest.mock('../../../prompts');
|
||||
describe(SelectChannel, () => {
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
it('returns null if project has no channels', async () => {
|
||||
jest.mocked(getChannelsDatasetAsync).mockResolvedValue([]);
|
||||
const ctx = createCtxMock();
|
||||
const selectChannel = new SelectChannel();
|
||||
const channel = await selectChannel.runAsync(ctx);
|
||||
expect(channel).toBeNull();
|
||||
});
|
||||
it('returns the channel without prompting if project only one channel', async () => {
|
||||
jest.mocked(getChannelsDatasetAsync).mockResolvedValue([testBasicChannelInfo]);
|
||||
const ctx = createCtxMock();
|
||||
const selectChannel = new SelectChannel();
|
||||
const channel = await selectChannel.runAsync(ctx);
|
||||
expect(channel).toBe(testBasicChannelInfo);
|
||||
});
|
||||
it('returns the selected channel', async () => {
|
||||
jest
|
||||
.mocked(getChannelsDatasetAsync)
|
||||
.mockResolvedValue([testBasicChannelInfo, testBasicChannelInfo2]);
|
||||
jest.mocked(promptAsync).mockImplementation(async () => ({
|
||||
channel: testBasicChannelInfo,
|
||||
}));
|
||||
const ctx = createCtxMock();
|
||||
const selectChannel = new SelectChannel();
|
||||
const channel = await selectChannel.runAsync(ctx);
|
||||
expect(channel).toBe(testBasicChannelInfo);
|
||||
});
|
||||
it('throws an error in Non-Interactive Mode', async () => {
|
||||
const ctx = createCtxMock({
|
||||
nonInteractive: true,
|
||||
});
|
||||
const selectChannel = new SelectChannel();
|
||||
|
||||
// dont fail if users are running in non-interactive mode
|
||||
await expect(selectChannel.runAsync(ctx)).rejects.toThrowError(NonInteractiveError);
|
||||
});
|
||||
});
|
||||
@@ -1,116 +0,0 @@
|
||||
import assert from 'assert';
|
||||
|
||||
// TODO(quin): move this into a common package with www
|
||||
export type BranchMappingOperator =
|
||||
| '=='
|
||||
| '!='
|
||||
| '<'
|
||||
| '>'
|
||||
| '<='
|
||||
| '>='
|
||||
| 'in'
|
||||
| 'regex'
|
||||
| 'hash_lt'
|
||||
| 'hash_lte'
|
||||
| 'hash_gt'
|
||||
| 'hash_gte';
|
||||
export type BranchMappingObject = {
|
||||
clientKey: string;
|
||||
branchMappingOperator: BranchMappingOperator;
|
||||
operand: number | string | string[];
|
||||
};
|
||||
export type BranchMappingAlwaysTrue = 'true';
|
||||
export type BranchMappingStatement =
|
||||
| ['and' | 'or', ...BranchMappingNode[]]
|
||||
| ['not', BranchMappingNode];
|
||||
export type BranchMappingNode =
|
||||
| BranchMappingAlwaysTrue
|
||||
| BranchMappingObject
|
||||
| BranchMappingStatement;
|
||||
export type BranchMapping = {
|
||||
version: number;
|
||||
data: {
|
||||
branchId: string;
|
||||
branchMappingLogic: BranchMappingNode;
|
||||
}[];
|
||||
};
|
||||
|
||||
export function getAlwaysTrueBranchMapping(branchId: string): BranchMapping {
|
||||
return {
|
||||
version: 0,
|
||||
data: [
|
||||
{
|
||||
branchId,
|
||||
branchMappingLogic: 'true',
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
export function getBranchMapping(branchMappingString: string): BranchMapping {
|
||||
try {
|
||||
return JSON.parse(branchMappingString);
|
||||
} catch {
|
||||
throw new Error(`Could not parse branchMapping string into a JSON: "${branchMappingString}"`);
|
||||
}
|
||||
}
|
||||
|
||||
export function getNodesFromStatement(statement: BranchMappingStatement): BranchMappingNode[] {
|
||||
return statement.slice(1) as BranchMappingNode[];
|
||||
}
|
||||
|
||||
export function isAndStatement(
|
||||
statement: BranchMappingStatement
|
||||
): statement is BranchMappingStatement {
|
||||
return statement[0] === 'and';
|
||||
}
|
||||
|
||||
export function isStatement(node: BranchMappingNode): node is BranchMappingStatement {
|
||||
return Array.isArray(node);
|
||||
}
|
||||
|
||||
export function isNodeObject(node: BranchMappingNode): node is BranchMappingObject {
|
||||
return typeof node === 'object' && !isStatement(node);
|
||||
}
|
||||
|
||||
export function andStatement(nodes: BranchMappingNode[]): ['and', ...BranchMappingNode[]] {
|
||||
return ['and', ...nodes];
|
||||
}
|
||||
|
||||
export function isAlwaysTrue(node: BranchMappingNode): boolean {
|
||||
return node === 'true';
|
||||
}
|
||||
|
||||
export function alwaysTrue(): BranchMappingAlwaysTrue {
|
||||
return 'true';
|
||||
}
|
||||
|
||||
export function equalsOperator(): BranchMappingOperator {
|
||||
return '==';
|
||||
}
|
||||
|
||||
export function hashLtOperator(): BranchMappingOperator {
|
||||
return 'hash_lt';
|
||||
}
|
||||
|
||||
export function assertStatement(node: BranchMappingNode): asserts node is BranchMappingStatement {
|
||||
assert(
|
||||
isStatement(node),
|
||||
'Branch mapping node must be a statement. Received: ' + JSON.stringify(node)
|
||||
);
|
||||
}
|
||||
|
||||
export function assertNodeObject(node: BranchMappingNode): asserts node is BranchMappingObject {
|
||||
assert(
|
||||
isNodeObject(node),
|
||||
'Branch mapping node must be an object. Received: ' + JSON.stringify(node)
|
||||
);
|
||||
}
|
||||
|
||||
export function assertNumber(operand: string | number | string[]): asserts operand is number {
|
||||
assert(typeof operand === 'number', 'Expected a number. Received: ' + JSON.stringify(operand));
|
||||
}
|
||||
|
||||
export function assertString(operand: string | number | string[]): asserts operand is string {
|
||||
assert(typeof operand === 'string', 'Expected a string. Received: ' + JSON.stringify(operand));
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import chalk from 'chalk';
|
||||
import { print } from 'graphql';
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
@@ -8,23 +7,18 @@ import { withErrorHandlingAsync } from '../graphql/client';
|
||||
import {
|
||||
CreateUpdateChannelOnAppMutation,
|
||||
CreateUpdateChannelOnAppMutationVariables,
|
||||
PageInfo,
|
||||
UpdateChannelBasicInfoFragment,
|
||||
ViewBranchesOnUpdateChannelQueryVariables,
|
||||
ViewUpdateChannelsOnAppQueryVariables,
|
||||
} from '../graphql/generated';
|
||||
import { BranchQuery, UpdateBranchOnChannelObject } from '../graphql/queries/BranchQuery';
|
||||
import { ChannelQuery, UpdateChannelObject } from '../graphql/queries/ChannelQuery';
|
||||
import { UpdateChannelBasicInfoFragmentNode } from '../graphql/types/UpdateChannelBasicInfo';
|
||||
import Log from '../log';
|
||||
import { ora } from '../ora';
|
||||
import formatFields from '../utils/formatFields';
|
||||
import { printJsonOnlyOutput } from '../utils/json';
|
||||
import {
|
||||
paginatedQueryWithConfirmPromptAsync,
|
||||
paginatedQueryWithSelectPromptAsync,
|
||||
} from '../utils/queries';
|
||||
import { Connection, QueryParams, getPaginatedDatasetAsync } from '../utils/relay';
|
||||
import { logChannelDetails } from './utils';
|
||||
|
||||
export const CHANNELS_LIMIT = 25;
|
||||
@@ -233,11 +227,11 @@ export async function createChannelOnAppAsync(
|
||||
updateChannel {
|
||||
createUpdateChannelForApp(appId: $appId, name: $name, branchMapping: $branchMapping) {
|
||||
id
|
||||
...UpdateChannelBasicInfoFragment
|
||||
name
|
||||
branchMapping
|
||||
}
|
||||
}
|
||||
}
|
||||
${print(UpdateChannelBasicInfoFragmentNode)}
|
||||
`,
|
||||
{
|
||||
appId,
|
||||
@@ -268,46 +262,3 @@ export async function ensureChannelExistsAsync(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function getChannelsDatasetAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
{
|
||||
appId,
|
||||
filterPredicate,
|
||||
batchSize = 100,
|
||||
}: {
|
||||
appId: string;
|
||||
filterPredicate?: (channelInfo: UpdateChannelBasicInfoFragment) => boolean;
|
||||
batchSize?: number;
|
||||
}
|
||||
): Promise<UpdateChannelBasicInfoFragment[]> {
|
||||
const queryAsync = async ({
|
||||
first,
|
||||
after,
|
||||
}: QueryParams): Promise<Connection<UpdateChannelBasicInfoFragment>> =>
|
||||
await ChannelQuery.viewUpdateChannelsBasicInfoPaginatedOnAppAsync(graphqlClient, {
|
||||
appId,
|
||||
first,
|
||||
after,
|
||||
});
|
||||
|
||||
const assetSpinner = ora().start('Fetching channels...');
|
||||
const afterEachQuery = (
|
||||
totalNodesFetched: number,
|
||||
_dataset: UpdateChannelBasicInfoFragment[],
|
||||
_batch: UpdateChannelBasicInfoFragment[],
|
||||
pageInfo: PageInfo
|
||||
): void => {
|
||||
if (pageInfo.hasNextPage) {
|
||||
assetSpinner.text = `Fetched ${totalNodesFetched} channels`;
|
||||
}
|
||||
};
|
||||
const dataset = await getPaginatedDatasetAsync({
|
||||
queryAsync,
|
||||
afterEachQuery,
|
||||
filterPredicate,
|
||||
batchSize,
|
||||
});
|
||||
assetSpinner.succeed(`Fetched all channels`);
|
||||
return dataset;
|
||||
}
|
||||
@@ -1,14 +1,25 @@
|
||||
import assert from 'assert';
|
||||
import chalk from 'chalk';
|
||||
|
||||
import { UpdateBranchObject, UpdateChannelObject } from '../graphql/queries/ChannelQuery';
|
||||
import { UpdateChannelObject } from '../graphql/queries/ChannelQuery';
|
||||
import Log from '../log';
|
||||
import {
|
||||
FormattedBranchDescription,
|
||||
formatBranch,
|
||||
getUpdateGroupDescriptionsWithBranch,
|
||||
} from '../update/utils';
|
||||
import { BranchMapping, assertNodeObject, assertNumber, isNodeObject } from './branch-mapping';
|
||||
|
||||
export type BranchMapping = {
|
||||
version: number;
|
||||
data: {
|
||||
branchId: string;
|
||||
branchMappingLogic: {
|
||||
operand: number;
|
||||
clientKey: string;
|
||||
branchMappingOperator: string;
|
||||
} & string;
|
||||
}[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the branch mapping and determine whether it is a rollout.
|
||||
@@ -35,12 +46,8 @@ export function getBranchMapping(branchMappingString?: string): {
|
||||
}
|
||||
|
||||
const isRollout = branchMapping.data.length === 2;
|
||||
const branchMappingNode = branchMapping.data[0]?.branchMappingLogic;
|
||||
let rolloutPercent: number | undefined;
|
||||
if (isNodeObject(branchMappingNode)) {
|
||||
assertNumber(branchMappingNode.operand);
|
||||
rolloutPercent = branchMappingNode.operand;
|
||||
}
|
||||
const rolloutPercent = branchMapping.data[0]?.branchMappingLogic.operand;
|
||||
|
||||
switch (branchMapping.data.length) {
|
||||
case 0:
|
||||
break;
|
||||
@@ -50,11 +57,10 @@ export function getBranchMapping(branchMappingString?: string): {
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
assertNodeObject(branchMappingNode);
|
||||
if (branchMappingNode.clientKey !== 'rolloutToken') {
|
||||
if (branchMapping.data[0].branchMappingLogic.clientKey !== 'rolloutToken') {
|
||||
throw new Error('Client key of initial branch mapping must be "rolloutToken"');
|
||||
}
|
||||
if (branchMappingNode.branchMappingOperator !== 'hash_lt') {
|
||||
if (branchMapping.data[0].branchMappingLogic.branchMappingOperator !== 'hash_lt') {
|
||||
throw new Error('Branch mapping operator of initial branch mapping must be "hash_lt"');
|
||||
}
|
||||
if (rolloutPercent == null) {
|
||||
@@ -109,25 +115,3 @@ export function logChannelDetails(channel: UpdateChannelObject): void {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function getUpdateBranchNullable(
|
||||
channel: UpdateChannelObject,
|
||||
branchId: string
|
||||
): UpdateBranchObject | null {
|
||||
const updateBranches = channel.updateBranches;
|
||||
const updateBranch = updateBranches.find(branch => branch.id === branchId);
|
||||
return updateBranch ?? null;
|
||||
}
|
||||
|
||||
export function getUpdateBranch(
|
||||
channel: UpdateChannelObject,
|
||||
branchId: string
|
||||
): UpdateBranchObject {
|
||||
const updateBranch = getUpdateBranchNullable(channel, branchId);
|
||||
if (!updateBranch) {
|
||||
throw new Error(
|
||||
`Could not find branch with id "${branchId}" in branch-mapping of channel "${channel.name}"`
|
||||
);
|
||||
}
|
||||
return updateBranch;
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Command } from '@oclif/core';
|
||||
import { CombinedError } from '@urql/core';
|
||||
import { GraphQLError } from 'graphql/error';
|
||||
import nullthrows from 'nullthrows';
|
||||
|
||||
import {
|
||||
@@ -194,22 +193,10 @@ export default abstract class EasCommand extends Command {
|
||||
if (err instanceof EasCommandError) {
|
||||
Log.error(err.message);
|
||||
} else if (err instanceof CombinedError && err?.graphQLErrors) {
|
||||
const cleanMessage = err?.graphQLErrors
|
||||
.map((graphQLError: GraphQLError) => {
|
||||
const messageLine = graphQLError.message.replace('[GraphQL] ', '');
|
||||
const requestIdLine = graphQLError.extensions?.requestId
|
||||
? `\nRequest ID: ${err.graphQLErrors[0].extensions.requestId}`
|
||||
: '';
|
||||
|
||||
const defaultMsg = `${messageLine}${requestIdLine}`;
|
||||
|
||||
if (graphQLError.extensions?.errorCode === 'UNAUTHORIZED_ERROR') {
|
||||
return `You don't have the required permissions to perform this operation.\n\n${defaultMsg}`;
|
||||
}
|
||||
|
||||
return defaultMsg;
|
||||
})
|
||||
.join('\n');
|
||||
let cleanMessage = err.message.replace('[GraphQL] ', '');
|
||||
cleanMessage += err?.graphQLErrors?.[0]?.extensions?.requestId
|
||||
? `\nRequest ID: ${err.graphQLErrors[0].extensions.requestId}`
|
||||
: '';
|
||||
Log.error(cleanMessage);
|
||||
baseMessage = BASE_GRAPHQL_ERROR_MESSAGE;
|
||||
} else {
|
||||
|
||||
@@ -172,44 +172,6 @@ describe(EasCommand.name, () => {
|
||||
expect(logDebugSpy).toBeCalledWith(error);
|
||||
});
|
||||
|
||||
it('logs the cleaned messages with request IDs if multiple GraphQL errors present', async () => {
|
||||
const TestEasCommand = createTestEasCommand();
|
||||
const logErrorSpy = jest.spyOn(Log, 'error');
|
||||
const logDebugSpy = jest.spyOn(Log, 'debug');
|
||||
const runAsyncMock = jest.spyOn(TestEasCommand.prototype as any, 'runAsync');
|
||||
const graphQLErrors = [
|
||||
new GraphQLError('Unexpected GraphQL error message', null, null, null, null, null, {
|
||||
errorCode: 'UNKNOWN_GRAPHQL_ERROR',
|
||||
requestId: mockRequestId,
|
||||
}),
|
||||
new GraphQLError('Other GraphQL error message', null, null, null, null, null, {
|
||||
errorCode: 'OTHER_GRAPHQL_ERROR',
|
||||
requestId: mockRequestId,
|
||||
}),
|
||||
new GraphQLError('Yet another GraphQL error message', null, null, null, null, null, {
|
||||
errorCode: 'YET_ANOTHER_GRAPHQL_ERROR',
|
||||
requestId: mockRequestId,
|
||||
}),
|
||||
];
|
||||
const error = new CombinedError({ graphQLErrors });
|
||||
runAsyncMock.mockImplementation(() => {
|
||||
throw error;
|
||||
});
|
||||
try {
|
||||
await TestEasCommand.run();
|
||||
} catch {}
|
||||
|
||||
expect(logErrorSpy).toBeCalledWith(
|
||||
'Unexpected GraphQL error message\n' +
|
||||
`Request ID: ${mockRequestId}\n` +
|
||||
'Other GraphQL error message\n' +
|
||||
`Request ID: ${mockRequestId}\n` +
|
||||
'Yet another GraphQL error message\n' +
|
||||
`Request ID: ${mockRequestId}`
|
||||
);
|
||||
expect(logDebugSpy).toBeCalledWith(error);
|
||||
});
|
||||
|
||||
it('re-throws the error with default base message', async () => {
|
||||
const TestEasCommand = createTestEasCommand();
|
||||
const runAsyncMock = jest.spyOn(TestEasCommand.prototype as any, 'runAsync');
|
||||
@@ -224,7 +186,7 @@ describe(EasCommand.name, () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('re-throws the error with a different default base message in case of CombinedError', async () => {
|
||||
it('re-throws the error with a different default base message in case of graphQLError', async () => {
|
||||
const TestEasCommand = createTestEasCommand();
|
||||
const runAsyncMock = jest.spyOn(TestEasCommand.prototype as any, 'runAsync');
|
||||
runAsyncMock.mockImplementation(() => {
|
||||
@@ -238,34 +200,6 @@ describe(EasCommand.name, () => {
|
||||
expect((caughtError as Error).message).toEqual('GraphQL request failed.');
|
||||
}
|
||||
});
|
||||
|
||||
it('re-throws the error with a different default base message in case of CombinedError with multiple GraphQLErrors', async () => {
|
||||
const TestEasCommand = createTestEasCommand();
|
||||
const runAsyncMock = jest.spyOn(TestEasCommand.prototype as any, 'runAsync');
|
||||
runAsyncMock.mockImplementation(() => {
|
||||
const graphQLErrors = [
|
||||
new GraphQLError('Unexpected GraphQL error message', null, null, null, null, null, {
|
||||
errorCode: 'UNEXPECTED_GRAPHQL_ERROR',
|
||||
requestId: mockRequestId,
|
||||
}),
|
||||
new GraphQLError('Other GraphQL error message', null, null, null, null, null, {
|
||||
errorCode: 'OTHER_GRAPHQL_ERROR',
|
||||
requestId: mockRequestId,
|
||||
}),
|
||||
new GraphQLError('Yet another GraphQL error message', null, null, null, null, null, {
|
||||
errorCode: 'YET_ANOTHER_GRAPHQL_ERROR',
|
||||
requestId: mockRequestId,
|
||||
}),
|
||||
];
|
||||
throw new CombinedError({ graphQLErrors });
|
||||
});
|
||||
try {
|
||||
await TestEasCommand.run();
|
||||
} catch (caughtError) {
|
||||
expect(caughtError).toBeInstanceOf(Error);
|
||||
expect((caughtError as Error).message).toEqual('GraphQL request failed.');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
+1
-5
@@ -1,4 +1,4 @@
|
||||
import { getConfig, getConfigFilePaths, modifyConfigAsync } from '@expo/config';
|
||||
import { getConfig, modifyConfigAsync } from '@expo/config';
|
||||
import { vol } from 'memfs';
|
||||
import { anything, instance, mock, when } from 'ts-mockito';
|
||||
|
||||
@@ -26,10 +26,6 @@ describe(getProjectIdAsync, () => {
|
||||
let sessionManager: SessionManager;
|
||||
|
||||
beforeEach(() => {
|
||||
jest
|
||||
.mocked(getConfigFilePaths)
|
||||
.mockReturnValue({ staticConfigPath: null, dynamicConfigPath: null });
|
||||
|
||||
const sessionManagerMock = mock<SessionManager>();
|
||||
when(sessionManagerMock.ensureLoggedInAsync(anything())).thenResolve({
|
||||
actor: {
|
||||
|
||||
@@ -3,10 +3,11 @@ import {
|
||||
Client,
|
||||
OperationContext,
|
||||
OperationResult,
|
||||
OperationResultSource,
|
||||
PromisifiedSource,
|
||||
TypedDocumentNode,
|
||||
cacheExchange,
|
||||
createClient as createUrqlClient,
|
||||
dedupExchange,
|
||||
fetchExchange,
|
||||
} from '@urql/core';
|
||||
import { retryExchange } from '@urql/exchange-retry';
|
||||
@@ -21,7 +22,7 @@ export interface ExpoGraphqlClient extends Client {
|
||||
query: DocumentNode | TypedDocumentNode<Data, Variables> | string,
|
||||
variables: Variables,
|
||||
context: Partial<OperationContext> & { additionalTypenames: string[] }
|
||||
): OperationResultSource<OperationResult<Data, Variables>>;
|
||||
): PromisifiedSource<OperationResult<Data, Variables>>;
|
||||
}
|
||||
|
||||
export function createGraphqlClient(authInfo: {
|
||||
@@ -31,6 +32,7 @@ export function createGraphqlClient(authInfo: {
|
||||
return createUrqlClient({
|
||||
url: getExpoApiBaseUrl() + '/graphql',
|
||||
exchanges: [
|
||||
dedupExchange,
|
||||
cacheExchange,
|
||||
retryExchange({
|
||||
maxDelayMs: 4000,
|
||||
|
||||
@@ -11,10 +11,7 @@ import { isExpoUpdatesInstalled, isUsingEASUpdate } from '../../project/projectU
|
||||
import { resolveWorkflowAsync } from '../../project/workflow';
|
||||
import { promptAsync } from '../../prompts';
|
||||
import { syncUpdatesConfigurationAsync as syncAndroidUpdatesConfigurationAsync } from '../../update/android/UpdatesModule';
|
||||
import {
|
||||
ensureEASUpdateIsConfiguredInEasJsonAsync,
|
||||
ensureUseClassicUpdatesIsRemovedAsync,
|
||||
} from '../../update/configure';
|
||||
import { ensureEASUpdateIsConfiguredInEasJsonAsync } from '../../update/configure';
|
||||
import { syncUpdatesConfigurationAsync as syncIosUpdatesConfigurationAsync } from '../../update/ios/UpdatesModule';
|
||||
import { getVcsClient } from '../../vcs';
|
||||
|
||||
@@ -66,12 +63,6 @@ export default class BuildConfigure extends EasCommand {
|
||||
nonInteractive: false,
|
||||
});
|
||||
if (didCreateEasJson && isUsingEASUpdate(exp, projectId)) {
|
||||
if (exp.updates?.useClassicUpdates) {
|
||||
// NOTE: this method modifies the Expo config; be sure to use this function's return value
|
||||
// if the config object is used later in the future
|
||||
await ensureUseClassicUpdatesIsRemovedAsync({ exp, projectDir });
|
||||
}
|
||||
|
||||
await ensureEASUpdateIsConfiguredInEasJsonAsync(projectDir);
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,6 @@ export default class BuildVersionGetView extends EasCommand {
|
||||
easJsonAccessor,
|
||||
platforms,
|
||||
profileName: flags.profile ?? undefined,
|
||||
projectDir,
|
||||
});
|
||||
const results: { [key in Platform]?: string } = {};
|
||||
for (const { profile, platform } of buildProfiles) {
|
||||
|
||||
@@ -80,7 +80,6 @@ export default class BuildVersionSyncView extends EasCommand {
|
||||
easJsonAccessor,
|
||||
platforms,
|
||||
profileName: flags.profile ?? undefined,
|
||||
projectDir,
|
||||
});
|
||||
for (const profileInfo of buildProfiles) {
|
||||
const { exp, projectId } = await getDynamicPrivateProjectConfigAsync({
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Flags } from '@oclif/core';
|
||||
import chalk from 'chalk';
|
||||
import { print } from 'graphql';
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
import { selectBranchOnAppAsync } from '../../branch/queries';
|
||||
@@ -10,20 +9,18 @@ import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/creat
|
||||
import { EasNonInteractiveAndJsonFlags } from '../../commandUtils/flags';
|
||||
import { withErrorHandlingAsync } from '../../graphql/client';
|
||||
import {
|
||||
UpdateChannelBasicInfoFragment,
|
||||
UpdateChannelBranchMappingMutation,
|
||||
UpdateChannelBranchMappingMutationVariables,
|
||||
} from '../../graphql/generated';
|
||||
import { BranchQuery } from '../../graphql/queries/BranchQuery';
|
||||
import { ChannelQuery } from '../../graphql/queries/ChannelQuery';
|
||||
import { UpdateChannelBasicInfoFragmentNode } from '../../graphql/types/UpdateChannelBasicInfo';
|
||||
import Log from '../../log';
|
||||
import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
|
||||
|
||||
export async function updateChannelBranchMappingAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
{ channelId, branchMapping }: UpdateChannelBranchMappingMutationVariables
|
||||
): Promise<UpdateChannelBasicInfoFragment> {
|
||||
): Promise<UpdateChannelBranchMappingMutation['updateChannel']['editUpdateChannel']> {
|
||||
const data = await withErrorHandlingAsync(
|
||||
graphqlClient
|
||||
.mutation<UpdateChannelBranchMappingMutation, UpdateChannelBranchMappingMutationVariables>(
|
||||
@@ -32,11 +29,11 @@ export async function updateChannelBranchMappingAsync(
|
||||
updateChannel {
|
||||
editUpdateChannel(channelId: $channelId, branchMapping: $branchMapping) {
|
||||
id
|
||||
...UpdateChannelBasicInfoFragment
|
||||
name
|
||||
branchMapping
|
||||
}
|
||||
}
|
||||
}
|
||||
${print(UpdateChannelBasicInfoFragmentNode)}
|
||||
`,
|
||||
{ channelId, branchMapping }
|
||||
)
|
||||
|
||||
@@ -2,20 +2,14 @@ import { Flags } from '@oclif/core';
|
||||
import chalk from 'chalk';
|
||||
|
||||
import { selectBranchOnAppAsync } from '../../branch/queries';
|
||||
import {
|
||||
BranchMapping,
|
||||
BranchMappingObject,
|
||||
assertNodeObject,
|
||||
assertNumber,
|
||||
} from '../../channel/branch-mapping';
|
||||
import { selectChannelOnAppAsync } from '../../channel/queries';
|
||||
import { getBranchMapping } from '../../channel/utils';
|
||||
import { BranchMapping, getBranchMapping } from '../../channel/utils';
|
||||
import EasCommand from '../../commandUtils/EasCommand';
|
||||
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
import { EasNonInteractiveAndJsonFlags } from '../../commandUtils/flags';
|
||||
import { UpdateBranch } from '../../graphql/generated';
|
||||
import { BranchQuery } from '../../graphql/queries/BranchQuery';
|
||||
import { ChannelQuery, UpdateChannelObject } from '../../graphql/queries/ChannelQuery';
|
||||
import { ChannelQuery, UpdateChannelByNameObject } from '../../graphql/queries/ChannelQuery';
|
||||
import Log from '../../log';
|
||||
import { getDisplayNameForProjectIdAsync } from '../../project/projectUtils';
|
||||
import { promptAsync, selectAsync } from '../../prompts';
|
||||
@@ -45,7 +39,7 @@ async function promptForRolloutPercentAsync({
|
||||
return rolloutPercent;
|
||||
}
|
||||
|
||||
function getRolloutInfo(channel: UpdateChannelObject): {
|
||||
function getRolloutInfo(channel: UpdateChannelByNameObject): {
|
||||
newBranch: Pick<UpdateBranch, 'name' | 'id'>;
|
||||
oldBranch: Pick<UpdateBranch, 'name' | 'id'>;
|
||||
currentPercent: number;
|
||||
@@ -59,10 +53,7 @@ function getRolloutInfo(channel: UpdateChannelObject): {
|
||||
throw new Error(`Branch mapping rollout is missing a branch for channel "${channel.name}".`);
|
||||
}
|
||||
|
||||
const branchMappingNode = branchMapping.data[0]?.branchMappingLogic;
|
||||
assertNodeObject(branchMappingNode);
|
||||
assertNumber(branchMappingNode.operand);
|
||||
const currentPercent = 100 * branchMappingNode.operand;
|
||||
const currentPercent = 100 * branchMapping.data[0].branchMappingLogic.operand;
|
||||
return { newBranch, oldBranch, currentPercent };
|
||||
}
|
||||
|
||||
@@ -84,7 +75,7 @@ async function startRolloutAsync(
|
||||
projectId: string;
|
||||
displayName: string;
|
||||
currentBranchMapping: BranchMapping;
|
||||
channel: UpdateChannelObject;
|
||||
channel: UpdateChannelByNameObject;
|
||||
nonInteractive: boolean;
|
||||
}
|
||||
): Promise<{
|
||||
@@ -165,7 +156,7 @@ async function editRolloutAsync(
|
||||
percent?: number;
|
||||
nonInteractive: boolean;
|
||||
currentBranchMapping: BranchMapping;
|
||||
channel: UpdateChannelObject;
|
||||
channel: UpdateChannelByNameObject;
|
||||
}
|
||||
): Promise<{
|
||||
newChannelInfo: {
|
||||
@@ -192,7 +183,7 @@ async function editRolloutAsync(
|
||||
}
|
||||
|
||||
const newBranchMapping = { ...currentBranchMapping };
|
||||
(newBranchMapping.data[0].branchMappingLogic as BranchMappingObject).operand = percent / 100;
|
||||
newBranchMapping.data[0].branchMappingLogic.operand = percent / 100;
|
||||
|
||||
const newChannelInfo = await updateChannelBranchMappingAsync(graphqlClient, {
|
||||
channelId: channel.id,
|
||||
@@ -223,7 +214,7 @@ async function endRolloutAsync(
|
||||
branchName?: string;
|
||||
nonInteractive: boolean;
|
||||
projectId: string;
|
||||
channel: UpdateChannelObject;
|
||||
channel: UpdateChannelByNameObject;
|
||||
}
|
||||
): Promise<{
|
||||
newChannelInfo: {
|
||||
|
||||
@@ -47,7 +47,6 @@ export default class MetadataLint extends EasCommand {
|
||||
easJsonAccessor: EasJsonAccessor.fromProjectPath(projectDir),
|
||||
platforms: [Platform.IOS],
|
||||
profileName: flags.profile,
|
||||
projectDir,
|
||||
});
|
||||
|
||||
if (submitProfiles.length !== 1) {
|
||||
|
||||
@@ -49,7 +49,6 @@ export default class MetadataPull extends EasCommand {
|
||||
easJsonAccessor: EasJsonAccessor.fromProjectPath(projectDir),
|
||||
platforms: [Platform.IOS],
|
||||
profileName: flags.profile,
|
||||
projectDir,
|
||||
});
|
||||
|
||||
if (submitProfiles.length !== 1) {
|
||||
|
||||
@@ -47,7 +47,6 @@ export default class MetadataPush extends EasCommand {
|
||||
easJsonAccessor: EasJsonAccessor.fromProjectPath(projectDir),
|
||||
platforms: [Platform.IOS],
|
||||
profileName: flags.profile,
|
||||
projectDir,
|
||||
});
|
||||
|
||||
if (submitProfiles.length !== 1) {
|
||||
|
||||
@@ -118,7 +118,6 @@ export default class Submit extends EasCommand {
|
||||
easJsonAccessor: EasJsonAccessor.fromProjectPath(projectDir),
|
||||
platforms,
|
||||
profileName: flagsWithPlatform.profile,
|
||||
projectDir,
|
||||
});
|
||||
|
||||
const submissions: SubmissionFragment[] = [];
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import { ExpoConfig } from '@expo/config';
|
||||
import { instance, mock } from 'ts-mockito';
|
||||
|
||||
import { ExpoGraphqlClient } from '../../../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
import { ensureEASUpdateIsConfiguredAsync } from '../../../update/configure';
|
||||
|
||||
describe(ensureEASUpdateIsConfiguredAsync, () => {
|
||||
it('errors with "useClassicUpdates" set and no app.json', async () => {
|
||||
const graphqlClient = instance(mock<ExpoGraphqlClient>({}));
|
||||
const exp: ExpoConfig = {
|
||||
name: 'test',
|
||||
slug: 'test',
|
||||
updates: { useClassicUpdates: true },
|
||||
};
|
||||
|
||||
await expect(async () => {
|
||||
await ensureEASUpdateIsConfiguredAsync(graphqlClient, {
|
||||
exp,
|
||||
projectId: 'test',
|
||||
projectDir: '/tmp/test',
|
||||
platform: null,
|
||||
});
|
||||
}).rejects.toThrow(
|
||||
`Your app config sets "updates.useClassicUpdates" but EAS Update does not support classic updates. Remove "useClassicUpdates" from your app config and run this command again.`
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -41,7 +41,7 @@ export default class UpdateConfigure extends EasCommand {
|
||||
});
|
||||
|
||||
Log.log(
|
||||
'💡 The following process will configure your project to use EAS Update. These changes only apply to your local project files and you can safely revert them at any time.'
|
||||
'💡 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();
|
||||
@@ -56,7 +56,7 @@ export default class UpdateConfigure extends EasCommand {
|
||||
await ensureEASUpdateIsConfiguredInEasJsonAsync(projectDir);
|
||||
|
||||
Log.addNewLineIfNone();
|
||||
Log.log(`🎉 Your app is configured to use EAS Update!`);
|
||||
Log.log(`🎉 Your app is configured with EAS Update!`);
|
||||
Log.newLine();
|
||||
const easJsonExists = await easJsonExistsAsync(projectDir);
|
||||
if (!easJsonExists) {
|
||||
|
||||
+4
-4
@@ -5,10 +5,10 @@ import gql from 'graphql-tag';
|
||||
import { ExpoGraphqlClient } from '../../../../../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
import { withErrorHandlingAsync } from '../../../../../graphql/client';
|
||||
import {
|
||||
AndroidAppBuildCredentials,
|
||||
AndroidAppBuildCredentialsFragment,
|
||||
AndroidAppBuildCredentialsInput,
|
||||
CreateAndroidAppBuildCredentialsMutation,
|
||||
SetDefaultAndroidAppBuildCredentialsMutation,
|
||||
SetKeystoreMutation,
|
||||
} from '../../../../../graphql/generated';
|
||||
import { AndroidAppBuildCredentialsFragmentNode } from '../../../../../graphql/types/credentials/AndroidAppBuildCredentials';
|
||||
@@ -62,9 +62,9 @@ export const AndroidAppBuildCredentialsMutation = {
|
||||
): Promise<AndroidAppBuildCredentialsFragment> {
|
||||
const data = await withErrorHandlingAsync(
|
||||
graphqlClient
|
||||
.mutation<SetDefaultAndroidAppBuildCredentialsMutation>(
|
||||
.mutation<AndroidAppBuildCredentials>(
|
||||
gql`
|
||||
mutation SetDefaultAndroidAppBuildCredentialsMutation(
|
||||
mutation AndroidAppBuildCredentialsMutation(
|
||||
$androidAppBuildCredentialsId: ID!
|
||||
$isDefault: Boolean!
|
||||
) {
|
||||
@@ -85,7 +85,7 @@ export const AndroidAppBuildCredentialsMutation = {
|
||||
.toPromise()
|
||||
);
|
||||
assert(data, `GraphQL: 'setDefault' not defined in server response ${JSON.stringify(data)}}`);
|
||||
return data.androidAppBuildCredentials.setDefault;
|
||||
return data;
|
||||
},
|
||||
async setKeystoreAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import { testAppJson } from '../../credentials/__tests__/fixtures-constants';
|
||||
import { EASUpdateContext } from '../utils';
|
||||
|
||||
export function createCtxMock(options: { nonInteractive?: boolean } = {}): EASUpdateContext {
|
||||
return {
|
||||
graphqlClient: jest.fn() as any,
|
||||
nonInteractive: options.nonInteractive ?? false,
|
||||
app: { exp: testAppJson, projectId: 'test-project-id' },
|
||||
};
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { ExpoConfig } from '@expo/config-types';
|
||||
|
||||
import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
|
||||
export type EASUpdateContext = {
|
||||
graphqlClient: ExpoGraphqlClient;
|
||||
nonInteractive: boolean;
|
||||
app: { exp: ExpoConfig; projectId: string };
|
||||
};
|
||||
|
||||
export interface EASUpdateAction<T = any> {
|
||||
runAsync(ctx: EASUpdateContext): Promise<T>;
|
||||
}
|
||||
|
||||
export class NonInteractiveError extends Error {}
|
||||
@@ -6,16 +6,7 @@ export async function withErrorHandlingAsync<T>(promise: Promise<OperationResult
|
||||
const { data, error } = await promise;
|
||||
|
||||
if (error) {
|
||||
if (
|
||||
error.graphQLErrors.some(
|
||||
e =>
|
||||
e?.extensions?.isTransient &&
|
||||
![
|
||||
'EAS_BUILD_FREE_TIER_LIMIT_EXCEEDED',
|
||||
'EAS_BUILD_FREE_TIER_IOS_LIMIT_EXCEEDED',
|
||||
].includes(e?.extensions?.errorCode as string)
|
||||
)
|
||||
) {
|
||||
if (error.graphQLErrors.some(e => e?.extensions?.isTransient)) {
|
||||
Log.error(`We've encountered a transient error. Try again shortly.`);
|
||||
}
|
||||
throw error;
|
||||
|
||||
+27
-146
@@ -112,8 +112,6 @@ export type Account = {
|
||||
googleServiceAccountKeys: Array<GoogleServiceAccountKey>;
|
||||
id: Scalars['ID'];
|
||||
isCurrent: Scalars['Boolean'];
|
||||
/** Whether this account has SSO enabled. Can be queried by all members. */
|
||||
isSSOEnabled: Scalars['Boolean'];
|
||||
name: Scalars['String'];
|
||||
/** Offers set on this account */
|
||||
offers?: Maybe<Array<Offer>>;
|
||||
@@ -468,14 +466,20 @@ export type AccountQueryByNameArgs = {
|
||||
/** Auth configuration data for an SSO account. */
|
||||
export type AccountSsoConfiguration = {
|
||||
__typename?: 'AccountSSOConfiguration';
|
||||
authEndpoint?: Maybe<Scalars['String']>;
|
||||
authProtocol: AuthProtocolType;
|
||||
authProviderIdentifier: Scalars['String'];
|
||||
clientIdentifier: Scalars['String'];
|
||||
clientSecret: Scalars['String'];
|
||||
createdAt: Scalars['DateTime'];
|
||||
endSessionEndpoint?: Maybe<Scalars['String']>;
|
||||
id: Scalars['ID'];
|
||||
issuer: Scalars['String'];
|
||||
jwksEndpoint?: Maybe<Scalars['String']>;
|
||||
revokeEndpoint?: Maybe<Scalars['String']>;
|
||||
tokenEndpoint?: Maybe<Scalars['String']>;
|
||||
updatedAt: Scalars['DateTime'];
|
||||
userInfoEndpoint?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type AccountSsoConfigurationData = {
|
||||
@@ -522,11 +526,17 @@ export type AccountSsoConfigurationMutationUpdateAccountSsoConfigurationArgs = {
|
||||
/** Public auth configuration data for an SSO account. */
|
||||
export type AccountSsoConfigurationPublicData = {
|
||||
__typename?: 'AccountSSOConfigurationPublicData';
|
||||
authEndpoint?: Maybe<Scalars['String']>;
|
||||
authProtocol: AuthProtocolType;
|
||||
authProviderIdentifier: Scalars['String'];
|
||||
authorizationUrl: Scalars['String'];
|
||||
clientIdentifier: Scalars['String'];
|
||||
endSessionEndpoint?: Maybe<Scalars['String']>;
|
||||
id: Scalars['ID'];
|
||||
issuer: Scalars['String'];
|
||||
jwksEndpoint?: Maybe<Scalars['String']>;
|
||||
revokeEndpoint?: Maybe<Scalars['String']>;
|
||||
tokenEndpoint?: Maybe<Scalars['String']>;
|
||||
userInfoEndpoint?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type AccountSsoConfigurationPublicDataQuery = {
|
||||
@@ -962,7 +972,6 @@ export type AndroidSubmissionConfig = {
|
||||
/** @deprecated archiveType is deprecated and will be null */
|
||||
archiveType?: Maybe<SubmissionAndroidArchiveType>;
|
||||
releaseStatus?: Maybe<SubmissionAndroidReleaseStatus>;
|
||||
rollout?: Maybe<Scalars['Float']>;
|
||||
track: SubmissionAndroidTrack;
|
||||
};
|
||||
|
||||
@@ -973,7 +982,6 @@ export type AndroidSubmissionConfigInput = {
|
||||
googleServiceAccountKeyId?: InputMaybe<Scalars['String']>;
|
||||
googleServiceAccountKeyJson?: InputMaybe<Scalars['String']>;
|
||||
releaseStatus?: InputMaybe<SubmissionAndroidReleaseStatus>;
|
||||
rollout?: InputMaybe<Scalars['Float']>;
|
||||
track: SubmissionAndroidTrack;
|
||||
};
|
||||
|
||||
@@ -2001,8 +2009,7 @@ export type BackgroundJobReceiptQueryByIdArgs = {
|
||||
};
|
||||
|
||||
export enum BackgroundJobResultType {
|
||||
GithubBuild = 'GITHUB_BUILD',
|
||||
Void = 'VOID'
|
||||
GithubBuild = 'GITHUB_BUILD'
|
||||
}
|
||||
|
||||
export enum BackgroundJobState {
|
||||
@@ -2065,7 +2072,6 @@ export type Build = ActivityTimelineProjectActivity & BuildOrBuildJob & {
|
||||
initiatingUser?: Maybe<User>;
|
||||
iosEnterpriseProvisioning?: Maybe<BuildIosEnterpriseProvisioning>;
|
||||
isGitWorkingTreeDirty?: Maybe<Scalars['Boolean']>;
|
||||
isWaived: Scalars['Boolean'];
|
||||
logFiles: Array<Scalars['String']>;
|
||||
maxBuildTimeSeconds: Scalars['Int'];
|
||||
/** Retry time starts after completedAt */
|
||||
@@ -2236,17 +2242,6 @@ export enum BuildJobStatus {
|
||||
Started = 'STARTED'
|
||||
}
|
||||
|
||||
export type BuildLimitThresholdExceededMetadata = {
|
||||
__typename?: 'BuildLimitThresholdExceededMetadata';
|
||||
account: Account;
|
||||
thresholdsExceeded: Array<NotificationThresholdExceeded>;
|
||||
};
|
||||
|
||||
export enum BuildLimitThresholdExceededMetadataType {
|
||||
Ios = 'IOS',
|
||||
Total = 'TOTAL'
|
||||
}
|
||||
|
||||
export type BuildLogs = {
|
||||
__typename?: 'BuildLogs';
|
||||
format?: Maybe<BuildJobLogsFormat>;
|
||||
@@ -2392,14 +2387,6 @@ export type BuildParamsInput = {
|
||||
sdkVersion?: InputMaybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type BuildPlanCreditThresholdExceededMetadata = {
|
||||
__typename?: 'BuildPlanCreditThresholdExceededMetadata';
|
||||
account: Account;
|
||||
buildCreditUsage: Scalars['Int'];
|
||||
planLimit: Scalars['Int'];
|
||||
threshold: Scalars['Int'];
|
||||
};
|
||||
|
||||
export enum BuildPriority {
|
||||
High = 'HIGH',
|
||||
Normal = 'NORMAL',
|
||||
@@ -2717,11 +2704,6 @@ export type DeleteRobotResult = {
|
||||
id: Scalars['ID'];
|
||||
};
|
||||
|
||||
export type DeleteSsoUserResult = {
|
||||
__typename?: 'DeleteSSOUserResult';
|
||||
id: Scalars['ID'];
|
||||
};
|
||||
|
||||
export type DeleteUpdateBranchResult = {
|
||||
__typename?: 'DeleteUpdateBranchResult';
|
||||
id: Scalars['ID'];
|
||||
@@ -3117,7 +3099,7 @@ export type GitHubRepository = {
|
||||
githubRepositoryIdentifier: Scalars['Int'];
|
||||
githubRepositoryUrl?: Maybe<Scalars['String']>;
|
||||
id: Scalars['ID'];
|
||||
metadata: GitHubRepositoryMetadata;
|
||||
metadata?: Maybe<GitHubRepositoryMetadata>;
|
||||
nodeIdentifier: Scalars['String'];
|
||||
};
|
||||
|
||||
@@ -3130,6 +3112,7 @@ export type GitHubRepositoryMetadata = {
|
||||
githubRepoUrl: Scalars['String'];
|
||||
lastPushed: Scalars['DateTime'];
|
||||
lastUpdated: Scalars['DateTime'];
|
||||
openGraphImageUrl?: Maybe<Scalars['String']>;
|
||||
private: Scalars['Boolean'];
|
||||
};
|
||||
|
||||
@@ -3645,8 +3628,6 @@ export type MeMutation = {
|
||||
createAccount: Account;
|
||||
/** Delete an Account created via createAccount */
|
||||
deleteAccount: DeleteAccountResult;
|
||||
/** Delete a SSO user. Actor must be an owner on the SSO user's SSO account. */
|
||||
deleteSSOUser: DeleteSsoUserResult;
|
||||
/** Delete a second factor device */
|
||||
deleteSecondFactorDevice: SecondFactorBooleanResult;
|
||||
/** Delete a Snack that the current user owns */
|
||||
@@ -3699,11 +3680,6 @@ export type MeMutationDeleteAccountArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MeMutationDeleteSsoUserArgs = {
|
||||
ssoUserId: Scalars['ID'];
|
||||
};
|
||||
|
||||
|
||||
export type MeMutationDeleteSecondFactorDeviceArgs = {
|
||||
otp: Scalars['String'];
|
||||
userSecondFactorDeviceId: Scalars['ID'];
|
||||
@@ -3777,26 +3753,12 @@ export type MeteredBillingStatus = {
|
||||
EAS_UPDATE: Scalars['Boolean'];
|
||||
};
|
||||
|
||||
export type Notification = {
|
||||
__typename?: 'Notification';
|
||||
createdAt: Scalars['DateTime'];
|
||||
event: NotificationEvent;
|
||||
id: Scalars['ID'];
|
||||
metadata?: Maybe<NotificationMetadata>;
|
||||
type: NotificationType;
|
||||
updatedAt: Scalars['DateTime'];
|
||||
};
|
||||
|
||||
export enum NotificationEvent {
|
||||
BuildComplete = 'BUILD_COMPLETE',
|
||||
BuildLimitThresholdExceeded = 'BUILD_LIMIT_THRESHOLD_EXCEEDED',
|
||||
BuildPlanCreditThresholdExceeded = 'BUILD_PLAN_CREDIT_THRESHOLD_EXCEEDED',
|
||||
SubmissionComplete = 'SUBMISSION_COMPLETE',
|
||||
Test = 'TEST'
|
||||
SubmissionComplete = 'SUBMISSION_COMPLETE'
|
||||
}
|
||||
|
||||
export type NotificationMetadata = BuildLimitThresholdExceededMetadata | BuildPlanCreditThresholdExceededMetadata | TestNotificationMetadata;
|
||||
|
||||
export type NotificationSubscription = {
|
||||
__typename?: 'NotificationSubscription';
|
||||
account?: Maybe<Account>;
|
||||
@@ -3837,17 +3799,8 @@ export type NotificationSubscriptionMutationUnsubscribeArgs = {
|
||||
id: Scalars['ID'];
|
||||
};
|
||||
|
||||
export type NotificationThresholdExceeded = {
|
||||
__typename?: 'NotificationThresholdExceeded';
|
||||
count: Scalars['Int'];
|
||||
limit: Scalars['Int'];
|
||||
threshold: Scalars['Int'];
|
||||
type: BuildLimitThresholdExceededMetadataType;
|
||||
};
|
||||
|
||||
export enum NotificationType {
|
||||
Email = 'EMAIL',
|
||||
Web = 'WEB'
|
||||
Email = 'EMAIL'
|
||||
}
|
||||
|
||||
export type Offer = {
|
||||
@@ -4252,8 +4205,6 @@ export type RootQuery = {
|
||||
user: UserQuery;
|
||||
/** Top-level query object for querying UserActors. */
|
||||
userActor: UserActorQuery;
|
||||
/** Top-level query object for querying UserActorPublicData publicly. */
|
||||
userActorPublicData: UserActorPublicDataQuery;
|
||||
/** @deprecated Use 'byId' field under 'user'. */
|
||||
userByUserId?: Maybe<User>;
|
||||
/** @deprecated Use 'byUsername' field under 'user'. */
|
||||
@@ -4350,8 +4301,6 @@ export type SsoUser = Actor & UserActor & {
|
||||
/** @deprecated No longer supported */
|
||||
twitterUsername?: Maybe<Scalars['String']>;
|
||||
username: Scalars['String'];
|
||||
/** Web notifications linked to a user */
|
||||
webNotifications: Array<Notification>;
|
||||
};
|
||||
|
||||
|
||||
@@ -4788,11 +4737,6 @@ export type SubscriptionDetailsPlanEnablementArgs = {
|
||||
serviceMetric: EasServiceMetric;
|
||||
};
|
||||
|
||||
export type TestNotificationMetadata = {
|
||||
__typename?: 'TestNotificationMetadata';
|
||||
message: Scalars['String'];
|
||||
};
|
||||
|
||||
export type TimelineActivityConnection = {
|
||||
__typename?: 'TimelineActivityConnection';
|
||||
edges: Array<TimelineActivityEdge>;
|
||||
@@ -5072,7 +5016,7 @@ export type User = Actor & UserActor & {
|
||||
/** Discord account linked to a user */
|
||||
discordUser?: Maybe<DiscordUser>;
|
||||
displayName: Scalars['String'];
|
||||
email: Scalars['String'];
|
||||
email?: Maybe<Scalars['String']>;
|
||||
emailVerified: Scalars['Boolean'];
|
||||
/**
|
||||
* Server feature gate values for this actor, optionally filtering by desired gates.
|
||||
@@ -5110,7 +5054,6 @@ export type User = Actor & UserActor & {
|
||||
/** @deprecated No longer supported */
|
||||
twitterUsername?: Maybe<Scalars['String']>;
|
||||
username: Scalars['String'];
|
||||
webNotifications: Array<Notification>;
|
||||
};
|
||||
|
||||
|
||||
@@ -5199,8 +5142,6 @@ export type UserActor = {
|
||||
/** @deprecated No longer supported */
|
||||
twitterUsername?: Maybe<Scalars['String']>;
|
||||
username: Scalars['String'];
|
||||
/** Web notifications linked to a user */
|
||||
webNotifications: Array<Notification>;
|
||||
};
|
||||
|
||||
|
||||
@@ -5238,46 +5179,6 @@ export type UserActorSnacksArgs = {
|
||||
offset: Scalars['Int'];
|
||||
};
|
||||
|
||||
/** A human user (type User or SSOUser) that can login to the Expo website, use Expo services, and be a member of accounts. */
|
||||
export type UserActorPublicData = {
|
||||
__typename?: 'UserActorPublicData';
|
||||
/** Apps this user has published */
|
||||
apps: Array<App>;
|
||||
firstName?: Maybe<Scalars['String']>;
|
||||
id: Scalars['ID'];
|
||||
lastName?: Maybe<Scalars['String']>;
|
||||
profilePhoto: Scalars['String'];
|
||||
/** Snacks associated with this user's personal account */
|
||||
snacks: Array<Snack>;
|
||||
username: Scalars['String'];
|
||||
};
|
||||
|
||||
|
||||
/** A human user (type User or SSOUser) that can login to the Expo website, use Expo services, and be a member of accounts. */
|
||||
export type UserActorPublicDataAppsArgs = {
|
||||
includeUnpublished?: InputMaybe<Scalars['Boolean']>;
|
||||
limit: Scalars['Int'];
|
||||
offset: Scalars['Int'];
|
||||
};
|
||||
|
||||
|
||||
/** A human user (type User or SSOUser) that can login to the Expo website, use Expo services, and be a member of accounts. */
|
||||
export type UserActorPublicDataSnacksArgs = {
|
||||
limit: Scalars['Int'];
|
||||
offset: Scalars['Int'];
|
||||
};
|
||||
|
||||
export type UserActorPublicDataQuery = {
|
||||
__typename?: 'UserActorPublicDataQuery';
|
||||
/** Get UserActorPublicData by username */
|
||||
byUsername: UserActorPublicData;
|
||||
};
|
||||
|
||||
|
||||
export type UserActorPublicDataQueryByUsernameArgs = {
|
||||
username: Scalars['String'];
|
||||
};
|
||||
|
||||
export type UserActorQuery = {
|
||||
__typename?: 'UserActorQuery';
|
||||
/** Query a UserActor by ID */
|
||||
@@ -5614,14 +5515,6 @@ export type CreateAndroidAppBuildCredentialsMutationVariables = Exact<{
|
||||
|
||||
export type CreateAndroidAppBuildCredentialsMutation = { __typename?: 'RootMutation', androidAppBuildCredentials: { __typename?: 'AndroidAppBuildCredentialsMutation', createAndroidAppBuildCredentials: { __typename?: 'AndroidAppBuildCredentials', id: string, isDefault: boolean, isLegacy: boolean, name: string, androidKeystore?: { __typename?: 'AndroidKeystore', id: string, type: AndroidKeystoreType, keystore: string, keystorePassword: string, keyAlias: string, keyPassword?: string | null, md5CertificateFingerprint?: string | null, sha1CertificateFingerprint?: string | null, sha256CertificateFingerprint?: string | null, createdAt: any, updatedAt: any } | null } } };
|
||||
|
||||
export type SetDefaultAndroidAppBuildCredentialsMutationVariables = Exact<{
|
||||
androidAppBuildCredentialsId: Scalars['ID'];
|
||||
isDefault: Scalars['Boolean'];
|
||||
}>;
|
||||
|
||||
|
||||
export type SetDefaultAndroidAppBuildCredentialsMutation = { __typename?: 'RootMutation', androidAppBuildCredentials: { __typename?: 'AndroidAppBuildCredentialsMutation', setDefault: { __typename?: 'AndroidAppBuildCredentials', id: string, isDefault: boolean, isLegacy: boolean, name: string, androidKeystore?: { __typename?: 'AndroidKeystore', id: string, type: AndroidKeystoreType, keystore: string, keystorePassword: string, keyAlias: string, keyPassword?: string | null, md5CertificateFingerprint?: string | null, sha1CertificateFingerprint?: string | null, sha256CertificateFingerprint?: string | null, createdAt: any, updatedAt: any } | null } } };
|
||||
|
||||
export type SetKeystoreMutationVariables = Exact<{
|
||||
androidAppBuildCredentialsId: Scalars['ID'];
|
||||
keystoreId: Scalars['ID'];
|
||||
@@ -6105,7 +5998,7 @@ export type CreateAndroidSubmissionMutationVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type CreateAndroidSubmissionMutation = { __typename?: 'RootMutation', submission: { __typename?: 'SubmissionMutation', createAndroidSubmission: { __typename?: 'CreateSubmissionResult', submission: { __typename?: 'Submission', id: string, status: SubmissionStatus, platform: AppPlatform, logsUrl?: string | null, app: { __typename?: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } }, androidConfig?: { __typename?: 'AndroidSubmissionConfig', applicationIdentifier?: string | null, track: SubmissionAndroidTrack, releaseStatus?: SubmissionAndroidReleaseStatus | null, rollout?: number | null } | null, iosConfig?: { __typename?: 'IosSubmissionConfig', ascAppIdentifier: string, appleIdUsername?: string | null } | null, error?: { __typename?: 'SubmissionError', errorCode?: string | null, message?: string | null } | null } } } };
|
||||
export type CreateAndroidSubmissionMutation = { __typename?: 'RootMutation', submission: { __typename?: 'SubmissionMutation', createAndroidSubmission: { __typename?: 'CreateSubmissionResult', submission: { __typename?: 'Submission', id: string, status: SubmissionStatus, platform: AppPlatform, logsUrl?: string | null, app: { __typename?: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } }, androidConfig?: { __typename?: 'AndroidSubmissionConfig', applicationIdentifier?: string | null, track: SubmissionAndroidTrack, releaseStatus?: SubmissionAndroidReleaseStatus | null } | null, iosConfig?: { __typename?: 'IosSubmissionConfig', ascAppIdentifier: string, appleIdUsername?: string | null } | null, error?: { __typename?: 'SubmissionError', errorCode?: string | null, message?: string | null } | null } } } };
|
||||
|
||||
export type CreateIosSubmissionMutationVariables = Exact<{
|
||||
appId: Scalars['ID'];
|
||||
@@ -6115,7 +6008,7 @@ export type CreateIosSubmissionMutationVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type CreateIosSubmissionMutation = { __typename?: 'RootMutation', submission: { __typename?: 'SubmissionMutation', createIosSubmission: { __typename?: 'CreateSubmissionResult', submission: { __typename?: 'Submission', id: string, status: SubmissionStatus, platform: AppPlatform, logsUrl?: string | null, app: { __typename?: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } }, androidConfig?: { __typename?: 'AndroidSubmissionConfig', applicationIdentifier?: string | null, track: SubmissionAndroidTrack, releaseStatus?: SubmissionAndroidReleaseStatus | null, rollout?: number | null } | null, iosConfig?: { __typename?: 'IosSubmissionConfig', ascAppIdentifier: string, appleIdUsername?: string | null } | null, error?: { __typename?: 'SubmissionError', errorCode?: string | null, message?: string | null } | null } } } };
|
||||
export type CreateIosSubmissionMutation = { __typename?: 'RootMutation', submission: { __typename?: 'SubmissionMutation', createIosSubmission: { __typename?: 'CreateSubmissionResult', submission: { __typename?: 'Submission', id: string, status: SubmissionStatus, platform: AppPlatform, logsUrl?: string | null, app: { __typename?: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } }, androidConfig?: { __typename?: 'AndroidSubmissionConfig', applicationIdentifier?: string | null, track: SubmissionAndroidTrack, releaseStatus?: SubmissionAndroidReleaseStatus | null } | null, iosConfig?: { __typename?: 'IosSubmissionConfig', ascAppIdentifier: string, appleIdUsername?: string | null } | null, error?: { __typename?: 'SubmissionError', errorCode?: string | null, message?: string | null } | null } } } };
|
||||
|
||||
export type CreateUploadSessionMutationVariables = Exact<{
|
||||
type: UploadSessionType;
|
||||
@@ -6209,7 +6102,7 @@ export type BuildsWithSubmissionsByIdQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type BuildsWithSubmissionsByIdQuery = { __typename?: 'RootQuery', builds: { __typename?: 'BuildQuery', byId: { __typename?: 'Build', id: string, status: BuildStatus, platform: AppPlatform, channel?: string | null, releaseChannel?: string | null, distribution?: DistributionType | null, iosEnterpriseProvisioning?: BuildIosEnterpriseProvisioning | null, buildProfile?: string | null, sdkVersion?: string | null, appVersion?: string | null, appBuildVersion?: string | null, runtimeVersion?: string | null, gitCommitHash?: string | null, gitCommitMessage?: string | null, initialQueuePosition?: number | null, queuePosition?: number | null, estimatedWaitTimeLeftSeconds?: number | null, priority: BuildPriority, createdAt: any, updatedAt: any, message?: string | null, completedAt?: any | null, resourceClass: BuildResourceClass, expirationDate?: any | null, submissions: Array<{ __typename?: 'Submission', id: string, status: SubmissionStatus, platform: AppPlatform, logsUrl?: string | null, app: { __typename?: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } }, androidConfig?: { __typename?: 'AndroidSubmissionConfig', applicationIdentifier?: string | null, track: SubmissionAndroidTrack, releaseStatus?: SubmissionAndroidReleaseStatus | null, rollout?: number | null } | null, iosConfig?: { __typename?: 'IosSubmissionConfig', ascAppIdentifier: string, appleIdUsername?: string | null } | null, error?: { __typename?: 'SubmissionError', errorCode?: string | null, message?: string | null } | null }>, error?: { __typename?: 'BuildError', errorCode: string, message: string, docsUrl?: string | null } | null, artifacts?: { __typename?: 'BuildArtifacts', buildUrl?: string | null, xcodeBuildLogsUrl?: string | null, applicationArchiveUrl?: string | null } | null, initiatingActor?: { __typename: 'Robot', id: string, displayName: string } | { __typename: 'SSOUser', id: string, displayName: string } | { __typename: 'User', id: string, displayName: string } | null, project: { __typename: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } } | { __typename: 'Snack', id: string, name: string, slug: string } } } };
|
||||
export type BuildsWithSubmissionsByIdQuery = { __typename?: 'RootQuery', builds: { __typename?: 'BuildQuery', byId: { __typename?: 'Build', id: string, status: BuildStatus, platform: AppPlatform, channel?: string | null, releaseChannel?: string | null, distribution?: DistributionType | null, iosEnterpriseProvisioning?: BuildIosEnterpriseProvisioning | null, buildProfile?: string | null, sdkVersion?: string | null, appVersion?: string | null, appBuildVersion?: string | null, runtimeVersion?: string | null, gitCommitHash?: string | null, gitCommitMessage?: string | null, initialQueuePosition?: number | null, queuePosition?: number | null, estimatedWaitTimeLeftSeconds?: number | null, priority: BuildPriority, createdAt: any, updatedAt: any, message?: string | null, completedAt?: any | null, resourceClass: BuildResourceClass, expirationDate?: any | null, submissions: Array<{ __typename?: 'Submission', id: string, status: SubmissionStatus, platform: AppPlatform, logsUrl?: string | null, app: { __typename?: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } }, androidConfig?: { __typename?: 'AndroidSubmissionConfig', applicationIdentifier?: string | null, track: SubmissionAndroidTrack, releaseStatus?: SubmissionAndroidReleaseStatus | null } | null, iosConfig?: { __typename?: 'IosSubmissionConfig', ascAppIdentifier: string, appleIdUsername?: string | null } | null, error?: { __typename?: 'SubmissionError', errorCode?: string | null, message?: string | null } | null }>, error?: { __typename?: 'BuildError', errorCode: string, message: string, docsUrl?: string | null } | null, artifacts?: { __typename?: 'BuildArtifacts', buildUrl?: string | null, xcodeBuildLogsUrl?: string | null, applicationArchiveUrl?: string | null } | null, initiatingActor?: { __typename: 'Robot', id: string, displayName: string } | { __typename: 'SSOUser', id: string, displayName: string } | { __typename: 'User', id: string, displayName: string } | null, project: { __typename: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } } | { __typename: 'Snack', id: string, name: string, slug: string } } } };
|
||||
|
||||
export type ViewBuildsOnAppQueryVariables = Exact<{
|
||||
appId: Scalars['String'];
|
||||
@@ -6224,7 +6117,6 @@ export type ViewBuildsOnAppQuery = { __typename?: 'RootQuery', app: { __typename
|
||||
export type ViewUpdateChannelOnAppQueryVariables = Exact<{
|
||||
appId: Scalars['String'];
|
||||
channelName: Scalars['String'];
|
||||
filter?: InputMaybe<UpdatesFilter>;
|
||||
}>;
|
||||
|
||||
|
||||
@@ -6237,16 +6129,7 @@ export type ViewUpdateChannelsOnAppQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type ViewUpdateChannelsOnAppQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, updateChannels: Array<{ __typename?: 'UpdateChannel', id: string, name: string, createdAt: any, branchMapping: string, updateBranches: Array<{ __typename?: 'UpdateBranch', id: string, name: string, updateGroups: Array<Array<{ __typename?: 'Update', id: string, group: string, message?: string | null, createdAt: any, runtimeVersion: string, platform: string, manifestFragment: string, isRollBackToEmbedded: boolean, manifestPermalink: string, gitCommitHash?: string | null, actor?: { __typename: 'Robot', firstName?: string | null, id: string } | { __typename: 'SSOUser', username: string, id: string } | { __typename: 'User', username: string, id: string } | null, branch: { __typename?: 'UpdateBranch', id: string, name: string }, codeSigningInfo?: { __typename?: 'CodeSigningInfo', keyid: string, sig: string, alg: string } | null }>> }> }> } } };
|
||||
|
||||
export type ViewUpdateChannelsPaginatedOnAppQueryVariables = Exact<{
|
||||
appId: Scalars['String'];
|
||||
first?: InputMaybe<Scalars['Int']>;
|
||||
after?: InputMaybe<Scalars['String']>;
|
||||
}>;
|
||||
|
||||
|
||||
export type ViewUpdateChannelsPaginatedOnAppQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, channelsPaginated: { __typename?: 'AppChannelsConnection', edges: Array<{ __typename?: 'AppChannelEdge', node: { __typename?: 'UpdateChannel', id: string, name: string, branchMapping: string } }>, pageInfo: { __typename?: 'PageInfo', hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: string | null, endCursor?: string | null } } } } };
|
||||
export type ViewUpdateChannelsOnAppQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, updateChannels: Array<{ __typename?: 'UpdateChannel', id: string, name: string, branchMapping: string, updateBranches: Array<{ __typename?: 'UpdateBranch', id: string, name: string, updateGroups: Array<Array<{ __typename?: 'Update', id: string, group: string, message?: string | null, createdAt: any, runtimeVersion: string, platform: string, manifestFragment: string, isRollBackToEmbedded: boolean, manifestPermalink: string, gitCommitHash?: string | null, actor?: { __typename: 'Robot', firstName?: string | null, id: string } | { __typename: 'SSOUser', username: string, id: string } | { __typename: 'User', username: string, id: string } | null, branch: { __typename?: 'UpdateBranch', id: string, name: string }, codeSigningInfo?: { __typename?: 'CodeSigningInfo', keyid: string, sig: string, alg: string } | null }>> }> }> } } };
|
||||
|
||||
export type EnvironmentSecretsByAppIdQueryVariables = Exact<{
|
||||
appId: Scalars['String'];
|
||||
@@ -6281,7 +6164,7 @@ export type SubmissionsByIdQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type SubmissionsByIdQuery = { __typename?: 'RootQuery', submissions: { __typename?: 'SubmissionQuery', byId: { __typename?: 'Submission', id: string, status: SubmissionStatus, platform: AppPlatform, logsUrl?: string | null, app: { __typename?: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } }, androidConfig?: { __typename?: 'AndroidSubmissionConfig', applicationIdentifier?: string | null, track: SubmissionAndroidTrack, releaseStatus?: SubmissionAndroidReleaseStatus | null, rollout?: number | null } | null, iosConfig?: { __typename?: 'IosSubmissionConfig', ascAppIdentifier: string, appleIdUsername?: string | null } | null, error?: { __typename?: 'SubmissionError', errorCode?: string | null, message?: string | null } | null } } };
|
||||
export type SubmissionsByIdQuery = { __typename?: 'RootQuery', submissions: { __typename?: 'SubmissionQuery', byId: { __typename?: 'Submission', id: string, status: SubmissionStatus, platform: AppPlatform, logsUrl?: string | null, app: { __typename?: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } }, androidConfig?: { __typename?: 'AndroidSubmissionConfig', applicationIdentifier?: string | null, track: SubmissionAndroidTrack, releaseStatus?: SubmissionAndroidReleaseStatus | null } | null, iosConfig?: { __typename?: 'IosSubmissionConfig', ascAppIdentifier: string, appleIdUsername?: string | null } | null, error?: { __typename?: 'SubmissionError', errorCode?: string | null, message?: string | null } | null } } };
|
||||
|
||||
export type GetAllSubmissionsForAppQueryVariables = Exact<{
|
||||
appId: Scalars['String'];
|
||||
@@ -6292,7 +6175,7 @@ export type GetAllSubmissionsForAppQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type GetAllSubmissionsForAppQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, submissions: Array<{ __typename?: 'Submission', id: string, status: SubmissionStatus, platform: AppPlatform, logsUrl?: string | null, app: { __typename?: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } }, androidConfig?: { __typename?: 'AndroidSubmissionConfig', applicationIdentifier?: string | null, track: SubmissionAndroidTrack, releaseStatus?: SubmissionAndroidReleaseStatus | null, rollout?: number | null } | null, iosConfig?: { __typename?: 'IosSubmissionConfig', ascAppIdentifier: string, appleIdUsername?: string | null } | null, error?: { __typename?: 'SubmissionError', errorCode?: string | null, message?: string | null } | null }> } } };
|
||||
export type GetAllSubmissionsForAppQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, submissions: Array<{ __typename?: 'Submission', id: string, status: SubmissionStatus, platform: AppPlatform, logsUrl?: string | null, app: { __typename?: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } }, androidConfig?: { __typename?: 'AndroidSubmissionConfig', applicationIdentifier?: string | null, track: SubmissionAndroidTrack, releaseStatus?: SubmissionAndroidReleaseStatus | null } | null, iosConfig?: { __typename?: 'IosSubmissionConfig', ascAppIdentifier: string, appleIdUsername?: string | null } | null, error?: { __typename?: 'SubmissionError', errorCode?: string | null, message?: string | null } | null }> } } };
|
||||
|
||||
export type ViewUpdatesByGroupQueryVariables = Exact<{
|
||||
groupId: Scalars['ID'];
|
||||
@@ -6348,20 +6231,18 @@ export type AppFragment = { __typename?: 'App', id: string, fullName: string, sl
|
||||
|
||||
export type BuildFragment = { __typename?: 'Build', id: string, status: BuildStatus, platform: AppPlatform, channel?: string | null, releaseChannel?: string | null, distribution?: DistributionType | null, iosEnterpriseProvisioning?: BuildIosEnterpriseProvisioning | null, buildProfile?: string | null, sdkVersion?: string | null, appVersion?: string | null, appBuildVersion?: string | null, runtimeVersion?: string | null, gitCommitHash?: string | null, gitCommitMessage?: string | null, initialQueuePosition?: number | null, queuePosition?: number | null, estimatedWaitTimeLeftSeconds?: number | null, priority: BuildPriority, createdAt: any, updatedAt: any, message?: string | null, completedAt?: any | null, resourceClass: BuildResourceClass, expirationDate?: any | null, error?: { __typename?: 'BuildError', errorCode: string, message: string, docsUrl?: string | null } | null, artifacts?: { __typename?: 'BuildArtifacts', buildUrl?: string | null, xcodeBuildLogsUrl?: string | null, applicationArchiveUrl?: string | null } | null, initiatingActor?: { __typename: 'Robot', id: string, displayName: string } | { __typename: 'SSOUser', id: string, displayName: string } | { __typename: 'User', id: string, displayName: string } | null, project: { __typename: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } } | { __typename: 'Snack', id: string, name: string, slug: string } };
|
||||
|
||||
export type BuildWithSubmissionsFragment = { __typename?: 'Build', id: string, status: BuildStatus, platform: AppPlatform, channel?: string | null, releaseChannel?: string | null, distribution?: DistributionType | null, iosEnterpriseProvisioning?: BuildIosEnterpriseProvisioning | null, buildProfile?: string | null, sdkVersion?: string | null, appVersion?: string | null, appBuildVersion?: string | null, runtimeVersion?: string | null, gitCommitHash?: string | null, gitCommitMessage?: string | null, initialQueuePosition?: number | null, queuePosition?: number | null, estimatedWaitTimeLeftSeconds?: number | null, priority: BuildPriority, createdAt: any, updatedAt: any, message?: string | null, completedAt?: any | null, resourceClass: BuildResourceClass, expirationDate?: any | null, submissions: Array<{ __typename?: 'Submission', id: string, status: SubmissionStatus, platform: AppPlatform, logsUrl?: string | null, app: { __typename?: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } }, androidConfig?: { __typename?: 'AndroidSubmissionConfig', applicationIdentifier?: string | null, track: SubmissionAndroidTrack, releaseStatus?: SubmissionAndroidReleaseStatus | null, rollout?: number | null } | null, iosConfig?: { __typename?: 'IosSubmissionConfig', ascAppIdentifier: string, appleIdUsername?: string | null } | null, error?: { __typename?: 'SubmissionError', errorCode?: string | null, message?: string | null } | null }>, error?: { __typename?: 'BuildError', errorCode: string, message: string, docsUrl?: string | null } | null, artifacts?: { __typename?: 'BuildArtifacts', buildUrl?: string | null, xcodeBuildLogsUrl?: string | null, applicationArchiveUrl?: string | null } | null, initiatingActor?: { __typename: 'Robot', id: string, displayName: string } | { __typename: 'SSOUser', id: string, displayName: string } | { __typename: 'User', id: string, displayName: string } | null, project: { __typename: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } } | { __typename: 'Snack', id: string, name: string, slug: string } };
|
||||
export type BuildWithSubmissionsFragment = { __typename?: 'Build', id: string, status: BuildStatus, platform: AppPlatform, channel?: string | null, releaseChannel?: string | null, distribution?: DistributionType | null, iosEnterpriseProvisioning?: BuildIosEnterpriseProvisioning | null, buildProfile?: string | null, sdkVersion?: string | null, appVersion?: string | null, appBuildVersion?: string | null, runtimeVersion?: string | null, gitCommitHash?: string | null, gitCommitMessage?: string | null, initialQueuePosition?: number | null, queuePosition?: number | null, estimatedWaitTimeLeftSeconds?: number | null, priority: BuildPriority, createdAt: any, updatedAt: any, message?: string | null, completedAt?: any | null, resourceClass: BuildResourceClass, expirationDate?: any | null, submissions: Array<{ __typename?: 'Submission', id: string, status: SubmissionStatus, platform: AppPlatform, logsUrl?: string | null, app: { __typename?: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } }, androidConfig?: { __typename?: 'AndroidSubmissionConfig', applicationIdentifier?: string | null, track: SubmissionAndroidTrack, releaseStatus?: SubmissionAndroidReleaseStatus | null } | null, iosConfig?: { __typename?: 'IosSubmissionConfig', ascAppIdentifier: string, appleIdUsername?: string | null } | null, error?: { __typename?: 'SubmissionError', errorCode?: string | null, message?: string | null } | null }>, error?: { __typename?: 'BuildError', errorCode: string, message: string, docsUrl?: string | null } | null, artifacts?: { __typename?: 'BuildArtifacts', buildUrl?: string | null, xcodeBuildLogsUrl?: string | null, applicationArchiveUrl?: string | null } | null, initiatingActor?: { __typename: 'Robot', id: string, displayName: string } | { __typename: 'SSOUser', id: string, displayName: string } | { __typename: 'User', id: string, displayName: string } | null, project: { __typename: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } } | { __typename: 'Snack', id: string, name: string, slug: string } };
|
||||
|
||||
export type EnvironmentSecretFragment = { __typename?: 'EnvironmentSecret', id: string, name: string, type: EnvironmentSecretType, createdAt: any };
|
||||
|
||||
export type StatuspageServiceFragment = { __typename?: 'StatuspageService', id: string, name: StatuspageServiceName, status: StatuspageServiceStatus, incidents: Array<{ __typename?: 'StatuspageIncident', id: string, status: StatuspageIncidentStatus, name: string, impact: StatuspageIncidentImpact, shortlink: string }> };
|
||||
|
||||
export type SubmissionFragment = { __typename?: 'Submission', id: string, status: SubmissionStatus, platform: AppPlatform, logsUrl?: string | null, app: { __typename?: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } }, androidConfig?: { __typename?: 'AndroidSubmissionConfig', applicationIdentifier?: string | null, track: SubmissionAndroidTrack, releaseStatus?: SubmissionAndroidReleaseStatus | null, rollout?: number | null } | null, iosConfig?: { __typename?: 'IosSubmissionConfig', ascAppIdentifier: string, appleIdUsername?: string | null } | null, error?: { __typename?: 'SubmissionError', errorCode?: string | null, message?: string | null } | null };
|
||||
export type SubmissionFragment = { __typename?: 'Submission', id: string, status: SubmissionStatus, platform: AppPlatform, logsUrl?: string | null, app: { __typename?: 'App', id: string, name: string, slug: string, ownerAccount: { __typename?: 'Account', id: string, name: string } }, androidConfig?: { __typename?: 'AndroidSubmissionConfig', applicationIdentifier?: string | null, track: SubmissionAndroidTrack, releaseStatus?: SubmissionAndroidReleaseStatus | null } | null, iosConfig?: { __typename?: 'IosSubmissionConfig', ascAppIdentifier: string, appleIdUsername?: string | null } | null, error?: { __typename?: 'SubmissionError', errorCode?: string | null, message?: string | null } | null };
|
||||
|
||||
export type UpdateFragment = { __typename?: 'Update', id: string, group: string, message?: string | null, createdAt: any, runtimeVersion: string, platform: string, manifestFragment: string, isRollBackToEmbedded: boolean, manifestPermalink: string, gitCommitHash?: string | null, actor?: { __typename: 'Robot', firstName?: string | null, id: string } | { __typename: 'SSOUser', username: string, id: string } | { __typename: 'User', username: string, id: string } | null, branch: { __typename?: 'UpdateBranch', id: string, name: string }, codeSigningInfo?: { __typename?: 'CodeSigningInfo', keyid: string, sig: string, alg: string } | null };
|
||||
|
||||
export type UpdateBranchFragment = { __typename?: 'UpdateBranch', id: string, name: string, updates: Array<{ __typename?: 'Update', id: string, group: string, message?: string | null, createdAt: any, runtimeVersion: string, platform: string, manifestFragment: string, isRollBackToEmbedded: boolean, manifestPermalink: string, gitCommitHash?: string | null, actor?: { __typename: 'Robot', firstName?: string | null, id: string } | { __typename: 'SSOUser', username: string, id: string } | { __typename: 'User', username: string, id: string } | null, branch: { __typename?: 'UpdateBranch', id: string, name: string }, codeSigningInfo?: { __typename?: 'CodeSigningInfo', keyid: string, sig: string, alg: string } | null }> };
|
||||
|
||||
export type UpdateChannelBasicInfoFragment = { __typename?: 'UpdateChannel', id: string, name: string, branchMapping: string };
|
||||
|
||||
export type WebhookFragment = { __typename?: 'Webhook', id: string, event: WebhookType, url: string, createdAt: any, updatedAt: any };
|
||||
|
||||
export type AndroidAppBuildCredentialsFragment = { __typename?: 'AndroidAppBuildCredentials', id: string, isDefault: boolean, isLegacy: boolean, name: string, androidKeystore?: { __typename?: 'AndroidKeystore', id: string, type: AndroidKeystoreType, keystore: string, keystorePassword: string, keyAlias: string, keyPassword?: string | null, md5CertificateFingerprint?: string | null, sha1CertificateFingerprint?: string | null, sha256CertificateFingerprint?: string | null, createdAt: any, updatedAt: any } | null };
|
||||
|
||||
@@ -9,39 +9,27 @@ import {
|
||||
ViewUpdateChannelOnAppQueryVariables,
|
||||
ViewUpdateChannelsOnAppQuery,
|
||||
ViewUpdateChannelsOnAppQueryVariables,
|
||||
ViewUpdateChannelsPaginatedOnAppQuery,
|
||||
ViewUpdateChannelsPaginatedOnAppQueryVariables,
|
||||
} from '../generated';
|
||||
import { UpdateFragmentNode } from '../types/Update';
|
||||
import { UpdateChannelBasicInfoFragmentNode } from '../types/UpdateChannelBasicInfo';
|
||||
|
||||
type ViewUpdateChannelsOnAppObject = NonNullable<
|
||||
export type UpdateChannelObject = NonNullable<
|
||||
ViewUpdateChannelsOnAppQuery['app']['byId']['updateChannels']
|
||||
>[number];
|
||||
|
||||
type UpdateChannelByNameObject = NonNullable<
|
||||
export type UpdateChannelByNameObject = NonNullable<
|
||||
ViewUpdateChannelOnAppQuery['app']['byId']['updateChannelByName']
|
||||
>;
|
||||
|
||||
// these types should have the same fields
|
||||
export type UpdateChannelObject = ViewUpdateChannelsOnAppObject & UpdateChannelByNameObject;
|
||||
|
||||
export type UpdateBranchObject = UpdateChannelObject['updateBranches'][number];
|
||||
|
||||
export const ChannelQuery = {
|
||||
async viewUpdateChannelAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
{ appId, channelName, filter }: ViewUpdateChannelOnAppQueryVariables
|
||||
{ appId, channelName }: ViewUpdateChannelOnAppQueryVariables
|
||||
): Promise<UpdateChannelByNameObject> {
|
||||
const response = await withErrorHandlingAsync(
|
||||
graphqlClient
|
||||
.query<ViewUpdateChannelOnAppQuery, ViewUpdateChannelOnAppQueryVariables>(
|
||||
gql`
|
||||
query ViewUpdateChannelOnApp(
|
||||
$appId: String!
|
||||
$channelName: String!
|
||||
$filter: UpdatesFilter
|
||||
) {
|
||||
query ViewUpdateChannelOnApp($appId: String!, $channelName: String!) {
|
||||
app {
|
||||
byId(appId: $appId) {
|
||||
id
|
||||
@@ -53,7 +41,7 @@ export const ChannelQuery = {
|
||||
updateBranches(offset: 0, limit: 5) {
|
||||
id
|
||||
name
|
||||
updateGroups(offset: 0, limit: 1, filter: $filter) {
|
||||
updateGroups(offset: 0, limit: 1) {
|
||||
id
|
||||
...UpdateFragment
|
||||
}
|
||||
@@ -64,7 +52,7 @@ export const ChannelQuery = {
|
||||
}
|
||||
${print(UpdateFragmentNode)}
|
||||
`,
|
||||
{ appId, channelName, filter },
|
||||
{ appId, channelName },
|
||||
{ additionalTypenames: ['UpdateChannel', 'UpdateBranch', 'Update'] }
|
||||
)
|
||||
.toPromise()
|
||||
@@ -92,7 +80,6 @@ export const ChannelQuery = {
|
||||
updateChannels(offset: $offset, limit: $limit) {
|
||||
id
|
||||
name
|
||||
createdAt
|
||||
branchMapping
|
||||
updateBranches(offset: 0, limit: 5) {
|
||||
id
|
||||
@@ -121,50 +108,4 @@ export const ChannelQuery = {
|
||||
|
||||
return updateChannels;
|
||||
},
|
||||
async viewUpdateChannelsBasicInfoPaginatedOnAppAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
{ appId, first, after }: ViewUpdateChannelsPaginatedOnAppQueryVariables
|
||||
): Promise<ViewUpdateChannelsPaginatedOnAppQuery['app']['byId']['channelsPaginated']> {
|
||||
const response = await withErrorHandlingAsync(
|
||||
graphqlClient
|
||||
.query<
|
||||
ViewUpdateChannelsPaginatedOnAppQuery,
|
||||
ViewUpdateChannelsPaginatedOnAppQueryVariables
|
||||
>(
|
||||
gql`
|
||||
query ViewUpdateChannelsPaginatedOnApp($appId: String!, $first: Int, $after: String) {
|
||||
app {
|
||||
byId(appId: $appId) {
|
||||
id
|
||||
channelsPaginated(first: $first, after: $after) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
...UpdateChannelBasicInfoFragment
|
||||
}
|
||||
}
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
hasPreviousPage
|
||||
startCursor
|
||||
endCursor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${print(UpdateChannelBasicInfoFragmentNode)}
|
||||
`,
|
||||
{ appId, first, after },
|
||||
{ additionalTypenames: ['UpdateChannel', 'UpdateBranch', 'Update'] }
|
||||
)
|
||||
.toPromise()
|
||||
);
|
||||
const { channelsPaginated } = response.app.byId;
|
||||
|
||||
if (!channelsPaginated) {
|
||||
throw new Error(`Could not find channels on project with id ${appId}`);
|
||||
}
|
||||
return channelsPaginated;
|
||||
},
|
||||
};
|
||||
@@ -18,7 +18,6 @@ export const SubmissionFragmentNode = gql`
|
||||
applicationIdentifier
|
||||
track
|
||||
releaseStatus
|
||||
rollout
|
||||
}
|
||||
iosConfig {
|
||||
ascAppIdentifier
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
export const UpdateChannelBasicInfoFragmentNode = gql`
|
||||
fragment UpdateChannelBasicInfoFragment on UpdateChannel {
|
||||
id
|
||||
name
|
||||
branchMapping
|
||||
}
|
||||
`;
|
||||
@@ -3,7 +3,6 @@ import { Env } from '@expo/eas-build-job';
|
||||
import JsonFile from '@expo/json-file';
|
||||
import fs from 'fs-extra';
|
||||
import Joi from 'joi';
|
||||
import nullthrows from 'nullthrows';
|
||||
import path from 'path';
|
||||
|
||||
export type PublicExpoConfig = Omit<
|
||||
@@ -94,24 +93,19 @@ export function ensureExpoConfigExists(projectDir: string): void {
|
||||
}
|
||||
|
||||
async function ensureStaticExpoConfigIsValidAsync(projectDir: string): Promise<void> {
|
||||
if (isUsingStaticExpoConfig(projectDir)) {
|
||||
const staticConfigPath = nullthrows(getConfigFilePaths(projectDir).staticConfigPath);
|
||||
const staticConfig = await JsonFile.readAsync(staticConfigPath);
|
||||
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(staticConfigPath, staticConfig);
|
||||
await JsonFile.writeAsync(paths.staticConfigPath, staticConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function isUsingStaticExpoConfig(projectDir: string): boolean {
|
||||
const paths = getConfigFilePaths(projectDir);
|
||||
return !!(paths.staticConfigPath?.endsWith('app.json') && !paths.dynamicConfigPath);
|
||||
}
|
||||
|
||||
export function getPublicExpoConfig(
|
||||
projectDir: string,
|
||||
opts: ExpoConfigOptions = {}
|
||||
|
||||
@@ -3,7 +3,6 @@ import { JSONObject } from '@expo/json-file';
|
||||
import { getPrebuildConfigAsync } from '@expo/prebuild-config';
|
||||
|
||||
import { readPlistAsync } from '../../utils/plist';
|
||||
import { hasIgnoredIosProjectAsync } from '../workflow';
|
||||
|
||||
interface Target {
|
||||
buildConfiguration?: string;
|
||||
@@ -14,7 +13,6 @@ export async function getManagedApplicationTargetEntitlementsAsync(
|
||||
env: Record<string, string>
|
||||
): Promise<JSONObject> {
|
||||
const originalProcessEnv: NodeJS.ProcessEnv = process.env;
|
||||
|
||||
try {
|
||||
process.env = {
|
||||
...process.env,
|
||||
@@ -26,7 +24,6 @@ export async function getManagedApplicationTargetEntitlementsAsync(
|
||||
projectRoot: projectDir,
|
||||
platforms: ['ios'],
|
||||
introspect: true,
|
||||
ignoreExistingNativeFiles: await hasIgnoredIosProjectAsync(projectDir),
|
||||
});
|
||||
return expWithMods.ios?.entitlements || {};
|
||||
} finally {
|
||||
|
||||
@@ -38,7 +38,7 @@ const AppExtensionsConfigSchema = Joi.array().items(
|
||||
})
|
||||
);
|
||||
|
||||
export async function resolveManagedProjectTargetsAsync({
|
||||
export async function resolveMangedProjectTargetsAsync({
|
||||
exp,
|
||||
projectDir,
|
||||
xcodeBuildContext,
|
||||
@@ -138,7 +138,7 @@ export async function resolveTargetsAsync(opts: ResolveTargetOptions): Promise<T
|
||||
if (workflow === Workflow.GENERIC) {
|
||||
return await resolveBareProjectTargetsAsync(opts);
|
||||
} else if (workflow === Workflow.MANAGED) {
|
||||
return await resolveManagedProjectTargetsAsync(opts);
|
||||
return await resolveMangedProjectTargetsAsync(opts);
|
||||
} else {
|
||||
throw new Error(`Unknown workflow: ${workflow}`);
|
||||
}
|
||||
|
||||
@@ -84,6 +84,13 @@ 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);
|
||||
}
|
||||
|
||||
@@ -644,9 +644,7 @@ export async function getRuntimeVersionObjectAsync(
|
||||
Workflow.MANAGED;
|
||||
if (!isManaged) {
|
||||
throw new Error(
|
||||
`You're currently using the bare workflow, where runtime version policies are not supported. You must set your runtime version manually. For example, define your runtime version as "1.0.0", not {"policy": "appVersion"} in your app config. ${learnMore(
|
||||
'https://docs.expo.dev/eas-update/runtime-versions'
|
||||
)}`
|
||||
'Runtime version policies are only supported in the managed workflow. In the bare workflow, runtime version needs to be set manually.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,15 +44,3 @@ export async function resolveWorkflowPerPlatformAsync(
|
||||
]);
|
||||
return { android, ios };
|
||||
}
|
||||
|
||||
export async function hasIgnoredIosProjectAsync(projectDir: string): Promise<boolean> {
|
||||
const vcsClient = getVcsClient();
|
||||
const vcsRootPath = path.normalize(await vcsClient.getRootPathAsync());
|
||||
|
||||
try {
|
||||
const pbxProjectPath = IOSConfig.Paths.getPBXProjectPath(projectDir);
|
||||
return await vcsClient.isFileIgnoredAsync(path.relative(vcsRootPath, pbxProjectPath));
|
||||
} finally {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,269 +0,0 @@
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import {
|
||||
testChannelObject,
|
||||
testUpdateBranch1,
|
||||
testUpdateBranch2,
|
||||
} from '../../channel/__tests__/fixtures';
|
||||
import {
|
||||
BranchMappingOperator,
|
||||
alwaysTrue,
|
||||
andStatement,
|
||||
equalsOperator,
|
||||
hashLtOperator,
|
||||
} from '../../channel/branch-mapping';
|
||||
import {
|
||||
editRolloutBranchMapping,
|
||||
getRollout,
|
||||
getRolloutInfoFromBranchMapping,
|
||||
isConstrainedRollout,
|
||||
isConstrainedRolloutInfo,
|
||||
isLegacyRolloutInfo,
|
||||
isRollout,
|
||||
} from '../branch-mapping';
|
||||
import {
|
||||
rolloutBranchMapping,
|
||||
rolloutBranchMappingLegacy,
|
||||
standardBranchMapping,
|
||||
} from './fixtures';
|
||||
|
||||
describe(isLegacyRolloutInfo, () => {
|
||||
it('classifies rollouts properly', () => {
|
||||
const constrainedRollout = getRolloutInfoFromBranchMapping(rolloutBranchMapping);
|
||||
expect(isLegacyRolloutInfo(constrainedRollout)).toBe(false);
|
||||
const legacyRollout = getRolloutInfoFromBranchMapping(rolloutBranchMappingLegacy);
|
||||
expect(isLegacyRolloutInfo(legacyRollout)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe(isConstrainedRollout, () => {
|
||||
it('classifies rollouts properly', () => {
|
||||
const constrainedRollout = getRolloutInfoFromBranchMapping(rolloutBranchMapping);
|
||||
expect(isConstrainedRolloutInfo(constrainedRollout)).toBe(true);
|
||||
const legacyRollout = getRolloutInfoFromBranchMapping(rolloutBranchMappingLegacy);
|
||||
expect(isConstrainedRolloutInfo(legacyRollout)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe(getRollout, () => {
|
||||
it('doesnt get the mapping if it isnt a rollout', () => {
|
||||
const notRollout = { ...testChannelObject };
|
||||
notRollout.branchMapping = JSON.stringify(standardBranchMapping);
|
||||
expect(() => getRollout(notRollout)).toThrowError();
|
||||
});
|
||||
it('gets a constrained rollout', () => {
|
||||
const constrainedRollout = { ...testChannelObject };
|
||||
const rolloutBranchMappingWithCorrectBranch = { ...rolloutBranchMapping };
|
||||
rolloutBranchMappingWithCorrectBranch.data[0].branchId = testUpdateBranch1.id;
|
||||
rolloutBranchMappingWithCorrectBranch.data[1].branchId = testUpdateBranch2.id;
|
||||
constrainedRollout.branchMapping = JSON.stringify(rolloutBranchMapping);
|
||||
|
||||
const rollout = getRollout(constrainedRollout);
|
||||
expect(rollout.percentRolledOut).toEqual(10);
|
||||
expect(isConstrainedRolloutInfo(rollout)).toBe(true);
|
||||
expect(rollout.defaultBranch).toEqual(testUpdateBranch2);
|
||||
expect(rollout.rolledOutBranch).toEqual(testUpdateBranch1);
|
||||
expect(rollout.defaultBranchId).toEqual(testUpdateBranch2.id);
|
||||
expect(rollout.rolledOutBranchId).toEqual(testUpdateBranch1.id);
|
||||
});
|
||||
it('gets a legacy rollout', () => {
|
||||
const rollout = getRollout(testChannelObject);
|
||||
expect(rollout.percentRolledOut).toEqual(15);
|
||||
expect(isLegacyRolloutInfo(rollout)).toBe(true);
|
||||
expect(rollout.defaultBranch).toEqual(testUpdateBranch2);
|
||||
expect(rollout.rolledOutBranch).toEqual(testUpdateBranch1);
|
||||
expect(rollout.defaultBranchId).toEqual(testUpdateBranch2.id);
|
||||
expect(rollout.rolledOutBranchId).toEqual(testUpdateBranch1.id);
|
||||
});
|
||||
});
|
||||
|
||||
describe(getRolloutInfoFromBranchMapping, () => {
|
||||
it('doesnt get the mapping if it isnt a rollout', () => {
|
||||
expect(() => getRolloutInfoFromBranchMapping(standardBranchMapping)).toThrowError();
|
||||
});
|
||||
it('gets a constrained rollout', () => {
|
||||
const rollout = getRolloutInfoFromBranchMapping(rolloutBranchMapping);
|
||||
expect(rollout.percentRolledOut).toEqual(10);
|
||||
expect(isConstrainedRolloutInfo(rollout)).toBe(true);
|
||||
expect(rollout.defaultBranchId).toEqual(rolloutBranchMapping.data[1].branchId);
|
||||
expect(rollout.rolledOutBranchId).toEqual(rolloutBranchMapping.data[0].branchId);
|
||||
});
|
||||
it('gets a legacy rollout', () => {
|
||||
const rollout = getRolloutInfoFromBranchMapping(rolloutBranchMappingLegacy);
|
||||
expect(rollout.percentRolledOut).toEqual(10);
|
||||
expect(isLegacyRolloutInfo(rollout)).toBe(true);
|
||||
expect(rollout.defaultBranchId).toEqual(rolloutBranchMappingLegacy.data[1].branchId);
|
||||
expect(rollout.rolledOutBranchId).toEqual(rolloutBranchMappingLegacy.data[0].branchId);
|
||||
});
|
||||
});
|
||||
|
||||
describe(editRolloutBranchMapping, () => {
|
||||
it('doesnt edit the branch mapping if it isnt a rollout', () => {
|
||||
expect(() => editRolloutBranchMapping(standardBranchMapping, 50)).toThrowError();
|
||||
});
|
||||
it('doesnt edit the branch mapping if the input is out of range', () => {
|
||||
expect(() => editRolloutBranchMapping(standardBranchMapping, -1)).toThrowError();
|
||||
expect(() => editRolloutBranchMapping(standardBranchMapping, 101)).toThrowError();
|
||||
expect(() => editRolloutBranchMapping(standardBranchMapping, 0.1)).toThrowError();
|
||||
});
|
||||
it('edits the branch mapping for a constrained rollout', () => {
|
||||
const editedBranchMapping = editRolloutBranchMapping(rolloutBranchMapping, 50);
|
||||
const rollout = getRolloutInfoFromBranchMapping(editedBranchMapping);
|
||||
expect(rollout.percentRolledOut).toEqual(50);
|
||||
expect(isConstrainedRolloutInfo(rollout)).toBe(true);
|
||||
});
|
||||
it('edits the branch mapping for a legacy rollout', () => {
|
||||
const editedBranchMapping = editRolloutBranchMapping(rolloutBranchMappingLegacy, 50);
|
||||
const rollout = getRolloutInfoFromBranchMapping(editedBranchMapping);
|
||||
expect(rollout.percentRolledOut).toEqual(50);
|
||||
expect(isLegacyRolloutInfo(rollout)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe(isRollout, () => {
|
||||
it('detects a rollout made by the cli', () => {
|
||||
expect(isRollout(rolloutBranchMappingLegacy)).toBe(true);
|
||||
expect(isRollout(rolloutBranchMapping)).toBe(true);
|
||||
});
|
||||
it('detects custom mappings equivalent to rollouts made by the cli', () => {
|
||||
const customMapping1 = {
|
||||
version: 0,
|
||||
data: [
|
||||
{
|
||||
branchId: uuidv4(),
|
||||
branchMappingLogic: andStatement([
|
||||
{
|
||||
operand: 10 / 100,
|
||||
clientKey: 'rolloutToken',
|
||||
branchMappingOperator: hashLtOperator(),
|
||||
},
|
||||
{
|
||||
operand: '1.0.0',
|
||||
clientKey: 'runtimeVersion',
|
||||
branchMappingOperator: equalsOperator(),
|
||||
},
|
||||
]),
|
||||
},
|
||||
{ branchId: uuidv4(), branchMappingLogic: alwaysTrue() },
|
||||
],
|
||||
};
|
||||
expect(isRollout(customMapping1)).toBe(true);
|
||||
});
|
||||
it('correctly classifies branchMappings that arent rollouts', () => {
|
||||
expect(isRollout(standardBranchMapping)).toBe(false);
|
||||
|
||||
const customMapping1 = {
|
||||
version: 0,
|
||||
data: [
|
||||
{
|
||||
branchId: uuidv4(),
|
||||
branchMappingLogic: {
|
||||
operand: 10 / 100,
|
||||
clientKey: 'rolloutToken',
|
||||
branchMappingOperator: 'hash_gt' as BranchMappingOperator,
|
||||
},
|
||||
},
|
||||
{ branchId: uuidv4(), branchMappingLogic: alwaysTrue() },
|
||||
],
|
||||
};
|
||||
expect(isRollout(customMapping1)).toBe(false);
|
||||
|
||||
const customMapping2 = {
|
||||
version: 0,
|
||||
data: [
|
||||
{
|
||||
branchId: uuidv4(),
|
||||
branchMappingLogic: andStatement([
|
||||
{
|
||||
operand: '1.0.0',
|
||||
clientKey: 'runtimeVersion',
|
||||
branchMappingOperator: equalsOperator(),
|
||||
},
|
||||
{
|
||||
operand: 10 / 100,
|
||||
clientKey: 'FOOBAR',
|
||||
branchMappingOperator: hashLtOperator(),
|
||||
},
|
||||
]),
|
||||
},
|
||||
{ branchId: uuidv4(), branchMappingLogic: alwaysTrue() },
|
||||
],
|
||||
};
|
||||
expect(isRollout(customMapping2)).toBe(false);
|
||||
|
||||
const customMapping3 = {
|
||||
version: 0,
|
||||
data: [
|
||||
{
|
||||
branchId: uuidv4(),
|
||||
branchMappingLogic: {
|
||||
operand: 10 / 100,
|
||||
clientKey: 'FOOBAR',
|
||||
branchMappingOperator: hashLtOperator(),
|
||||
},
|
||||
},
|
||||
{ branchId: uuidv4(), branchMappingLogic: alwaysTrue() },
|
||||
],
|
||||
};
|
||||
expect(isRollout(customMapping3)).toBe(false);
|
||||
|
||||
const customMapping4 = {
|
||||
version: 0,
|
||||
data: [
|
||||
{
|
||||
branchId: uuidv4(),
|
||||
branchMappingLogic: {
|
||||
operand: 10 / 100,
|
||||
clientKey: 'FOOBAR',
|
||||
branchMappingOperator: hashLtOperator(),
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
expect(isRollout(customMapping4)).toBe(false);
|
||||
|
||||
const customMapping5 = {
|
||||
version: 0,
|
||||
data: [
|
||||
{
|
||||
branchId: uuidv4(),
|
||||
branchMappingLogic: andStatement([
|
||||
{
|
||||
operand: '1.0.0',
|
||||
clientKey: 'runtimeVersion',
|
||||
branchMappingOperator: equalsOperator(),
|
||||
},
|
||||
{
|
||||
operand: 10 / 100,
|
||||
clientKey: 'rolloutToken',
|
||||
branchMappingOperator: hashLtOperator(),
|
||||
},
|
||||
{
|
||||
operand: '2.0.0',
|
||||
clientKey: 'runtimeVersion',
|
||||
branchMappingOperator: equalsOperator(),
|
||||
},
|
||||
]),
|
||||
},
|
||||
{ branchId: uuidv4(), branchMappingLogic: alwaysTrue() },
|
||||
],
|
||||
};
|
||||
expect(isRollout(customMapping5)).toBe(false);
|
||||
|
||||
const customMapping6 = {
|
||||
version: 0,
|
||||
data: [
|
||||
{ branchId: uuidv4(), branchMappingLogic: alwaysTrue() },
|
||||
{
|
||||
branchId: uuidv4(),
|
||||
branchMappingLogic: {
|
||||
operand: 10 / 100,
|
||||
clientKey: 'rolloutToken',
|
||||
branchMappingOperator: hashLtOperator(),
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
expect(isRollout(customMapping6)).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -1,50 +0,0 @@
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import {
|
||||
alwaysTrue,
|
||||
andStatement,
|
||||
equalsOperator,
|
||||
hashLtOperator,
|
||||
} from '../../channel/branch-mapping';
|
||||
|
||||
export const rolloutBranchMapping = {
|
||||
version: 0,
|
||||
data: [
|
||||
{
|
||||
branchId: uuidv4(),
|
||||
branchMappingLogic: andStatement([
|
||||
{
|
||||
operand: '1.0.0',
|
||||
clientKey: 'runtimeVersion',
|
||||
branchMappingOperator: equalsOperator(),
|
||||
},
|
||||
{
|
||||
operand: 10 / 100,
|
||||
clientKey: 'rolloutToken',
|
||||
branchMappingOperator: hashLtOperator(),
|
||||
},
|
||||
]),
|
||||
},
|
||||
{ branchId: uuidv4(), branchMappingLogic: alwaysTrue() },
|
||||
],
|
||||
};
|
||||
|
||||
export const rolloutBranchMappingLegacy = {
|
||||
version: 0,
|
||||
data: [
|
||||
{
|
||||
branchId: uuidv4(),
|
||||
branchMappingLogic: {
|
||||
operand: 10 / 100,
|
||||
clientKey: 'rolloutToken',
|
||||
branchMappingOperator: hashLtOperator(),
|
||||
},
|
||||
},
|
||||
{ branchId: uuidv4(), branchMappingLogic: alwaysTrue() },
|
||||
],
|
||||
};
|
||||
|
||||
export const standardBranchMapping = {
|
||||
version: 0,
|
||||
data: [{ branchId: uuidv4(), branchMappingLogic: alwaysTrue() }],
|
||||
};
|
||||
@@ -1,22 +0,0 @@
|
||||
import { SelectChannel } from '../../channel/actions/SelectChannel';
|
||||
import { getBranchMapping } from '../../channel/branch-mapping';
|
||||
import { EASUpdateAction, EASUpdateContext } from '../../eas-update/utils';
|
||||
import { UpdateChannelBasicInfoFragment } from '../../graphql/generated';
|
||||
import { isRollout } from '../branch-mapping';
|
||||
|
||||
/**
|
||||
* Select an existing rollout for the project.
|
||||
*/
|
||||
export class SelectRollout implements EASUpdateAction<UpdateChannelBasicInfoFragment | null> {
|
||||
public async runAsync(ctx: EASUpdateContext): Promise<UpdateChannelBasicInfoFragment | null> {
|
||||
const rolloutFilterPredicate = (channelInfo: UpdateChannelBasicInfoFragment): boolean => {
|
||||
const branchMapping = getBranchMapping(channelInfo.branchMapping);
|
||||
return isRollout(branchMapping);
|
||||
};
|
||||
const selectChannel = new SelectChannel({
|
||||
printedType: 'rollout',
|
||||
filterPredicate: rolloutFilterPredicate,
|
||||
});
|
||||
return await selectChannel.runAsync(ctx);
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
import { testBasicChannelInfo, testBasicChannelInfo2 } from '../../../channel/__tests__/fixtures';
|
||||
import { getChannelsDatasetAsync } from '../../../channel/queries';
|
||||
import { createCtxMock } from '../../../eas-update/__tests__/fixtures';
|
||||
import { NonInteractiveError } from '../../../eas-update/utils';
|
||||
import { promptAsync } from '../../../prompts';
|
||||
import { standardBranchMapping } from '../../__tests__/fixtures';
|
||||
import { SelectRollout } from '../SelectRollout';
|
||||
|
||||
jest.mock('../../../channel/queries');
|
||||
jest.mock('../../../prompts');
|
||||
describe(SelectRollout, () => {
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
it('returns null if project has no rollouts', async () => {
|
||||
jest.mocked(getChannelsDatasetAsync).mockResolvedValue([]);
|
||||
const ctx = createCtxMock();
|
||||
const selectRollout = new SelectRollout();
|
||||
const rollout = await selectRollout.runAsync(ctx);
|
||||
expect(rollout).toBeNull();
|
||||
});
|
||||
it('returns the rollout without prompting if project only one rollout', async () => {
|
||||
jest.mocked(getChannelsDatasetAsync).mockResolvedValue([testBasicChannelInfo]);
|
||||
const ctx = createCtxMock();
|
||||
const selectRollout = new SelectRollout();
|
||||
const rollout = await selectRollout.runAsync(ctx);
|
||||
expect(rollout).toBe(testBasicChannelInfo);
|
||||
});
|
||||
it('returns the selected rollout', async () => {
|
||||
jest
|
||||
.mocked(getChannelsDatasetAsync)
|
||||
.mockResolvedValue([testBasicChannelInfo, testBasicChannelInfo2]);
|
||||
jest.mocked(promptAsync).mockImplementation(async () => ({
|
||||
channel: testBasicChannelInfo,
|
||||
}));
|
||||
const ctx = createCtxMock();
|
||||
const selectRollout = new SelectRollout();
|
||||
const rollout = await selectRollout.runAsync(ctx);
|
||||
expect(rollout).toBe(testBasicChannelInfo);
|
||||
});
|
||||
it('filters the channels for rollouts', async () => {
|
||||
const standardBranchMappingChannel = { ...testBasicChannelInfo };
|
||||
standardBranchMappingChannel.branchMapping = JSON.stringify(standardBranchMapping);
|
||||
const mockDataset = [standardBranchMappingChannel];
|
||||
jest.mocked(getChannelsDatasetAsync).mockImplementation((_gqlClient, args: any) => {
|
||||
const filterPredicate = args.filterPredicate as any;
|
||||
return mockDataset.filter(filterPredicate) as any;
|
||||
});
|
||||
const ctx = createCtxMock();
|
||||
const selectRollout = new SelectRollout();
|
||||
const rollout = await selectRollout.runAsync(ctx);
|
||||
expect(rollout).toBeNull();
|
||||
});
|
||||
it('throws an error in Non-Interactive Mode', async () => {
|
||||
const ctx = createCtxMock({
|
||||
nonInteractive: true,
|
||||
});
|
||||
const selectRollout = new SelectRollout();
|
||||
|
||||
// dont fail if users are running in non-interactive mode
|
||||
await expect(selectRollout.runAsync(ctx)).rejects.toThrowError(NonInteractiveError);
|
||||
});
|
||||
});
|
||||
@@ -1,265 +0,0 @@
|
||||
import assert from 'assert';
|
||||
|
||||
import {
|
||||
BranchMapping,
|
||||
BranchMappingNode,
|
||||
assertNodeObject,
|
||||
assertNumber,
|
||||
assertStatement,
|
||||
assertString,
|
||||
getBranchMapping,
|
||||
getNodesFromStatement,
|
||||
isAlwaysTrue,
|
||||
isAndStatement,
|
||||
isStatement,
|
||||
} from '../channel/branch-mapping';
|
||||
import { getUpdateBranch } from '../channel/utils';
|
||||
import { UpdateChannelBasicInfoFragment } from '../graphql/generated';
|
||||
import { UpdateBranchObject, UpdateChannelObject } from '../graphql/queries/ChannelQuery';
|
||||
|
||||
export type Rollout = LegacyRollout | ConstrainedRollout;
|
||||
export type RolloutInfo = LegacyRolloutInfo | ConstrainedRolloutInfo;
|
||||
type ConstrainedRollout = LegacyRollout & {
|
||||
runtimeVersion: string;
|
||||
};
|
||||
|
||||
type LegacyRollout = {
|
||||
rolledOutBranch: UpdateBranchObject;
|
||||
defaultBranch: UpdateBranchObject;
|
||||
} & LegacyRolloutInfo;
|
||||
|
||||
type ConstrainedRolloutInfo = LegacyRolloutInfo & {
|
||||
runtimeVersion: string;
|
||||
};
|
||||
|
||||
type LegacyRolloutInfo = {
|
||||
rolledOutBranchId: string;
|
||||
percentRolledOut: number;
|
||||
defaultBranchId: string;
|
||||
};
|
||||
|
||||
export function isLegacyRolloutInfo(rollout: RolloutInfo): rollout is LegacyRolloutInfo {
|
||||
return !isConstrainedRolloutInfo(rollout);
|
||||
}
|
||||
|
||||
export function isConstrainedRolloutInfo(rollout: RolloutInfo): rollout is ConstrainedRolloutInfo {
|
||||
return 'runtimeVersion' in rollout;
|
||||
}
|
||||
|
||||
export function isConstrainedRollout(rollout: Rollout): rollout is ConstrainedRollout {
|
||||
return isConstrainedRolloutInfo(rollout);
|
||||
}
|
||||
|
||||
export function getRolloutInfo(basicChannelInfo: UpdateChannelBasicInfoFragment): RolloutInfo {
|
||||
const branchMapping = getBranchMapping(basicChannelInfo.branchMapping);
|
||||
assertRollout(branchMapping);
|
||||
return getRolloutInfoFromBranchMapping(branchMapping);
|
||||
}
|
||||
|
||||
export function getRolloutInfoFromBranchMapping(branchMapping: BranchMapping): RolloutInfo {
|
||||
assertRollout(branchMapping);
|
||||
const rolledOutBranchId = branchMapping.data[0].branchId;
|
||||
const defaultBranchId = branchMapping.data[1].branchId;
|
||||
|
||||
if (isRtvConstrainedRollout(branchMapping)) {
|
||||
const statementNode = branchMapping.data[0].branchMappingLogic;
|
||||
assertStatement(statementNode);
|
||||
const nodesFromStatement = getNodesFromStatement(statementNode);
|
||||
|
||||
const runtimeVersionNode = nodesFromStatement.find(isRuntimeVersionNode);
|
||||
assert(runtimeVersionNode, 'Runtime version node must be defined.');
|
||||
assertNodeObject(runtimeVersionNode);
|
||||
const runtimeVersion = runtimeVersionNode.operand;
|
||||
assertString(runtimeVersion);
|
||||
|
||||
const rolloutNode = nodesFromStatement.find(isRolloutNode);
|
||||
assert(rolloutNode, 'Rollout node must be defined.');
|
||||
assertNodeObject(rolloutNode);
|
||||
const operand = rolloutNode.operand;
|
||||
assertNumber(operand);
|
||||
return {
|
||||
rolledOutBranchId,
|
||||
percentRolledOut: operand * 100,
|
||||
runtimeVersion,
|
||||
defaultBranchId,
|
||||
};
|
||||
} else {
|
||||
const rolloutNode = branchMapping.data[0].branchMappingLogic;
|
||||
assertNodeObject(rolloutNode);
|
||||
const operand = rolloutNode.operand;
|
||||
assertNumber(operand);
|
||||
return {
|
||||
rolledOutBranchId,
|
||||
percentRolledOut: operand * 100,
|
||||
defaultBranchId,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function getRollout(channel: UpdateChannelObject): Rollout {
|
||||
const branchMapping = getBranchMapping(channel.branchMapping);
|
||||
assertRollout(branchMapping);
|
||||
const rolledOutBranchId = branchMapping.data[0].branchId;
|
||||
const rolledOutBranch = getUpdateBranch(channel, rolledOutBranchId);
|
||||
const defaultBranchId = branchMapping.data[1].branchId;
|
||||
const defaultBranch = getUpdateBranch(channel, defaultBranchId);
|
||||
|
||||
const rolloutInfo = getRolloutInfo(channel);
|
||||
return {
|
||||
...rolloutInfo,
|
||||
rolledOutBranch,
|
||||
defaultBranch,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect if a branch mapping is a rollout.
|
||||
*
|
||||
* Types of rollout:
|
||||
* 1. Legacy unconstrained rollout:
|
||||
* Maps to a rollout branch via a rollout token
|
||||
* Falls back to a default branch
|
||||
*
|
||||
* Example:
|
||||
* {
|
||||
version: 0,
|
||||
data: [
|
||||
{
|
||||
branchId: uuidv4(),
|
||||
branchMappingLogic: {
|
||||
operand: 10 / 100,
|
||||
clientKey: 'rolloutToken',
|
||||
branchMappingOperator: hashLtOperator(),
|
||||
},
|
||||
},
|
||||
{ branchId: uuidv4(), branchMappingLogic: alwaysTrue() },
|
||||
],
|
||||
}
|
||||
*
|
||||
* 2. RTV constrained rollout:
|
||||
* Maps to a rollout branch via a rollout token, constrained by runtime version
|
||||
* Falls back to a default branch
|
||||
*
|
||||
* Example:
|
||||
* {
|
||||
version: 0,
|
||||
data: [
|
||||
{
|
||||
branchId: uuidv4(),
|
||||
branchMappingLogic: andStatement([
|
||||
{
|
||||
operand: '1.0.0',
|
||||
clientKey: 'runtimeVersion',
|
||||
branchMappingOperator: equalsOperator(),
|
||||
},
|
||||
{
|
||||
operand: 10 / 100,
|
||||
clientKey: 'rolloutToken',
|
||||
branchMappingOperator: hashLtOperator(),
|
||||
},
|
||||
]),
|
||||
},
|
||||
{ branchId: uuidv4(), branchMappingLogic: alwaysTrue() },
|
||||
],
|
||||
}
|
||||
*/
|
||||
export function isRollout(branchMapping: BranchMapping): boolean {
|
||||
return isUnconstrainedRollout(branchMapping) || isRtvConstrainedRollout(branchMapping);
|
||||
}
|
||||
|
||||
export function editRolloutBranchMapping(
|
||||
branchMapping: BranchMapping,
|
||||
percent: number
|
||||
): BranchMapping {
|
||||
assert(
|
||||
Number.isInteger(percent) && percent >= 0 && percent <= 100,
|
||||
'The rollout percentage must be an integer between 0 and 100 inclusive.'
|
||||
);
|
||||
assertRollout(branchMapping);
|
||||
if (isRtvConstrainedRollout(branchMapping)) {
|
||||
return editRtvConstrainedRollout(branchMapping, percent);
|
||||
} else {
|
||||
return editLegacyRollout(branchMapping, percent);
|
||||
}
|
||||
}
|
||||
|
||||
function editRtvConstrainedRollout(branchMapping: BranchMapping, percent: number): BranchMapping {
|
||||
const newBranchMapping = { ...branchMapping };
|
||||
const statementNode = newBranchMapping.data[0].branchMappingLogic;
|
||||
assertStatement(statementNode);
|
||||
const nodesFromStatement = getNodesFromStatement(statementNode);
|
||||
|
||||
const rolloutNode = nodesFromStatement.find(isRolloutNode);
|
||||
assert(rolloutNode, 'Rollout node must be defined.');
|
||||
assertNodeObject(rolloutNode);
|
||||
rolloutNode.operand = percent / 100;
|
||||
return newBranchMapping;
|
||||
}
|
||||
|
||||
function editLegacyRollout(branchMapping: BranchMapping, percent: number): BranchMapping {
|
||||
const newBranchMapping = { ...branchMapping };
|
||||
const rolloutNode = newBranchMapping.data[0].branchMappingLogic;
|
||||
assertNodeObject(rolloutNode);
|
||||
rolloutNode.operand = percent / 100;
|
||||
return newBranchMapping;
|
||||
}
|
||||
|
||||
function assertRollout(branchMapping: BranchMapping): asserts branchMapping is BranchMapping {
|
||||
assert(
|
||||
isRollout(branchMapping),
|
||||
'Branch mapping node must be a rollout. Received: ' + JSON.stringify(branchMapping)
|
||||
);
|
||||
}
|
||||
|
||||
function isRtvConstrainedRollout(branchMapping: BranchMapping): boolean {
|
||||
if (branchMapping.data.length !== 2) {
|
||||
return false;
|
||||
}
|
||||
const hasRtvRolloutNode = isRtvConstrainedRolloutNode(branchMapping.data[0].branchMappingLogic);
|
||||
const defaultsToAlwaysTrueNode = isAlwaysTrue(branchMapping.data[1].branchMappingLogic);
|
||||
|
||||
return hasRtvRolloutNode && defaultsToAlwaysTrueNode;
|
||||
}
|
||||
|
||||
function isRtvConstrainedRolloutNode(node: BranchMappingNode): boolean {
|
||||
if (!isStatement(node) || !isAndStatement(node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const statementNodes = getNodesFromStatement(node);
|
||||
if (statementNodes.length !== 2) {
|
||||
return false;
|
||||
}
|
||||
const hasRuntimeVersionNode = statementNodes.some(isRuntimeVersionNode);
|
||||
const hasRolloutNode = statementNodes.some(isRolloutNode);
|
||||
return hasRuntimeVersionNode && hasRolloutNode;
|
||||
}
|
||||
|
||||
function isUnconstrainedRollout(branchMapping: BranchMapping): boolean {
|
||||
if (branchMapping.data.length !== 2) {
|
||||
return false;
|
||||
}
|
||||
const hasRolloutNode = isRolloutNode(branchMapping.data[0].branchMappingLogic);
|
||||
const defaultsToAlwaysTrueNode = isAlwaysTrue(branchMapping.data[1].branchMappingLogic);
|
||||
return hasRolloutNode && defaultsToAlwaysTrueNode;
|
||||
}
|
||||
|
||||
function isRuntimeVersionNode(node: BranchMappingNode): boolean {
|
||||
if (typeof node === 'string') {
|
||||
return false;
|
||||
}
|
||||
if (Array.isArray(node)) {
|
||||
return false;
|
||||
}
|
||||
return node.clientKey === 'runtimeVersion' && node.branchMappingOperator === '==';
|
||||
}
|
||||
|
||||
function isRolloutNode(node: BranchMappingNode): boolean {
|
||||
if (typeof node === 'string') {
|
||||
return false;
|
||||
}
|
||||
if (Array.isArray(node)) {
|
||||
return false;
|
||||
}
|
||||
return node.clientKey === 'rolloutToken' && node.branchMappingOperator === 'hash_lt';
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
import chalk from 'chalk';
|
||||
|
||||
import { UpdateChannelObject } from '../graphql/queries/ChannelQuery';
|
||||
import Log from '../log';
|
||||
import formatFields from '../utils/formatFields';
|
||||
import { getRollout, isConstrainedRollout } from './branch-mapping';
|
||||
|
||||
export function printRollout(channel: UpdateChannelObject): void {
|
||||
const rollout = getRollout(channel);
|
||||
const rolledOutPercent = rollout.percentRolledOut;
|
||||
Log.addNewLineIfNone();
|
||||
Log.log(chalk.bold('Rollout:'));
|
||||
Log.log(
|
||||
formatFields([
|
||||
{ label: 'Channel', value: channel.name },
|
||||
...(isConstrainedRollout(rollout)
|
||||
? [{ label: 'Runtime Version', value: rollout.runtimeVersion }]
|
||||
: []),
|
||||
{
|
||||
label: 'Branches',
|
||||
value: `${rollout.rolledOutBranch.name} (${rolledOutPercent}%), ${
|
||||
rollout.defaultBranch.name
|
||||
} (${100 - rolledOutPercent}%)`,
|
||||
},
|
||||
])
|
||||
);
|
||||
Log.addNewLineIfNone();
|
||||
}
|
||||
|
||||
export function printBranch(channel: UpdateChannelObject): void {
|
||||
const rollout = getRollout(channel);
|
||||
const rolledOutPercent = rollout.percentRolledOut;
|
||||
Log.addNewLineIfNone();
|
||||
Log.log(chalk.bold('Rollout:'));
|
||||
Log.log(
|
||||
formatFields([
|
||||
{ label: 'Channel', value: channel.name },
|
||||
...(isConstrainedRollout(rollout)
|
||||
? [{ label: 'Runtime Version', value: rollout.runtimeVersion }]
|
||||
: []),
|
||||
{
|
||||
label: 'Branches',
|
||||
value: `${rollout.rolledOutBranch.name} (${rolledOutPercent}%), ${
|
||||
rollout.defaultBranch.name
|
||||
} (${100 - rolledOutPercent}%)`,
|
||||
},
|
||||
])
|
||||
);
|
||||
Log.addNewLineIfNone();
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
AmbiguousApplicationIdError,
|
||||
getApplicationIdAsync,
|
||||
} from '../../project/android/applicationId';
|
||||
import capitalizeFirstLetter from '../../utils/expodash/capitalize';
|
||||
import capitalize from '../../utils/expodash/capitalize';
|
||||
import { ArchiveSource } from '../ArchiveSource';
|
||||
import { resolveArchiveSource } from '../commons';
|
||||
import { SubmissionContext } from '../context';
|
||||
@@ -33,12 +33,9 @@ export default class AndroidSubmitCommand {
|
||||
const track = this.resolveTrack();
|
||||
const releaseStatus = this.resolveReleaseStatus();
|
||||
const archiveSource = this.resolveArchiveSource();
|
||||
const rollout = this.resolveRollout();
|
||||
const serviceAccountSource = await this.resolveServiceAccountSourceAsync();
|
||||
|
||||
const errored = [track, releaseStatus, archiveSource, serviceAccountSource, rollout].filter(
|
||||
r => !r.ok
|
||||
);
|
||||
const errored = [track, releaseStatus, archiveSource, serviceAccountSource].filter(r => !r.ok);
|
||||
if (errored.length > 0) {
|
||||
const message = errored.map(err => err.reason?.message).join('\n');
|
||||
Log.error(message);
|
||||
@@ -49,7 +46,6 @@ export default class AndroidSubmitCommand {
|
||||
projectId: this.ctx.projectId,
|
||||
track: track.enforceValue(),
|
||||
releaseStatus: releaseStatus.enforceValue(),
|
||||
rollout: rollout.enforceValue(),
|
||||
archiveSource: archiveSource.enforceValue(),
|
||||
serviceAccountSource: serviceAccountSource.enforceValue(),
|
||||
changesNotSentForReview: this.ctx.profile.changesNotSentForReview,
|
||||
@@ -77,7 +73,7 @@ export default class AndroidSubmitCommand {
|
||||
if (!track) {
|
||||
return result(SubmissionAndroidTrack.Internal);
|
||||
}
|
||||
const capitalizedTrack = capitalizeFirstLetter(track);
|
||||
const capitalizedTrack = capitalize(track);
|
||||
if (capitalizedTrack in SubmissionAndroidTrack) {
|
||||
return result(
|
||||
SubmissionAndroidTrack[capitalizedTrack as keyof typeof SubmissionAndroidTrack]
|
||||
@@ -98,7 +94,7 @@ export default class AndroidSubmitCommand {
|
||||
if (!releaseStatus) {
|
||||
return result(SubmissionAndroidReleaseStatus.Completed);
|
||||
}
|
||||
const capitalizedReleaseStatus = capitalizeFirstLetter(releaseStatus);
|
||||
const capitalizedReleaseStatus = capitalize(releaseStatus);
|
||||
if (capitalizedReleaseStatus in SubmissionAndroidReleaseStatus) {
|
||||
return result(
|
||||
SubmissionAndroidReleaseStatus[
|
||||
@@ -116,12 +112,6 @@ export default class AndroidSubmitCommand {
|
||||
}
|
||||
}
|
||||
|
||||
private resolveRollout(): Result<number | undefined> {
|
||||
const { rollout } = this.ctx.profile;
|
||||
|
||||
return result(rollout);
|
||||
}
|
||||
|
||||
private resolveArchiveSource(): Result<ArchiveSource> {
|
||||
try {
|
||||
return result(resolveArchiveSource(this.ctx));
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
export interface AndroidSubmissionOptions
|
||||
extends Pick<
|
||||
AndroidSubmissionConfigInput,
|
||||
'track' | 'releaseStatus' | 'changesNotSentForReview' | 'rollout'
|
||||
'track' | 'releaseStatus' | 'changesNotSentForReview'
|
||||
> {
|
||||
projectId: string;
|
||||
archiveSource: ArchiveSource;
|
||||
@@ -111,12 +111,11 @@ export default class AndroidSubmitter extends BaseSubmitter<
|
||||
options: AndroidSubmissionOptions,
|
||||
{ serviceAccountKeyResult }: ResolvedSourceOptions
|
||||
): AndroidSubmissionConfigInput {
|
||||
const { track, releaseStatus, changesNotSentForReview, rollout } = options;
|
||||
const { track, releaseStatus, changesNotSentForReview } = options;
|
||||
return {
|
||||
track,
|
||||
changesNotSentForReview,
|
||||
releaseStatus,
|
||||
rollout,
|
||||
...serviceAccountKeyResult.result,
|
||||
};
|
||||
}
|
||||
@@ -125,7 +124,7 @@ export default class AndroidSubmitter extends BaseSubmitter<
|
||||
options: AndroidSubmissionOptions,
|
||||
{ archive, serviceAccountKeyResult }: ResolvedSourceOptions
|
||||
): SummaryData {
|
||||
const { projectId, track, releaseStatus, changesNotSentForReview, rollout } = options;
|
||||
const { projectId, track, releaseStatus, changesNotSentForReview } = options;
|
||||
|
||||
// structuring order affects table rows order
|
||||
return {
|
||||
@@ -134,7 +133,6 @@ export default class AndroidSubmitter extends BaseSubmitter<
|
||||
changesNotSentForReview: changesNotSentForReview ?? undefined,
|
||||
releaseStatus: releaseStatus ?? undefined,
|
||||
formattedServiceAccount: formatServiceAccountSummary(serviceAccountKeyResult),
|
||||
rollout: rollout ?? undefined,
|
||||
...formatArchiveSourceSummary(archive),
|
||||
};
|
||||
}
|
||||
@@ -145,7 +143,6 @@ type SummaryData = {
|
||||
formattedServiceAccount: string;
|
||||
projectId: string;
|
||||
releaseStatus?: SubmissionAndroidReleaseStatus;
|
||||
rollout?: number;
|
||||
track: SubmissionAndroidTrack;
|
||||
} & ArchiveSourceSummaryFields;
|
||||
|
||||
@@ -157,7 +154,6 @@ const SummaryHumanReadableKeys: Record<keyof SummaryData, string> = {
|
||||
formattedServiceAccount: 'Google Service Account Key',
|
||||
projectId: 'Project ID',
|
||||
releaseStatus: 'Release status',
|
||||
rollout: 'Rollout',
|
||||
track: 'Release track',
|
||||
};
|
||||
|
||||
|
||||
@@ -145,46 +145,6 @@ describe(AndroidSubmitCommand, () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('sends a request to EAS Submit when using inProgress status', async () => {
|
||||
const projectId = uuidv4();
|
||||
const graphqlClient = {} as any as ExpoGraphqlClient;
|
||||
const analytics = instance(mock<Analytics>());
|
||||
|
||||
const ctx = await createSubmissionContextAsync({
|
||||
platform: Platform.ANDROID,
|
||||
projectDir: testProject.projectRoot,
|
||||
archiveFlags: {
|
||||
url: 'http://expo.dev/fake.apk',
|
||||
},
|
||||
profile: {
|
||||
serviceAccountKeyPath: '/google-service-account.json',
|
||||
track: AndroidReleaseTrack.internal,
|
||||
releaseStatus: AndroidReleaseStatus.inProgress,
|
||||
changesNotSentForReview: false,
|
||||
},
|
||||
nonInteractive: false,
|
||||
actor: mockJester,
|
||||
graphqlClient,
|
||||
analytics,
|
||||
exp: testProject.appJSON.expo,
|
||||
projectId,
|
||||
});
|
||||
|
||||
const command = new AndroidSubmitCommand(ctx);
|
||||
await command.runAsync();
|
||||
|
||||
expect(SubmissionMutation.createAndroidSubmissionAsync).toHaveBeenCalledWith(graphqlClient, {
|
||||
appId: projectId,
|
||||
archiveSource: { type: SubmissionArchiveSourceType.Url, url: 'http://expo.dev/fake.apk' },
|
||||
config: {
|
||||
googleServiceAccountKeyJson: fakeFiles['/google-service-account.json'],
|
||||
releaseStatus: SubmissionAndroidReleaseStatus.InProgress,
|
||||
track: SubmissionAndroidTrack.Internal,
|
||||
changesNotSentForReview: false,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('assigns the build ID to submission', async () => {
|
||||
const projectId = uuidv4();
|
||||
const graphqlClient = {} as any as ExpoGraphqlClient;
|
||||
|
||||
@@ -9,14 +9,14 @@ import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGr
|
||||
import { AppPlatform } from '../graphql/generated';
|
||||
import Log, { learnMore } from '../log';
|
||||
import { RequestedPlatform, appPlatformDisplayNames } from '../platform';
|
||||
import { createOrModifyExpoConfigAsync, isUsingStaticExpoConfig } from '../project/expoConfig';
|
||||
import { createOrModifyExpoConfigAsync } from '../project/expoConfig';
|
||||
import {
|
||||
installExpoUpdatesAsync,
|
||||
isDefinitelyUsingClassicUpdates,
|
||||
isExpoUpdatesInstalledAsDevDependency,
|
||||
isExpoUpdatesInstalledOrAvailable,
|
||||
} from '../project/projectUtils';
|
||||
import { resolveWorkflowPerPlatformAsync } from '../project/workflow';
|
||||
import { confirmAsync } from '../prompts';
|
||||
import { syncUpdatesConfigurationAsync as syncAndroidUpdatesConfigurationAsync } from './android/UpdatesModule';
|
||||
import { syncUpdatesConfigurationAsync as syncIosUpdatesConfigurationAsync } from './ios/UpdatesModule';
|
||||
|
||||
@@ -97,6 +97,10 @@ 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) };
|
||||
}
|
||||
@@ -155,16 +159,6 @@ async function ensureEASUpdatesIsConfiguredInExpoConfigAsync({
|
||||
}
|
||||
}
|
||||
|
||||
function serializeRuntimeVersionToString(
|
||||
runtimeVersion: NonNullable<ExpoConfig['runtimeVersion']>
|
||||
): string {
|
||||
if (typeof runtimeVersion === 'object') {
|
||||
return JSON.stringify(runtimeVersion);
|
||||
} else {
|
||||
return runtimeVersion;
|
||||
}
|
||||
}
|
||||
|
||||
function logEasUpdatesAutoConfig({
|
||||
modifyConfig,
|
||||
exp,
|
||||
@@ -172,6 +166,12 @@ 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
|
||||
@@ -186,21 +186,21 @@ function logEasUpdatesAutoConfig({
|
||||
Log.withTick(
|
||||
`Configured runtimeVersion for ${appPlatformDisplayNames[AppPlatform.Android]} and ${
|
||||
appPlatformDisplayNames[AppPlatform.Ios]
|
||||
} with "${serializeRuntimeVersionToString(androidRuntime)}"`
|
||||
} with "${modifyConfig.android?.runtimeVersion ?? modifyConfig.runtimeVersion}"`
|
||||
);
|
||||
} else {
|
||||
if (androidRuntime) {
|
||||
Log.withTick(
|
||||
`Configured runtimeVersion for ${
|
||||
appPlatformDisplayNames[AppPlatform.Android]
|
||||
} with "${serializeRuntimeVersionToString(androidRuntime)}"`
|
||||
`Configured runtimeVersion for ${appPlatformDisplayNames[AppPlatform.Android]} with "${
|
||||
modifyConfig.android?.runtimeVersion ?? modifyConfig.runtimeVersion
|
||||
}"`
|
||||
);
|
||||
}
|
||||
if (iosRuntime) {
|
||||
Log.withTick(
|
||||
`Configured runtimeVersion for ${
|
||||
appPlatformDisplayNames[AppPlatform.Ios]
|
||||
} with "${serializeRuntimeVersionToString(iosRuntime)}"`
|
||||
`Configured runtimeVersion for ${appPlatformDisplayNames[AppPlatform.Ios]} with "${
|
||||
modifyConfig.ios?.runtimeVersion ?? modifyConfig.runtimeVersion
|
||||
}"`
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -335,9 +335,9 @@ export async function ensureEASUpdateIsConfiguredInEasJsonAsync(projectDir: stri
|
||||
/**
|
||||
* Make sure EAS Update is fully configured in the current project.
|
||||
* This goes over a checklist and performs the following checks or changes:
|
||||
* - Ensure `updates.useClassicUpdates` (SDK 49) is not set in the app config
|
||||
* - Ensure the `expo-updates` package is currently installed.
|
||||
* - 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
|
||||
@@ -345,7 +345,7 @@ export async function ensureEASUpdateIsConfiguredInEasJsonAsync(projectDir: stri
|
||||
export async function ensureEASUpdateIsConfiguredAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
{
|
||||
exp: expMaybeWithoutUpdates,
|
||||
exp: expWithoutUpdates,
|
||||
projectId,
|
||||
projectDir,
|
||||
platform,
|
||||
@@ -356,17 +356,9 @@ export async function ensureEASUpdateIsConfiguredAsync(
|
||||
platform: RequestedPlatform | null;
|
||||
}
|
||||
): Promise<void> {
|
||||
// EAS Update and SDK 49's "useClassicUpdates" option are mutually exclusive
|
||||
if (expMaybeWithoutUpdates.updates?.useClassicUpdates) {
|
||||
expMaybeWithoutUpdates = await ensureUseClassicUpdatesIsRemovedAsync({
|
||||
exp: expMaybeWithoutUpdates,
|
||||
projectDir,
|
||||
});
|
||||
}
|
||||
|
||||
const hasExpoUpdates = isExpoUpdatesInstalledOrAvailable(
|
||||
projectDir,
|
||||
expMaybeWithoutUpdates.sdkVersion
|
||||
expWithoutUpdates.sdkVersion
|
||||
);
|
||||
const hasExpoUpdatesInDevDependencies = isExpoUpdatesInstalledAsDevDependency(projectDir);
|
||||
if (!hasExpoUpdates && !hasExpoUpdatesInDevDependencies) {
|
||||
@@ -387,7 +379,7 @@ export async function ensureEASUpdateIsConfiguredAsync(
|
||||
const workflows = await resolveWorkflowPerPlatformAsync(projectDir);
|
||||
const { projectChanged, exp: expWithUpdates } =
|
||||
await ensureEASUpdatesIsConfiguredInExpoConfigAsync({
|
||||
exp: expMaybeWithoutUpdates,
|
||||
exp: expWithoutUpdates,
|
||||
projectDir,
|
||||
projectId,
|
||||
platform,
|
||||
@@ -412,49 +404,3 @@ export async function ensureEASUpdateIsConfiguredAsync(
|
||||
Log.newLine();
|
||||
}
|
||||
}
|
||||
|
||||
export async function ensureUseClassicUpdatesIsRemovedAsync({
|
||||
exp: expMaybeWithoutUpdates,
|
||||
projectDir,
|
||||
}: {
|
||||
exp: ExpoConfig;
|
||||
projectDir: string;
|
||||
}): Promise<ExpoConfig> {
|
||||
if (!isUsingStaticExpoConfig(projectDir)) {
|
||||
throw new Error(
|
||||
`Your app config sets "updates.useClassicUpdates" but EAS Update does not support classic updates. Remove "useClassicUpdates" from your app config and run this command again.`
|
||||
);
|
||||
}
|
||||
|
||||
const shouldEditConfig = await confirmAsync({
|
||||
message: `Your app config sets "updates.useClassicUpdates" but EAS Update does not support classic updates. Remove "updates.useClassicUpdates" from your app config?`,
|
||||
});
|
||||
if (!shouldEditConfig) {
|
||||
throw new Error(
|
||||
`Manually remove "updates.useClassicUpdates" from your app config and run this command again.`
|
||||
);
|
||||
}
|
||||
|
||||
const editedExpoConfig = mergeExpoConfig(expMaybeWithoutUpdates, {
|
||||
updates: { useClassicUpdates: undefined },
|
||||
}) as ExpoConfig;
|
||||
const result = await createOrModifyExpoConfigAsync(projectDir, editedExpoConfig);
|
||||
|
||||
switch (result.type) {
|
||||
case 'success':
|
||||
Log.withTick(`Removed "updates.useClassicUpdates"`);
|
||||
expMaybeWithoutUpdates = editedExpoConfig;
|
||||
break;
|
||||
|
||||
case 'warn':
|
||||
case 'fail':
|
||||
throw new Error(result.message);
|
||||
|
||||
default:
|
||||
throw new Error(
|
||||
`Unexpected result type "${result.type}" received when modifying the project config.`
|
||||
);
|
||||
}
|
||||
|
||||
return editedExpoConfig;
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
import assert from 'assert';
|
||||
import openBrowserAsync from 'better-opn';
|
||||
import http from 'http';
|
||||
import { Socket } from 'node:net';
|
||||
@@ -6,48 +5,22 @@ import querystring from 'querystring';
|
||||
|
||||
import Log from '../log';
|
||||
|
||||
const successBody = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Expo SSO Login</title>
|
||||
<meta charset="utf-8">
|
||||
<style type="text/css">
|
||||
html {
|
||||
margin: 0;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #fff;
|
||||
font-family: Tahoma,Verdana;
|
||||
font-size: 16px;
|
||||
color: #000;
|
||||
max-width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: .5rem;
|
||||
margin: 1em;
|
||||
overflow-wrap: break-word
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
SSO login complete. You may now close this tab and return to the command prompt.
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
export async function getSessionUsingBrowserAuthFlowAsync({
|
||||
expoWebsiteUrl,
|
||||
}: {
|
||||
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 = (port: number): string => {
|
||||
const buildExpoSsoLoginUrl = (): string => {
|
||||
const data = {
|
||||
app_redirect_uri: `${scheme}://${hostname}:${port}${path}`,
|
||||
app_redirect_uri: redirectUri,
|
||||
};
|
||||
const params = querystring.stringify(data);
|
||||
return `${expoWebsiteUrl}/sso-login?${params}`;
|
||||
@@ -71,8 +44,8 @@ export async function getSessionUsingBrowserAuthFlowAsync({
|
||||
throw new Error('Request missing session_secret search parameter.');
|
||||
}
|
||||
resolve(sessionSecret);
|
||||
response.writeHead(200, { 'Content-Type': 'text/html' });
|
||||
response.write(successBody);
|
||||
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);
|
||||
@@ -86,17 +59,8 @@ export async function getSessionUsingBrowserAuthFlowAsync({
|
||||
}
|
||||
);
|
||||
|
||||
server.listen(0, hostname, () => {
|
||||
server.listen(serverPort, hostname, () => {
|
||||
Log.log('Waiting for browser login...');
|
||||
|
||||
const address = server.address();
|
||||
assert(
|
||||
address !== null && typeof address === 'object',
|
||||
'Server address and port should be set after listening has begun'
|
||||
);
|
||||
const port = address.port;
|
||||
const authorizeUrl = buildExpoSsoLoginUrl(port);
|
||||
openBrowserAsync(authorizeUrl);
|
||||
});
|
||||
|
||||
server.on('connection', connection => {
|
||||
@@ -106,6 +70,9 @@ export async function getSessionUsingBrowserAuthFlowAsync({
|
||||
connections.delete(connection);
|
||||
});
|
||||
});
|
||||
|
||||
const authorizeUrl = buildExpoSsoLoginUrl();
|
||||
openBrowserAsync(authorizeUrl);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getExpoWebsiteBaseUrl } from '../api';
|
||||
import { getExpoWebsiteBaseUrl, getSsoLocalServerPortAsync } from '../api';
|
||||
import { getSessionUsingBrowserAuthFlowAsync } from './expoSsoLauncher';
|
||||
import { fetchUserAsync } from './fetchUser';
|
||||
|
||||
@@ -7,9 +7,11 @@ export async function fetchSessionSecretAndSsoUserAsync(): Promise<{
|
||||
id: string;
|
||||
username: string;
|
||||
}> {
|
||||
const sessionSecret = await getSessionUsingBrowserAuthFlowAsync({
|
||||
const config = {
|
||||
expoWebsiteUrl: getExpoWebsiteBaseUrl(),
|
||||
});
|
||||
serverPort: await getSsoLocalServerPortAsync(),
|
||||
};
|
||||
const sessionSecret = await getSessionUsingBrowserAuthFlowAsync(config);
|
||||
|
||||
const userData = await fetchUserAsync({ sessionSecret });
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import { Platform } from '@expo/eas-build-job';
|
||||
import { BuildProfile, EasJsonAccessor, EasJsonUtils, errors } from '@expo/eas-json';
|
||||
import fs from 'fs-extra';
|
||||
import { vol } from 'memfs';
|
||||
import os from 'os';
|
||||
|
||||
import Log from '../../log';
|
||||
import { selectAsync } from '../../prompts';
|
||||
@@ -12,7 +9,6 @@ import {
|
||||
maybePrintBuildProfileDeprecationWarningsAsync,
|
||||
} from '../profiles';
|
||||
|
||||
jest.mock('fs');
|
||||
jest.mock('../../prompts');
|
||||
jest.mock('@expo/eas-json', () => {
|
||||
const actual = jest.requireActual('@expo/eas-json');
|
||||
@@ -36,7 +32,6 @@ const getBuildProfileDeprecationWarningsAsync = jest.spyOn(
|
||||
);
|
||||
const newLineSpy = jest.spyOn(Log, 'newLine');
|
||||
const warnSpy = jest.spyOn(Log, 'warn');
|
||||
const projectDir = '/app';
|
||||
|
||||
describe(getProfilesAsync, () => {
|
||||
afterEach(() => {
|
||||
@@ -56,7 +51,6 @@ describe(getProfilesAsync, () => {
|
||||
platforms: [Platform.ANDROID, Platform.IOS],
|
||||
profileName: undefined,
|
||||
type: 'build',
|
||||
projectDir,
|
||||
});
|
||||
|
||||
expect(result[0].profileName).toBe('production');
|
||||
@@ -77,7 +71,6 @@ describe(getProfilesAsync, () => {
|
||||
platforms: [Platform.ANDROID],
|
||||
profileName: undefined,
|
||||
type: 'build',
|
||||
projectDir,
|
||||
})
|
||||
).rejects.toThrowError(errors.MissingProfileError);
|
||||
});
|
||||
@@ -93,7 +86,6 @@ describe(getProfilesAsync, () => {
|
||||
platforms: [Platform.ANDROID, Platform.IOS],
|
||||
profileName: 'custom-profile',
|
||||
type: 'build',
|
||||
projectDir,
|
||||
});
|
||||
|
||||
expect(result[0].profileName).toBe('custom-profile');
|
||||
@@ -106,52 +98,6 @@ describe(getProfilesAsync, () => {
|
||||
expect(getBuildProfileAsync).toBeCalledWith(easJsonAccessor, Platform.IOS, 'custom-profile');
|
||||
});
|
||||
|
||||
describe('node version', () => {
|
||||
const nodeVersion = '14.17.1';
|
||||
|
||||
it('is read from profile', async () => {
|
||||
const easJsonAccessor = EasJsonAccessor.fromProjectPath(projectDir);
|
||||
getBuildProfileAsync.mockImplementation(async () => {
|
||||
return { node: nodeVersion } as BuildProfile<Platform.ANDROID>;
|
||||
});
|
||||
const result = await getProfilesAsync({
|
||||
easJsonAccessor,
|
||||
platforms: [Platform.ANDROID],
|
||||
profileName: 'custom-profile',
|
||||
type: 'build',
|
||||
projectDir,
|
||||
});
|
||||
|
||||
expect(result[0].profile.node).toBe(nodeVersion);
|
||||
});
|
||||
|
||||
describe('with .nvmrc', () => {
|
||||
beforeEach(async () => {
|
||||
vol.reset();
|
||||
await fs.mkdirp(os.tmpdir());
|
||||
|
||||
vol.fromJSON({ '.nvmrc': nodeVersion }, projectDir);
|
||||
});
|
||||
|
||||
it('is read from .nvmrc', async () => {
|
||||
const easJsonAccessor = EasJsonAccessor.fromProjectPath(projectDir);
|
||||
getBuildProfileAsync.mockImplementation(async () => {
|
||||
return {} as BuildProfile<Platform.ANDROID>;
|
||||
});
|
||||
|
||||
const result = await getProfilesAsync({
|
||||
easJsonAccessor,
|
||||
platforms: [Platform.ANDROID],
|
||||
profileName: 'custom-profile',
|
||||
type: 'build',
|
||||
projectDir,
|
||||
});
|
||||
|
||||
expect(result[0].profile.node).toBe(nodeVersion);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('throws validation error if eas.json is invalid', async () => {
|
||||
getBuildProfileAsync.mockImplementation(() => {
|
||||
throw new errors.InvalidEasJsonError('eas.json is not valid');
|
||||
@@ -163,7 +109,6 @@ describe(getProfilesAsync, () => {
|
||||
platforms: [Platform.ANDROID, Platform.IOS],
|
||||
profileName: undefined,
|
||||
type: 'build',
|
||||
projectDir,
|
||||
})
|
||||
).rejects.toThrowError(/eas.json is not valid/);
|
||||
});
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
import { getPaginatedDatasetAsync } from '../relay';
|
||||
|
||||
describe('getPaginatedDatasetAsync', () => {
|
||||
const mockQueryAsync = jest.fn(({ first, after }) =>
|
||||
Promise.resolve({
|
||||
edges: Array(first).fill({ node: 'node', cursor: 'cursor' }),
|
||||
pageInfo: {
|
||||
hasNextPage: after !== 'next',
|
||||
endCursor: after ? null : 'next',
|
||||
hasPreviousPage: false,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should query data page by page until no more data', async () => {
|
||||
const dataset = await getPaginatedDatasetAsync({
|
||||
queryAsync: mockQueryAsync,
|
||||
batchSize: 1,
|
||||
});
|
||||
|
||||
expect(mockQueryAsync).toHaveBeenCalledTimes(2);
|
||||
expect(mockQueryAsync).toHaveBeenCalledWith({ first: 1, after: undefined });
|
||||
expect(mockQueryAsync).toHaveBeenCalledWith({ first: 1, after: 'next' });
|
||||
expect(dataset).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('should call beforeEachQuery and afterEachQuery with correct parameters', async () => {
|
||||
// dataset is pass by reference, so we make a copy at each call
|
||||
const datasetAtNthCall_beforeEachQuery = [] as any;
|
||||
const mockBeforeEachQuery = jest.fn((totalNodesFetched, dataset) => {
|
||||
datasetAtNthCall_beforeEachQuery.push([...dataset]);
|
||||
});
|
||||
|
||||
// dataset is pass by reference, so we make a copy at each call
|
||||
const datasetAtNthCall_afterEachQuery = [] as any;
|
||||
const mockAfterEachQuery = jest.fn((totalNodesFetched, dataset, batch, pageInfo) => {
|
||||
datasetAtNthCall_afterEachQuery.push([...dataset]);
|
||||
});
|
||||
|
||||
await getPaginatedDatasetAsync({
|
||||
queryAsync: mockQueryAsync,
|
||||
beforeEachQuery: mockBeforeEachQuery,
|
||||
afterEachQuery: mockAfterEachQuery,
|
||||
batchSize: 1,
|
||||
});
|
||||
|
||||
expect(mockBeforeEachQuery).toHaveBeenCalledTimes(2);
|
||||
expect(mockBeforeEachQuery).toHaveBeenNthCalledWith(1, 0, expect.any(Array));
|
||||
expect(datasetAtNthCall_beforeEachQuery[0]).toStrictEqual([]);
|
||||
expect(mockBeforeEachQuery).toHaveBeenNthCalledWith(2, 1, expect.any(Array));
|
||||
expect(datasetAtNthCall_beforeEachQuery[1]).toStrictEqual(['node']);
|
||||
|
||||
expect(mockAfterEachQuery).toHaveBeenCalledTimes(2);
|
||||
expect(mockAfterEachQuery).toHaveBeenNthCalledWith(1, 1, expect.any(Array), ['node'], {
|
||||
hasNextPage: true,
|
||||
endCursor: 'next',
|
||||
hasPreviousPage: false,
|
||||
});
|
||||
expect(datasetAtNthCall_afterEachQuery[0]).toStrictEqual(['node']);
|
||||
expect(mockAfterEachQuery).toHaveBeenNthCalledWith(2, 2, expect.any(Array), ['node'], {
|
||||
hasNextPage: false,
|
||||
endCursor: null,
|
||||
hasPreviousPage: false,
|
||||
});
|
||||
expect(datasetAtNthCall_afterEachQuery[1]).toStrictEqual(['node', 'node']);
|
||||
});
|
||||
|
||||
it('should filter nodes if filterPredicate is provided', async () => {
|
||||
const filterPredicate = (node: string): boolean => node !== 'node';
|
||||
|
||||
const dataset = await getPaginatedDatasetAsync({
|
||||
queryAsync: mockQueryAsync,
|
||||
filterPredicate,
|
||||
batchSize: 1,
|
||||
});
|
||||
|
||||
expect(dataset).toEqual([]); // expecting an empty array because our filterPredicate will filter out 'node'
|
||||
});
|
||||
|
||||
it('should stop fetching when maxNodesFetched limit is reached', async () => {
|
||||
const dataset = await getPaginatedDatasetAsync({
|
||||
queryAsync: mockQueryAsync,
|
||||
batchSize: 2,
|
||||
maxNodesFetched: 2,
|
||||
});
|
||||
|
||||
expect(dataset).toHaveLength(2);
|
||||
expect(mockQueryAsync).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
@@ -1,13 +1,10 @@
|
||||
import capitalizeFirstLetter from '../capitalize';
|
||||
import capitalize from '../capitalize';
|
||||
|
||||
describe(capitalizeFirstLetter, () => {
|
||||
describe(capitalize, () => {
|
||||
it('capitalizes the string', () => {
|
||||
expect(capitalizeFirstLetter('dominik')).toBe('Dominik');
|
||||
expect(capitalize('dominik')).toBe('Dominik');
|
||||
});
|
||||
it('works with an empty string', () => {
|
||||
expect(capitalizeFirstLetter('')).toBe('');
|
||||
});
|
||||
it('does not change the case of other letters', () => {
|
||||
expect(capitalizeFirstLetter('inProgress')).toBe('InProgress');
|
||||
expect(capitalize('')).toBe('');
|
||||
});
|
||||
});
|
||||
@@ -1,3 +1,3 @@
|
||||
export default function capitalizeFirstLetter(s: string): string {
|
||||
return s ? s.charAt(0).toUpperCase() + s.slice(1) : '';
|
||||
export default function capitalize(s: string): string {
|
||||
return s ? s.charAt(0).toUpperCase() + s.slice(1).toLowerCase() : '';
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
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;
|
||||
}
|
||||
@@ -6,9 +6,6 @@ import {
|
||||
ProfileType,
|
||||
SubmitProfile,
|
||||
} from '@expo/eas-json';
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
import semver from 'semver';
|
||||
|
||||
import Log, { learnMore } from '../log';
|
||||
|
||||
@@ -27,23 +24,19 @@ export async function getProfilesAsync<T extends ProfileType>({
|
||||
platforms,
|
||||
profileName,
|
||||
type,
|
||||
projectDir,
|
||||
}: {
|
||||
easJsonAccessor: EasJsonAccessor;
|
||||
platforms: Platform[];
|
||||
profileName?: string;
|
||||
projectDir: string;
|
||||
type: T;
|
||||
}): Promise<ProfileData<T>[]> {
|
||||
const results = platforms.map(async function (platform) {
|
||||
const profile = await readProfileWithOverridesAsync({
|
||||
const profile = await readProfileAsync({
|
||||
easJsonAccessor,
|
||||
platform,
|
||||
type,
|
||||
profileName,
|
||||
projectDir,
|
||||
});
|
||||
|
||||
return {
|
||||
profile,
|
||||
profileName: profileName ?? 'production',
|
||||
@@ -54,53 +47,16 @@ export async function getProfilesAsync<T extends ProfileType>({
|
||||
return await Promise.all(results);
|
||||
}
|
||||
|
||||
async function setNodeVersionFromFileAsync(
|
||||
projectDir: string,
|
||||
profile: BuildProfile<Platform>
|
||||
): Promise<void> {
|
||||
if (profile?.node) {
|
||||
return;
|
||||
}
|
||||
const nodeVersion = await getNodeVersionFromFileAsync(projectDir);
|
||||
if (nodeVersion) {
|
||||
Log.log(
|
||||
`The EAS build profile does not specify a Node.js version. Using the version specified in .nvmrc: ${nodeVersion} `
|
||||
);
|
||||
|
||||
profile.node = nodeVersion;
|
||||
}
|
||||
}
|
||||
|
||||
async function getNodeVersionFromFileAsync(projectDir: string): Promise<string | undefined> {
|
||||
const nvmrcPath = path.join(projectDir, '.nvmrc');
|
||||
if (!(await fs.pathExists(nvmrcPath))) {
|
||||
return;
|
||||
}
|
||||
|
||||
let nodeVersion: string;
|
||||
try {
|
||||
nodeVersion = (await fs.readFile(nvmrcPath, 'utf8')).toString().trim();
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
if (!semver.valid(nodeVersion)) {
|
||||
throw new Error(`Invalid node version in .nvmrc: ${nodeVersion}`);
|
||||
}
|
||||
return nodeVersion;
|
||||
}
|
||||
|
||||
async function readProfileWithOverridesAsync<T extends ProfileType>({
|
||||
async function readProfileAsync<T extends ProfileType>({
|
||||
easJsonAccessor,
|
||||
platform,
|
||||
type,
|
||||
profileName,
|
||||
projectDir,
|
||||
}: {
|
||||
easJsonAccessor: EasJsonAccessor;
|
||||
platform: Platform;
|
||||
type: T;
|
||||
profileName?: string;
|
||||
projectDir: string;
|
||||
}): Promise<EasProfile<T>> {
|
||||
if (type === 'build') {
|
||||
const buildProfile = await EasJsonUtils.getBuildProfileAsync(
|
||||
@@ -110,7 +66,6 @@ async function readProfileWithOverridesAsync<T extends ProfileType>({
|
||||
);
|
||||
|
||||
await maybePrintBuildProfileDeprecationWarningsAsync(easJsonAccessor, platform, profileName);
|
||||
await setNodeVersionFromFileAsync(projectDir, buildProfile);
|
||||
|
||||
return buildProfile as EasProfile<T>;
|
||||
} else {
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
import { PageInfo } from '../graphql/generated';
|
||||
|
||||
export type Connection<T> = {
|
||||
edges: Edge<T>[];
|
||||
pageInfo: PageInfo;
|
||||
};
|
||||
|
||||
type Edge<T> = {
|
||||
node: T;
|
||||
};
|
||||
|
||||
export type QueryParams = {
|
||||
first: number;
|
||||
after?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetches dataset in paginated manner (batch by batch) using GraphQL queries.
|
||||
*
|
||||
* @param queryAsync A promise based function for querying.
|
||||
* @param beforeEachQuery Optional. A callback function to be called before each query
|
||||
* @param afterEachQuery Optional. A callback function to be called after each query.
|
||||
* @param filterPredicate Optional. A predicate function to filter the node.
|
||||
* @param batchSize Optional. The batch size of the pagination. Defaults to 100.
|
||||
*
|
||||
* @return {Promise<T[]>} - A promise that resolves to an array (the dataset).
|
||||
* @throws {Error} - If an error occurs during execution of the query or pagination.
|
||||
*/
|
||||
export async function getPaginatedDatasetAsync<T>({
|
||||
queryAsync,
|
||||
beforeEachQuery,
|
||||
afterEachQuery,
|
||||
filterPredicate,
|
||||
batchSize = 100,
|
||||
maxNodesFetched = 10_000,
|
||||
}: {
|
||||
queryAsync: ({ first, after }: QueryParams) => Promise<Connection<T>>;
|
||||
beforeEachQuery?: (totalNodesFetched: number, dataset: T[]) => void;
|
||||
afterEachQuery?: (
|
||||
totalNodesFetched: number,
|
||||
dataset: T[],
|
||||
batch: T[],
|
||||
pageInfo: PageInfo
|
||||
) => void;
|
||||
filterPredicate?: (node: T) => boolean;
|
||||
batchSize?: number;
|
||||
maxNodesFetched?: number;
|
||||
}): Promise<T[]> {
|
||||
const dataset = [];
|
||||
let hasMore = true;
|
||||
let after: string | undefined;
|
||||
let totalNodesFetched = 0;
|
||||
while (hasMore) {
|
||||
if (beforeEachQuery) {
|
||||
beforeEachQuery(totalNodesFetched, dataset);
|
||||
}
|
||||
const result = await queryAsync({ first: batchSize, after });
|
||||
const { edges, pageInfo } = result;
|
||||
const nodes = edges.map(edge => edge.node);
|
||||
const batch = filterPredicate ? nodes.filter(filterPredicate) : nodes;
|
||||
dataset.push(...batch);
|
||||
hasMore = pageInfo.hasNextPage;
|
||||
after = pageInfo.endCursor ?? undefined;
|
||||
totalNodesFetched += nodes.length;
|
||||
if (afterEachQuery) {
|
||||
afterEachQuery(totalNodesFetched, dataset, batch, pageInfo);
|
||||
}
|
||||
if (totalNodesFetched >= maxNodesFetched) {
|
||||
return dataset;
|
||||
}
|
||||
}
|
||||
return dataset;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.build",
|
||||
"compilerOptions": {
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true
|
||||
},
|
||||
"exclude": ["**/__mocks__/*", "**/__tests__/*"]
|
||||
}
|
||||
@@ -7,8 +7,8 @@
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noImplicitOverride": true,
|
||||
"noImplicitReturns": true,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"strict": true,
|
||||
"target": "ES2019",
|
||||
"outDir": "build",
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@expo/eas-json",
|
||||
"description": "A library for interacting with eas.json",
|
||||
"version": "3.18.0",
|
||||
"version": "3.13.0",
|
||||
"author": "Expo <[email protected]>",
|
||||
"bugs": "https://github.com/expo/eas-cli/issues",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "7.18.6",
|
||||
"@expo/eas-build-job": "1.0.30",
|
||||
"@expo/eas-build-job": "1.0.13",
|
||||
"chalk": "4.1.2",
|
||||
"env-string": "1.0.1",
|
||||
"fs-extra": "10.1.0",
|
||||
@@ -34,11 +34,10 @@
|
||||
"repository": "expo/eas-cli",
|
||||
"scripts": {
|
||||
"build": "tsc --project tsconfig.build.json",
|
||||
"build-ci": "tsc --project tsconfig.build-ci.json",
|
||||
"watch": "yarn build --watch --preserveWatchOutput",
|
||||
"typecheck": "tsc --project tsconfig.build-ci.json",
|
||||
"typecheck": "tsc",
|
||||
"prepack": "yarn rebuild",
|
||||
"rebuild": "rimraf build && yarn build-ci",
|
||||
"rebuild": "rimraf build && yarn build",
|
||||
"test": "jest",
|
||||
"clean": "rimraf build node_modules yarn-error.log"
|
||||
},
|
||||
|
||||
@@ -334,7 +334,6 @@
|
||||
"enum": [
|
||||
"default",
|
||||
"latest",
|
||||
"macos-ventura-13.4-xcode-14.3.1",
|
||||
"macos-ventura-13.3-xcode-14.3",
|
||||
"macos-monterey-12.6-xcode-14.2",
|
||||
"macos-monterey-12.6-xcode-14.1",
|
||||
@@ -346,9 +345,8 @@
|
||||
"macos-big-sur-11.4-xcode-12.5"
|
||||
],
|
||||
"markdownEnumDescriptions": [
|
||||
"`macos-ventura-13.3-xcode-14.3` for Apple silicon builders, `macos-monterey-12.6-xcode-14.1` for Intel builders",
|
||||
"`macos-ventura-13.4-xcode-14.3.1` for Apple silicon builders, `macos-monterey-12.6-xcode-14.2` for Intel builders",
|
||||
"only available for Apple silicon builders",
|
||||
"`macos-monterey-12.6-xcode-14.2` for Apple silicon builders, `macos-monterey-12.6-xcode-14.1` for Intel builders",
|
||||
"`macos-ventura-13.3-xcode-14.3` for Apple silicon builders, `macos-monterey-12.6-xcode-14.2` for Intel builders",
|
||||
"only available for Apple silicon builders"
|
||||
]
|
||||
},
|
||||
@@ -363,7 +361,7 @@
|
||||
"default": "default",
|
||||
"anyOf": [
|
||||
{
|
||||
"enum": ["default", "medium", "large", "m-medium"]
|
||||
"enum": ["default", "medium", "large", "intel-medium", "m-medium"]
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
@@ -464,11 +462,6 @@
|
||||
"The release will have no further changes. Its APKs are being served to all users, unless they are eligible to APKs of a more recent release."
|
||||
]
|
||||
},
|
||||
"rollout": {
|
||||
"type": "number",
|
||||
"description": "The initial fraction of users who are eligible to receive the release. Should be a value from 0 (no users) to 1 (all users). Works only with 'inProgress' release status. Learn more: https://developers.google.com/android-publisher/api-ref/rest/v3/edits.tracks",
|
||||
"markdownDescription": "The initial fraction of users who are eligible to receive the release. Should be a value from 0 (no users) to 1 (all users). Works only with `inProgress` release status. [Learn more](https://developers.google.com/android-publisher/api-ref/rest/v3/edits.tracks)"
|
||||
},
|
||||
"changesNotSentForReview": {
|
||||
"type": "boolean",
|
||||
"description": "Indicates that the changes sent with this submission will not be reviewed until they are explicitly sent for review from the Google Play Console UI. Defaults to false.",
|
||||
|
||||
@@ -3,8 +3,6 @@ import fs from 'fs-extra';
|
||||
import { vol } from 'memfs';
|
||||
|
||||
import { EasJsonAccessor } from '../accessor';
|
||||
import { InvalidEasJsonError } from '../errors';
|
||||
import { AndroidReleaseStatus } from '../submit/types';
|
||||
import { EasJsonUtils } from '../utils';
|
||||
|
||||
jest.mock('fs');
|
||||
@@ -239,157 +237,3 @@ test('get profile names', async () => {
|
||||
const allProfileNames = await EasJsonUtils.getSubmitProfileNamesAsync(accessor);
|
||||
expect(allProfileNames.sort()).toEqual(['production', 'blah'].sort());
|
||||
});
|
||||
|
||||
test.each([
|
||||
AndroidReleaseStatus.completed,
|
||||
AndroidReleaseStatus.draft,
|
||||
AndroidReleaseStatus.halted,
|
||||
])('android config with releaseStatus %s is valid when rollout is not set', async releaseStatus => {
|
||||
await fs.writeJson('/project/eas.json', {
|
||||
submit: {
|
||||
production: {
|
||||
android: {
|
||||
serviceAccountKeyPath: './path.json',
|
||||
track: 'beta',
|
||||
releaseStatus,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const accessor = EasJsonAccessor.fromProjectPath('/project');
|
||||
const androidProfile = await EasJsonUtils.getSubmitProfileAsync(
|
||||
accessor,
|
||||
Platform.ANDROID,
|
||||
'production'
|
||||
);
|
||||
|
||||
expect(androidProfile).toEqual({
|
||||
serviceAccountKeyPath: './path.json',
|
||||
track: 'beta',
|
||||
releaseStatus,
|
||||
changesNotSentForReview: false,
|
||||
});
|
||||
});
|
||||
|
||||
test.each([
|
||||
AndroidReleaseStatus.completed,
|
||||
AndroidReleaseStatus.draft,
|
||||
AndroidReleaseStatus.halted,
|
||||
])('android config with releaseStatus %s is invalid when rollout is set', async releaseStatus => {
|
||||
await fs.writeJson('/project/eas.json', {
|
||||
submit: {
|
||||
production: {
|
||||
android: {
|
||||
serviceAccountKeyPath: './path.json',
|
||||
track: 'beta',
|
||||
releaseStatus,
|
||||
rollout: 0.5,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const accessor = EasJsonAccessor.fromProjectPath('/project');
|
||||
const promise = EasJsonUtils.getSubmitProfileAsync(accessor, Platform.ANDROID, 'production');
|
||||
await expect(promise).rejects.toThrowError(InvalidEasJsonError);
|
||||
});
|
||||
|
||||
test(`android config with releaseStatus ${AndroidReleaseStatus.inProgress} is invalid when rollout is not set`, async () => {
|
||||
await fs.writeJson('/project/eas.json', {
|
||||
submit: {
|
||||
production: {
|
||||
android: {
|
||||
serviceAccountKeyPath: './path.json',
|
||||
track: 'beta',
|
||||
releaseStatus: AndroidReleaseStatus.inProgress,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const accessor = EasJsonAccessor.fromProjectPath('/project');
|
||||
const promise = EasJsonUtils.getSubmitProfileAsync(accessor, Platform.ANDROID, 'production');
|
||||
await expect(promise).rejects.toThrowError(InvalidEasJsonError);
|
||||
await expect(promise).rejects.toThrowError(/"submit\.production\.android\.rollout" is required/);
|
||||
});
|
||||
|
||||
test(`android config with releaseStatus ${AndroidReleaseStatus.inProgress} is valid when rollout is set`, async () => {
|
||||
await fs.writeJson('/project/eas.json', {
|
||||
submit: {
|
||||
production: {
|
||||
android: {
|
||||
serviceAccountKeyPath: './path.json',
|
||||
track: 'beta',
|
||||
releaseStatus: AndroidReleaseStatus.inProgress,
|
||||
rollout: 0.5,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const accessor = EasJsonAccessor.fromProjectPath('/project');
|
||||
const androidProfile = await EasJsonUtils.getSubmitProfileAsync(
|
||||
accessor,
|
||||
Platform.ANDROID,
|
||||
'production'
|
||||
);
|
||||
|
||||
expect(androidProfile).toEqual({
|
||||
serviceAccountKeyPath: './path.json',
|
||||
track: 'beta',
|
||||
releaseStatus: AndroidReleaseStatus.inProgress,
|
||||
changesNotSentForReview: false,
|
||||
rollout: 0.5,
|
||||
});
|
||||
});
|
||||
|
||||
test.each([0, 1, 0.2, 0.75, 0.22])('rollout value %s is valid', async rollout => {
|
||||
await fs.writeJson('/project/eas.json', {
|
||||
submit: {
|
||||
production: {
|
||||
android: {
|
||||
serviceAccountKeyPath: './path.json',
|
||||
track: 'beta',
|
||||
releaseStatus: AndroidReleaseStatus.inProgress,
|
||||
rollout,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const accessor = EasJsonAccessor.fromProjectPath('/project');
|
||||
const androidProfile = await EasJsonUtils.getSubmitProfileAsync(
|
||||
accessor,
|
||||
Platform.ANDROID,
|
||||
'production'
|
||||
);
|
||||
|
||||
expect(androidProfile).toEqual({
|
||||
serviceAccountKeyPath: './path.json',
|
||||
track: 'beta',
|
||||
releaseStatus: AndroidReleaseStatus.inProgress,
|
||||
changesNotSentForReview: false,
|
||||
rollout,
|
||||
});
|
||||
});
|
||||
|
||||
test.each([-5, 12, 1.2, 1.01, 99])('rollout value %s is invalid', async rollout => {
|
||||
await fs.writeJson('/project/eas.json', {
|
||||
submit: {
|
||||
production: {
|
||||
android: {
|
||||
serviceAccountKeyPath: './path.json',
|
||||
track: 'beta',
|
||||
releaseStatus: AndroidReleaseStatus.inProgress,
|
||||
rollout,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const accessor = EasJsonAccessor.fromProjectPath('/project');
|
||||
const promise = EasJsonUtils.getSubmitProfileAsync(accessor, Platform.ANDROID, 'production');
|
||||
|
||||
await expect(promise).rejects.toThrowError(InvalidEasJsonError);
|
||||
});
|
||||
@@ -12,11 +12,6 @@ export const AndroidSubmitProfileSchema = Joi.object({
|
||||
.default(AndroidReleaseStatus.completed),
|
||||
changesNotSentForReview: Joi.boolean().default(false),
|
||||
applicationId: Joi.string(),
|
||||
rollout: Joi.number().min(0).max(1).when('releaseStatus', {
|
||||
is: AndroidReleaseStatus.inProgress,
|
||||
then: Joi.required(),
|
||||
otherwise: Joi.forbidden(),
|
||||
}),
|
||||
});
|
||||
|
||||
export const IosSubmitProfileSchema = Joi.object({
|
||||
|
||||
@@ -20,7 +20,6 @@ export interface AndroidSubmitProfile {
|
||||
releaseStatus: AndroidReleaseStatus;
|
||||
changesNotSentForReview: boolean;
|
||||
applicationId?: string;
|
||||
rollout?: number;
|
||||
}
|
||||
|
||||
export const AndroidSubmitProfileFieldsToEvaluate: (keyof AndroidSubmitProfile)[] = [
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.build",
|
||||
"compilerOptions": {
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true
|
||||
},
|
||||
"exclude": ["**/__mocks__/*", "**/__tests__/*"]
|
||||
}
|
||||
@@ -7,8 +7,8 @@
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noImplicitOverride": true,
|
||||
"noImplicitReturns": true,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"strict": true,
|
||||
"target": "ES2019",
|
||||
"outDir": "build",
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
declare module 'freeport-async' {
|
||||
interface FreePortOptions {
|
||||
hostnames?: (string | null)[];
|
||||
}
|
||||
|
||||
function freePortAsync(rangeStart: number, options?: FreePortOptions): Promise<number>;
|
||||
export = freePortAsync;
|
||||
}
|
||||
@@ -2,11 +2,6 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@0no-co/graphql.web@^1.0.1":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@0no-co/graphql.web/-/graphql.web-1.0.4.tgz#9606eb651955499525d068ce0ad8bea596286ce2"
|
||||
integrity sha512-W3ezhHGfO0MS1PtGloaTpg0PbaT8aZSmmaerL7idtU5F7oCI+uu25k+MsMS31BVFlp4aMkHSrNRxiD72IlK8TA==
|
||||
|
||||
"@ampproject/remapping@^2.1.0":
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d"
|
||||
@@ -1352,7 +1347,49 @@
|
||||
node-forge "^1.2.1"
|
||||
nullthrows "^1.1.1"
|
||||
|
||||
"@expo/[email protected].4", "@expo/config-plugins@~7.2.0":
|
||||
"@expo/[email protected].3":
|
||||
version "7.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-7.2.3.tgz#982800bf1aec3811f3e087a1e8784c82f0853672"
|
||||
integrity sha512-8wBR4HH2PhPbupUNXCB1aslMD4vNYEnew26os1nCZ4vaUwcp0LeI9Zl2ycOCBVwGSdd5RNHFzK2R/OFE9P13tA==
|
||||
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/config-plugins@~5.0.3":
|
||||
version "5.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-5.0.4.tgz#216fea6558fe66615af1370de55193f4181cb23e"
|
||||
integrity sha512-vzUcVpqOMs3h+hyRdhGwk+eGIOhXa5xYdd92yO17RMNHav3v/+ekMbs7XA2c3lepMO8Yd4/5hqmRw9ZTL6jGzg==
|
||||
dependencies:
|
||||
"@expo/config-types" "^47.0.0"
|
||||
"@expo/json-file" "8.2.36"
|
||||
"@expo/plist" "0.0.18"
|
||||
"@expo/sdk-runtime-versions" "^1.0.0"
|
||||
"@react-native/normalize-color" "^2.0.0"
|
||||
chalk "^4.1.2"
|
||||
debug "^4.3.1"
|
||||
find-up "~5.0.0"
|
||||
getenv "^1.0.0"
|
||||
glob "7.1.6"
|
||||
resolve-from "^5.0.0"
|
||||
semver "^7.3.5"
|
||||
slash "^3.0.0"
|
||||
xcode "^3.0.1"
|
||||
xml2js "0.4.23"
|
||||
|
||||
"@expo/config-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==
|
||||
@@ -1378,7 +1415,12 @@
|
||||
resolved "https://registry.yarnpkg.com/@expo/config-types/-/config-types-49.0.0.tgz#15ffef715285c06703f6fb7ec0cda853f645cc09"
|
||||
integrity sha512-8eyREVi+K2acnMBe/rTIu1dOfyR2+AMnTLHlut+YpMV9OZPdeKV0Bs9BxAewGqBA2slslbQ9N39IS2CuTKpXkA==
|
||||
|
||||
"@expo/config@8.1.2", "@expo/config@~8.1.0":
|
||||
"@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/[email protected]":
|
||||
version "8.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@expo/config/-/config-8.1.2.tgz#7fff28b3acefe39702e9f3ce1c9fd896a52caa80"
|
||||
integrity sha512-4e7hzPj50mQIlsrzOH6XZ36O094mPfPTIDIH4yv49bWNMc7GFLTofB/lcT+QyxiLaJuC0Wlk9yOLB8DIqmtwug==
|
||||
@@ -1395,13 +1437,30 @@
|
||||
slugify "^1.3.4"
|
||||
sucrase "^3.20.0"
|
||||
|
||||
"@expo/eas-build-job@1.0.30":
|
||||
version "1.0.30"
|
||||
resolved "https://registry.yarnpkg.com/@expo/eas-build-job/-/eas-build-job-1.0.30.tgz#f8c57a673a2cc328f4041346996c480c3d910e92"
|
||||
integrity sha512-KQGn9POn5p3guMNQJ5ykG3wffRlSEpjTCLO87d5lJll9E4u1grpqHJH2chOh5ICxg7tiWcO4iXt5S8tU7Ogpig==
|
||||
"@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==
|
||||
dependencies:
|
||||
joi "^17.9.2"
|
||||
semver "^7.5.4"
|
||||
"@babel/code-frame" "~7.10.4"
|
||||
"@expo/config-plugins" "~5.0.3"
|
||||
"@expo/config-types" "^47.0.0"
|
||||
"@expo/json-file" "8.2.36"
|
||||
getenv "^1.0.0"
|
||||
glob "7.1.6"
|
||||
require-from-string "^2.0.2"
|
||||
resolve-from "^5.0.0"
|
||||
semver "7.3.2"
|
||||
slugify "^1.3.4"
|
||||
sucrase "^3.20.0"
|
||||
|
||||
"@expo/[email protected]":
|
||||
version "1.0.13"
|
||||
resolved "https://registry.yarnpkg.com/@expo/eas-build-job/-/eas-build-job-1.0.13.tgz#1cd3981e86e1d4235f20a96f7ac768793b4f7c62"
|
||||
integrity sha512-Q0i3GposBj/b2OPL0CV00HczawtslorNpoJSBQfB4aNR6i7DBIZZ1jWJtrFP8+zHZqlUi4d21aoblNUrKpgBew==
|
||||
dependencies:
|
||||
joi "^17.7.0"
|
||||
semver "^7.3.8"
|
||||
|
||||
"@expo/[email protected]":
|
||||
version "0.3.22"
|
||||
@@ -1438,10 +1497,10 @@
|
||||
json5 "^2.2.2"
|
||||
write-file-atomic "^2.3.0"
|
||||
|
||||
"@expo/[email protected].30":
|
||||
version "1.0.30"
|
||||
resolved "https://registry.yarnpkg.com/@expo/logger/-/logger-1.0.30.tgz#f964cc7b73cbb0c05de44c874a9451f5cfd2ec2d"
|
||||
integrity sha512-8wEUDZNLAv+Wi4jvo0kFErQ7nc4ZFfArq5GDeSCoIrRfdKK8baot7YJoJVsmpQ9/JXnTEAgwGDP3vYaR5wzcyg==
|
||||
"@expo/[email protected].21":
|
||||
version "1.0.21"
|
||||
resolved "https://registry.yarnpkg.com/@expo/logger/-/logger-1.0.21.tgz#9271b52b8e27159cbbe3385b9a01fca3317b37c2"
|
||||
integrity sha512-Vz+LHDGWUfowAwL10nBKqxrMYvO4qdZ8hLKcqUYc5mXBt+jmv7RP+8fcsMIejJEMWmYC2meO5eeCMLKKhEIgMA==
|
||||
dependencies:
|
||||
"@types/bunyan" "^1.8.8"
|
||||
bunyan "^1.8.15"
|
||||
@@ -1486,6 +1545,15 @@
|
||||
dependencies:
|
||||
node-forge "^1.2.1"
|
||||
|
||||
"@expo/[email protected]":
|
||||
version "0.0.18"
|
||||
resolved "https://registry.yarnpkg.com/@expo/plist/-/plist-0.0.18.tgz#9abcde78df703a88f6d9fa1a557ee2f045d178b0"
|
||||
integrity sha512-+48gRqUiz65R21CZ/IXa7RNBXgAI/uPSdvJqoN9x1hfL44DNbUoWHgHiEXTx7XelcATpDwNTz6sHLfy0iNqf+w==
|
||||
dependencies:
|
||||
"@xmldom/xmldom" "~0.7.0"
|
||||
base64-js "^1.2.3"
|
||||
xmlbuilder "^14.0.0"
|
||||
|
||||
"@expo/[email protected]", "@expo/plist@^0.0.20":
|
||||
version "0.0.20"
|
||||
resolved "https://registry.yarnpkg.com/@expo/plist/-/plist-0.0.20.tgz#a6b3124438031c02b762bad5a47b70584d3c0072"
|
||||
@@ -1516,21 +1584,21 @@
|
||||
semver "^7.3.7"
|
||||
tslib "^2.4.0"
|
||||
|
||||
"@expo/prebuild-config@6.2.5":
|
||||
version "6.2.5"
|
||||
resolved "https://registry.yarnpkg.com/@expo/prebuild-config/-/prebuild-config-6.2.5.tgz#2e7fdce8ddef3ac97fa05b4542f2b62a43bcea4b"
|
||||
integrity sha512-XHgQ4OWZ03rzczD+D2ulQRjyHCVnA36cfX4q+r2x1Say4hI7lIg75ZQEsWdEMU9rZV8TbDUtZlPL4pxNWpYu7Q==
|
||||
"@expo/prebuild-config@5.0.7":
|
||||
version "5.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@expo/prebuild-config/-/prebuild-config-5.0.7.tgz#4658b66126c4d32c7b6302571e458a71811b07aa"
|
||||
integrity sha512-D+TBpJUHe4+oTGFPb4o0rrw/h1xxc6wF+abJnbDHUkhnaeiHkE2O3ByS7FdiZ2FT36t0OKqeSKG/xFwWT3m1Ew==
|
||||
dependencies:
|
||||
"@expo/config" "~8.1.0"
|
||||
"@expo/config-plugins" "~7.2.0"
|
||||
"@expo/config-types" "^49.0.0-alpha.1"
|
||||
"@expo/config" "~7.0.2"
|
||||
"@expo/config-plugins" "~5.0.3"
|
||||
"@expo/config-types" "^47.0.0"
|
||||
"@expo/image-utils" "0.3.22"
|
||||
"@expo/json-file" "^8.2.37"
|
||||
"@expo/json-file" "8.2.36"
|
||||
debug "^4.3.1"
|
||||
fs-extra "^9.0.0"
|
||||
resolve-from "^5.0.0"
|
||||
semver "7.5.3"
|
||||
xml2js "0.6.0"
|
||||
semver "7.3.2"
|
||||
xml2js "0.4.23"
|
||||
|
||||
"@expo/[email protected]":
|
||||
version "1.0.0"
|
||||
@@ -1569,28 +1637,25 @@
|
||||
dependencies:
|
||||
cross-spawn "^7.0.3"
|
||||
|
||||
"@expo/spawn-async@^1.7.2":
|
||||
"@expo/spawn-async@^1.7.0":
|
||||
version "1.7.2"
|
||||
resolved "https://registry.yarnpkg.com/@expo/spawn-async/-/spawn-async-1.7.2.tgz#fcfe66c3e387245e72154b1a7eae8cada6a47f58"
|
||||
integrity sha512-QdWi16+CHB9JYP7gma19OVVg0BFkvU8zNj9GjWorYI8Iv8FUxjOCcYRuAmX4s/h91e4e7BPsskc8cSrZYho9Ew==
|
||||
dependencies:
|
||||
cross-spawn "^7.0.3"
|
||||
|
||||
"@expo/[email protected]1":
|
||||
version "1.0.31"
|
||||
resolved "https://registry.yarnpkg.com/@expo/steps/-/steps-1.0.31.tgz#61e0456e54bc63bd714aa40b9be27503c032caf0"
|
||||
integrity sha512-TPuaihUQ9MfVmgG5OzFdMKXcBAgv1dfLZWGpk/k5hWBjPZAoe01UXbw8GCt6F09tS2Z256d2G/kOTJzISLNcjQ==
|
||||
"@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==
|
||||
dependencies:
|
||||
"@expo/logger" "1.0.30"
|
||||
"@expo/spawn-async" "^1.7.2"
|
||||
"@expo/logger" "1.0.21"
|
||||
"@expo/spawn-async" "^1.7.0"
|
||||
arg "^5.0.2"
|
||||
fs-extra "^11.1.1"
|
||||
joi "^17.9.2"
|
||||
lodash.clonedeep "^4.5.0"
|
||||
lodash.get "^4.4.2"
|
||||
joi "^17.7.0"
|
||||
this-file "^2.0.3"
|
||||
uuid "^9.0.0"
|
||||
yaml "^2.3.1"
|
||||
yaml "^2.2.1"
|
||||
|
||||
"@expo/[email protected]":
|
||||
version "1.0.0"
|
||||
@@ -4544,21 +4609,20 @@
|
||||
"@typescript-eslint/types" "5.33.0"
|
||||
eslint-visitor-keys "^3.3.0"
|
||||
|
||||
"@urql/core@4.0.11", "@urql/core@>=4.0.0":
|
||||
version "4.0.11"
|
||||
resolved "https://registry.yarnpkg.com/@urql/core/-/core-4.0.11.tgz#b4e8bf3a3ff1a2519bb3aec38c7be99d2523308d"
|
||||
integrity sha512-FFdY97vF5xnUrElcGw9erOLvtu+KGMLfwrLNDfv4IPgdp2IBsiGe+Kb7Aypfd3kH//BETewVSLm3+y2sSzjX6A==
|
||||
"@urql/core@3.1.1", "@urql/core@>=3.0.0":
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@urql/core/-/core-3.1.1.tgz#a49cd572360d01f2469a786b294fba2269a65e53"
|
||||
integrity sha512-Mnxtq4I4QeFJsgs7Iytw+HyhiGxISR6qtyk66c9tipozLZ6QVxrCiUPF2HY4BxNIabaxcp+rivadvm8NAnXj4Q==
|
||||
dependencies:
|
||||
"@0no-co/graphql.web" "^1.0.1"
|
||||
wonka "^6.3.2"
|
||||
wonka "^6.1.2"
|
||||
|
||||
"@urql/exchange-retry@1.2.0":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@urql/exchange-retry/-/exchange-retry-1.2.0.tgz#23d3ec711754e3c67a843e0106f2cabddff2e5ff"
|
||||
integrity sha512-1O/biKiVhhn0EtvDF4UOvz325K4RrLupfL8rHcmqD2TBLv4qVDWQuzx4JGa1FfqjjRb+C9TNZ6w19f32Mq85Ug==
|
||||
"@urql/exchange-retry@1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@urql/exchange-retry/-/exchange-retry-1.0.0.tgz#25a48ef0c2f6854f5617e2ca4ea25ae240f1fcbc"
|
||||
integrity sha512-UGyyGAMXzop9C/fIoe7Ij63DkPSy1uMw2jipB5dnB8R3kl80za7LYzVnA1HvBEt2ZPWfMuwez/VGLOQ7XX4bTA==
|
||||
dependencies:
|
||||
"@urql/core" ">=4.0.0"
|
||||
wonka "^6.3.2"
|
||||
"@urql/core" ">=3.0.0"
|
||||
wonka "^6.0.0"
|
||||
|
||||
"@whatwg-node/[email protected]", "@whatwg-node/fetch@^0.5.0":
|
||||
version "0.5.4"
|
||||
@@ -4589,6 +4653,11 @@
|
||||
undici "^5.8.0"
|
||||
web-streams-polyfill "^3.2.0"
|
||||
|
||||
"@xmldom/xmldom@~0.7.0":
|
||||
version "0.7.2"
|
||||
resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.7.2.tgz#d920079e66806b2626b5311955f6a7c4bed1cba8"
|
||||
integrity sha512-t/Zqo0ewes3iq6zGqEqJNUWI27Acr3jkmSUNp6E3nl0Z2XbtqAG5XYqPNLdYonILmhcxANsIidh69tHzjXtuRg==
|
||||
|
||||
"@xmldom/xmldom@~0.7.7":
|
||||
version "0.7.9"
|
||||
resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.7.9.tgz#7f9278a50e737920e21b297b8a35286e9942c056"
|
||||
@@ -7449,6 +7518,11 @@ [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"
|
||||
@@ -7497,15 +7571,6 @@ fs-extra@^11.1.0:
|
||||
jsonfile "^6.0.1"
|
||||
universalify "^2.0.0"
|
||||
|
||||
fs-extra@^11.1.1:
|
||||
version "11.1.1"
|
||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.1.1.tgz#da69f7c39f3b002378b0954bb6ae7efdc0876e2d"
|
||||
integrity sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==
|
||||
dependencies:
|
||||
graceful-fs "^4.2.0"
|
||||
jsonfile "^6.0.1"
|
||||
universalify "^2.0.0"
|
||||
|
||||
fs-extra@^8.1:
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
|
||||
@@ -9374,10 +9439,10 @@ [email protected]:
|
||||
"@sideway/formula" "^3.0.0"
|
||||
"@sideway/pinpoint" "^2.0.0"
|
||||
|
||||
joi@^17.9.2:
|
||||
version "17.9.2"
|
||||
resolved "https://registry.yarnpkg.com/joi/-/joi-17.9.2.tgz#8b2e4724188369f55451aebd1d0b1d9482470690"
|
||||
integrity sha512-Itk/r+V4Dx0V3c7RLFdRh12IOjySm2/WGPMubBT92cQvRfYZhPM2W0hZlctjj72iES8jsRCwp7S/cRmWBnJ4nw==
|
||||
joi@^17.7.0:
|
||||
version "17.8.3"
|
||||
resolved "https://registry.yarnpkg.com/joi/-/joi-17.8.3.tgz#d772fe27a87a5cda21aace5cf11eee8671ca7e6f"
|
||||
integrity sha512-q5Fn6Tj/jR8PfrLrx4fpGH4v9qM6o+vDUfD4/3vxxyg34OmKcNqYZ1qn2mpLza96S8tL0p0rIw2gOZX+/cTg9w==
|
||||
dependencies:
|
||||
"@hapi/hoek" "^9.0.0"
|
||||
"@hapi/topo" "^5.0.0"
|
||||
@@ -9739,17 +9804,12 @@ locate-path@^6.0.0:
|
||||
dependencies:
|
||||
p-locate "^5.0.0"
|
||||
|
||||
lodash.clonedeep@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
|
||||
integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==
|
||||
|
||||
lodash.flatten@^4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f"
|
||||
integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=
|
||||
|
||||
lodash.get@^4, lodash.get@^4.4.2:
|
||||
lodash.get@^4:
|
||||
version "4.4.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
|
||||
integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=
|
||||
@@ -12117,13 +12177,6 @@ semver@^7.3.7:
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
semver@^7.5.4:
|
||||
version "7.5.4"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
|
||||
integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
[email protected]:
|
||||
version "0.18.0"
|
||||
resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be"
|
||||
@@ -13645,10 +13698,15 @@ widest-line@^3.1.0:
|
||||
dependencies:
|
||||
string-width "^4.0.0"
|
||||
|
||||
wonka@^6.3.2:
|
||||
version "6.3.2"
|
||||
resolved "https://registry.yarnpkg.com/wonka/-/wonka-6.3.2.tgz#6f32992b332251d7b696b038990f4dc284b3b33d"
|
||||
integrity sha512-2xXbQ1LnwNS7egVm1HPhW2FyKrekolzhpM3mCwXdQr55gO+tAiY76rhb32OL9kKsW8taj++iP7C6hxlVzbnvrw==
|
||||
wonka@^6.0.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/wonka/-/wonka-6.1.0.tgz#65297ebf7031ae46d4b0c56da93950fb3ae5baaa"
|
||||
integrity sha512-VgiMCz7BXOiDbgpVhf5iNhK7hurteY5Jv0fDJewUkY0s4fbxQD2iKqfGxNXNTwp2v3bgT8QVu2l5H7YdkZ5WIA==
|
||||
|
||||
wonka@^6.1.2:
|
||||
version "6.1.2"
|
||||
resolved "https://registry.yarnpkg.com/wonka/-/wonka-6.1.2.tgz#2c66fa5b26a12f002a03619b988258313d0b5352"
|
||||
integrity sha512-zNrXPMccg/7OEp9tSfFkMgTvhhowqasiSHdJ3eCZolXxVTV/aT6HUTofoZk9gwRbGoFey/Nss3JaZKUMKMbofg==
|
||||
|
||||
word-wrap@^1.2.3:
|
||||
version "1.2.3"
|
||||
@@ -13794,6 +13852,14 @@ [email protected]:
|
||||
sax ">=0.6.0"
|
||||
xmlbuilder "~9.0.1"
|
||||
|
||||
[email protected]:
|
||||
version "0.4.23"
|
||||
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66"
|
||||
integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==
|
||||
dependencies:
|
||||
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"
|
||||
@@ -13852,10 +13918,10 @@ yaml@^1.10.0, yaml@^1.7.2:
|
||||
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.0.tgz#3b593add944876077d4d683fee01081bd9fff31e"
|
||||
integrity sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==
|
||||
|
||||
yaml@^2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.1.tgz#02fe0975d23cd441242aa7204e09fc28ac2ac33b"
|
||||
integrity sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==
|
||||
yaml@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.2.1.tgz#3014bf0482dcd15147aa8e56109ce8632cd60ce4"
|
||||
integrity sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==
|
||||
|
||||
[email protected], yargs-parser@^20.2.2:
|
||||
version "20.2.4"
|
||||
|
||||
Reference in new issue
Block a user