Compare commits

..
221 changed files with 9824 additions and 5942 deletions

No files matched your search

+1 -1
View File
@@ -14,7 +14,7 @@ jobs:
token: ${{ secrets.EXPO_BOT_PAT }}
- uses: actions/setup-node@v2
with:
node-version: 20
node-version: 18
- name: Checkout Pull Request
run: gh pr checkout ${{ github.event.issue.number }}
env:
+1 -5
View File
@@ -8,10 +8,6 @@ on:
- labeled
- unlabeled
concurrency:
group: changelog-${{ github.ref }}
cancel-in-progress: true
jobs:
pr-changelog-entry:
name: Check CHANGELOG.md updated
@@ -20,7 +16,7 @@ jobs:
- uses: actions/checkout@v2
- name: Check if CHANGELOG.md was updated
id: changelog-updated
uses: tj-actions/changed-files@v41
uses: tj-actions/changed-files@v35
with:
files: CHANGELOG.md
- name: Fail if CHANGELOG.md was not updated and the "no changelog" label is absent
+9 -9
View File
@@ -27,9 +27,9 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 20
node-version: 18
- run: yarn install --frozen-lockfile --check-files
- run: yarn build
- run: yarn build-ci
- name: Build tarballs
working-directory: ${{ github.workspace }}/packages/eas-cli
run: |
@@ -68,9 +68,9 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 20
node-version: 18
- run: yarn install --frozen-lockfile --check-files
- run: yarn build
- run: yarn build-ci
- name: Build tarballs
working-directory: ${{ github.workspace }}/packages/eas-cli
run: |
@@ -96,10 +96,10 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 20
node-version: 18
- run: yarn install --frozen-lockfile --check-files
- run: sudo apt-get install nsis
- run: yarn build
- run: yarn build-ci
- run: |
yarn pretarball-ci
yarn oclif pack:win
@@ -138,11 +138,11 @@ jobs:
with:
registry-url: 'https://registry.npmjs.org/'
scope: 'expo'
node-version: 20
node-version: 18
- name: Install dependencies
run: yarn install --frozen-lockfile --check-files
- name: Build
run: yarn build
run: yarn build-ci
- name: Publish packages to npm
run: yarn lerna publish from-package --yes --no-verify-access
env:
@@ -165,7 +165,7 @@ jobs:
token: ${{ secrets.EXPO_BOT_PAT }}
- uses: actions/setup-node@v2
with:
node-version: 20
node-version: 18
- name: Install dependencies
working-directory: ./scripts
run: yarn install --frozen-lockfile --check-files
+1 -4
View File
@@ -2,9 +2,6 @@ name: Size
on:
pull_request:
types: [synchronize, opened]
concurrency:
group: size-${{ github.ref }}
cancel-in-progress: true
jobs:
compare:
runs-on: ubuntu-latest
@@ -12,7 +9,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 20
node-version: 18
- uses: preactjs/compressed-size-action@v2
with:
build-script: 'build:tarballs:linux'
+1 -5
View File
@@ -13,10 +13,6 @@ on:
paths:
- 'scripts/**'
concurrency:
group: test-scripts-${{ github.ref }}
cancel-in-progress: true
jobs:
test:
runs-on: ubuntu-latest
@@ -25,6 +21,6 @@ jobs:
- name: Setup node
uses: actions/setup-node@v2
with:
node-version: 20
node-version: 18
- run: yarn install --frozen-lockfile --check-files
- run: yarn typecheck
+2 -6
View File
@@ -6,18 +6,14 @@ on:
pull_request:
types: [opened, synchronize]
concurrency:
group: test-${{ github.ref }}
cancel-in-progress: true
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node: ['16', '18', '20']
node: ['14', '16', '18']
include:
- node: '20'
- node: '18'
coverage: true
name: Test with Node ${{ matrix.node }}
steps:
-34
View File
@@ -8,48 +8,14 @@ This is the log of notable changes to EAS CLI and related packages.
### 🎉 New features
- Add `build:delete` command. ([#2178](https://github.com/expo/eas-cli/pull/2178) by [@radoslawkrzemien](https://github.com/radoslawkrzemien))
- Add filter flags for `platform` and `profile` to `build:cancel` and `build:delete` commands. ([#2178](https://github.com/expo/eas-cli/pull/2178) by [@radoslawkrzemien](https://github.com/radoslawkrzemien))
### 🐛 Bug fixes
### 🧹 Chores
- Remove "bare"-specific **eas.json** template. ([#2179](https://github.com/expo/eas-cli/pull/2179) by [@sjchmiela](https://github.com/sjchmiela))
- Prompt users if they want to continue if EAS CLI fails to provision the devices. ([#2181](https://github.com/expo/eas-cli/pull/2181) by [@szdziedzic](https://github.com/szdziedzic))
- Update `eas-cli` and `@expo/eas-json` dependencies. ([#2176](https://github.com/expo/eas-cli/pull/2176) by [@szdziedzic](https://github.com/szdziedzic))
- Prompt user to map channel on update if unmapped. ([#2185](https://github.com/expo/eas-cli/pull/2185) by [@quinlanj](https://github.com/quinlanj))
## [6.0.0](https://github.com/expo/eas-cli/releases/tag/v6.0.0) - 2024-01-12
### 🛠 Breaking changes
- Drop support for Node 14. ([#2175](https://github.com/expo/eas-cli/pull/2175) by [@szdziedzic](https://github.com/szdziedzic))
### 🎉 New features
- Allow undefined update message for EAS Update publishing when no VCS. ([#2148](https://github.com/expo/eas-cli/pull/2148) by [@wschurman](https://github.com/wschurman))
### 🧹 Chores
- Upgrade `@expo/eas-build-job` to `1.0.56`, thus removing unused (since [#1524](https://github.com/expo/eas-cli/pull/1524)) support for S3 project archives. ([#2165](https://github.com/expo/eas-cli/pull/2165) by [@sjchmiela](https://github.com/sjchmiela))
## [5.9.3](https://github.com/expo/eas-cli/releases/tag/v5.9.3) - 2023-12-19
### 🧹 Chores
- Rename getUpdateGroupJsonInfo. ([#2157](https://github.com/expo/eas-cli/pull/2157) by [@quinlanj](https://github.com/quinlanj))
- Add new Xcode 15.1 image to `eas.schema.json`. ([#2155](https://github.com/expo/eas-cli/pull/2155) by [@szdziedzic](https://github.com/szdziedzic))
## [5.9.2](https://github.com/expo/eas-cli/releases/tag/v5.9.2) - 2023-12-15
### 🧹 Chores
- Throw error if custom build config is gitignored. ([#2123](https://github.com/expo/eas-cli/pull/2123) by [@szdziedzic](https://github.com/szdziedzic))
- Update `@expo/steps` library to `1.0.51`. ([#2130](https://github.com/expo/eas-cli/pull/2130) by [@szdziedzic](https://github.com/szdziedzic))
- Update `eas.schema.json` to include changes after some of our images were migrated from Ubuntu 18.04 to Ubuntu 20.04. ([#2137](https://github.com/expo/eas-cli/pull/2137) by [@szdziedzic](https://github.com/szdziedzic))
- Update oclif dependencies. ([#2008](https://github.com/expo/eas-cli/pull/2008) by [@radoslawkrzemien](https://github.com/radoslawkrzemien))
- Upgrade `eas-build-job` and unify how we're handling `buildMode`. ([#2138](https://github.com/expo/eas-cli/pull/2138) by [@sjchmiela](https://github.com/sjchmiela))
## [5.9.1](https://github.com/expo/eas-cli/releases/tag/v5.9.1) - 2023-11-20
-19
View File
@@ -18,25 +18,6 @@ If you're making changes to `packages/eas-json` or prefer/need to work with prod
yarn start
```
If it is easier for you to work with the code locally with compiler options set to:
```json
...
"compilerOptions": {
...
"noUnusedLocals": false,
"noUnusedParameters": false,
...
}
...
```
you can consider using:
```
yarn start-allow-unused
```
## Format
- Be sure to update the [`CHANGELOG.md`](./CHANGELOG.md) with changes for every PR. There is a changelog bot that can generate the proper entry for you. The instructions on how to use it are in the PR description placeholder.
+7
View File
@@ -0,0 +1,7 @@
module.exports = {
projects: [
require('./packages/eas-cli/jest.config.js'),
require('./packages/eas-json/jest.config.js'),
],
testPathIgnorePatterns: ['.*'],
};
-15
View File
@@ -1,15 +0,0 @@
import type { Config } from 'jest';
// eslint-disable-next-line import/no-relative-packages
import easCliConfig from './packages/eas-cli/jest.config';
// eslint-disable-next-line import/no-relative-packages
import easJsonConfig from './packages/eas-json/jest.config';
const config: Config = {
projects: [easCliConfig, easJsonConfig],
testPathIgnorePatterns: ['.*'],
watchPlugins: ['jest-watch-typeahead/filename', 'jest-watch-typeahead/testname'],
collectCoverageFrom: ['<rootDir>/src/**/*.{ts,tsx,js,jsx}'],
};
export default config;
+7
View File
@@ -0,0 +1,7 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testRegex: '/__tests__/.*(test|spec)\\.[jt]sx?$',
watchPlugins: ['jest-watch-typeahead/filename', 'jest-watch-typeahead/testname'],
collectCoverageFrom: ['<rootDir>/src/**/*.{ts,tsx,js,jsx}'],
};
-9
View File
@@ -1,9 +0,0 @@
import type { Config } from 'jest';
const config: Config = {
preset: 'ts-jest',
testEnvironment: 'node',
testRegex: '/__tests__/.*(test|spec)\\.[jt]sx?$',
};
export default config;
+2 -1
View File
@@ -1,5 +1,6 @@
{
"npmClient": "yarn",
"version": "6.0.0",
"useWorkspaces": true,
"version": "5.9.1",
"$schema": "node_modules/lerna/schemas/lerna-schema.json"
}
+14 -14
View File
@@ -6,11 +6,11 @@
],
"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",
"start": "lerna run watch --stream --parallel",
"start-allow-unused": "lerna run watch-allow-unused --stream --parallel",
"watch": "yarn start",
"eas": "packages/eas-cli/bin/run",
"lint": "eslint .",
@@ -20,22 +20,22 @@
"clean": "lerna run clean && rm -rf node_modules coverage"
},
"devDependencies": {
"@types/jest": "29.5.11",
"@types/node": "20.11.0",
"eslint": "8.56.0",
"eslint-config-universe": "12.0.0",
"eslint-plugin-async-protect": "3.1.0",
"@types/jest": "29.2.5",
"@types/node": "18.11.18",
"eslint": "8.31.0",
"eslint-config-universe": "11.1.1",
"eslint-plugin-async-protect": "3.0.0",
"eslint-plugin-node": "11.1.0",
"jest": "29.7.0",
"jest-watch-typeahead": "2.2.2",
"lerna": "7.4.2",
"jest": "29.3.1",
"jest-watch-typeahead": "2.2.1",
"lerna": "6.4.1",
"oclif": "^3.9.0",
"prettier": "3.1.1",
"ts-jest": "29.1.1",
"typescript": "5.3.3"
"prettier": "2.8.2",
"ts-jest": "29.0.3",
"typescript": "4.9.4"
},
"volta": {
"node": "20.11.0",
"yarn": "1.22.21"
"node": "18.6.0",
"yarn": "1.22.19"
}
}
+65 -67
View File
@@ -135,7 +135,7 @@ ALIASES
$ eas login
```
_See code: [src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/account/login.ts)_
_See code: [src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/account/login.ts)_
## `eas account:logout`
@@ -152,7 +152,7 @@ ALIASES
$ eas logout
```
_See code: [src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/account/logout.ts)_
_See code: [src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/account/logout.ts)_
## `eas account:view`
@@ -169,7 +169,7 @@ ALIASES
$ eas whoami
```
_See code: [src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/account/view.ts)_
_See code: [src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/account/view.ts)_
## `eas analytics [STATUS]`
@@ -183,7 +183,7 @@ DESCRIPTION
display or change analytics settings
```
_See code: [src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/analytics.ts)_
_See code: [src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/analytics.ts)_
## `eas autocomplete [SHELL]`
@@ -194,7 +194,7 @@ USAGE
$ eas autocomplete [SHELL] [-r]
ARGUMENTS
SHELL (zsh|bash|powershell) Shell type
SHELL shell type
FLAGS
-r, --refresh-cache Refresh cache (ignores displaying instructions)
@@ -209,12 +209,10 @@ EXAMPLES
$ eas autocomplete zsh
$ eas autocomplete powershell
$ eas autocomplete --refresh-cache
```
_See code: [@oclif/plugin-autocomplete](https://github.com/oclif/plugin-autocomplete/blob/v2.3.10/src/commands/autocomplete/index.ts)_
_See code: [@oclif/plugin-autocomplete](https://github.com/oclif/plugin-autocomplete/blob/v1.3.10/src/commands/autocomplete/index.ts)_
## `eas branch:create [NAME]`
@@ -235,7 +233,7 @@ DESCRIPTION
create a branch
```
_See code: [src/commands/branch/create.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/branch/create.ts)_
_See code: [src/commands/branch/create.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/branch/create.ts)_
## `eas branch:delete [NAME]`
@@ -256,7 +254,7 @@ DESCRIPTION
delete a branch
```
_See code: [src/commands/branch/delete.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/branch/delete.ts)_
_See code: [src/commands/branch/delete.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/branch/delete.ts)_
## `eas branch:list`
@@ -276,7 +274,7 @@ DESCRIPTION
list all branches
```
_See code: [src/commands/branch/list.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/branch/list.ts)_
_See code: [src/commands/branch/list.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/branch/list.ts)_
## `eas branch:rename`
@@ -296,7 +294,7 @@ DESCRIPTION
rename a branch
```
_See code: [src/commands/branch/rename.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/branch/rename.ts)_
_See code: [src/commands/branch/rename.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/branch/rename.ts)_
## `eas branch:view [NAME]`
@@ -319,7 +317,7 @@ DESCRIPTION
view a branch
```
_See code: [src/commands/branch/view.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/branch/view.ts)_
_See code: [src/commands/branch/view.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/branch/view.ts)_
## `eas build`
@@ -349,7 +347,7 @@ DESCRIPTION
start a build
```
_See code: [src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/build/index.ts)_
_See code: [src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/build/index.ts)_
## `eas build:cancel [BUILD_ID]`
@@ -366,7 +364,7 @@ DESCRIPTION
cancel a build
```
_See code: [src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/build/cancel.ts)_
_See code: [src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/build/cancel.ts)_
## `eas build:configure`
@@ -383,7 +381,7 @@ DESCRIPTION
configure the project to support EAS Build
```
_See code: [src/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/build/configure.ts)_
_See code: [src/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/build/configure.ts)_
## `eas build:inspect`
@@ -418,7 +416,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/v6.0.0/src/commands/build/inspect.ts)_
_See code: [src/commands/build/inspect.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/build/inspect.ts)_
## `eas build:list`
@@ -456,7 +454,7 @@ DESCRIPTION
list all builds for your project
```
_See code: [src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/build/list.ts)_
_See code: [src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/build/list.ts)_
## `eas build:resign`
@@ -482,7 +480,7 @@ DESCRIPTION
re-sign a build archive
```
_See code: [src/commands/build/resign.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/build/resign.ts)_
_See code: [src/commands/build/resign.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/build/resign.ts)_
## `eas build:run`
@@ -508,7 +506,7 @@ DESCRIPTION
run simulator/emulator builds from eas-cli
```
_See code: [src/commands/build/run.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/build/run.ts)_
_See code: [src/commands/build/run.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/build/run.ts)_
## `eas build:submit`
@@ -557,7 +555,7 @@ DESCRIPTION
get the latest version from EAS servers
```
_See code: [src/commands/build/version/get.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/build/version/get.ts)_
_See code: [src/commands/build/version/get.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/build/version/get.ts)_
## `eas build:version:set`
@@ -576,7 +574,7 @@ DESCRIPTION
update version of an app
```
_See code: [src/commands/build/version/set.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/build/version/set.ts)_
_See code: [src/commands/build/version/set.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/build/version/set.ts)_
## `eas build:version:sync`
@@ -595,7 +593,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/v6.0.0/src/commands/build/version/sync.ts)_
_See code: [src/commands/build/version/sync.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/build/version/sync.ts)_
## `eas build:view [BUILD_ID]`
@@ -612,7 +610,7 @@ DESCRIPTION
view a build for your project
```
_See code: [src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/build/view.ts)_
_See code: [src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/build/view.ts)_
## `eas channel:create [NAME]`
@@ -633,7 +631,7 @@ DESCRIPTION
create a channel
```
_See code: [src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/channel/create.ts)_
_See code: [src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/channel/create.ts)_
## `eas channel:edit [NAME]`
@@ -655,7 +653,7 @@ DESCRIPTION
point a channel at a new branch
```
_See code: [src/commands/channel/edit.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/channel/edit.ts)_
_See code: [src/commands/channel/edit.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/channel/edit.ts)_
## `eas channel:list`
@@ -675,7 +673,7 @@ DESCRIPTION
list all channels
```
_See code: [src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/channel/list.ts)_
_See code: [src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/channel/list.ts)_
## `eas channel:rollout [CHANNEL]`
@@ -707,7 +705,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/v6.0.0/src/commands/channel/rollout.ts)_
_See code: [src/commands/channel/rollout.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/channel/rollout.ts)_
## `eas channel:view [NAME]`
@@ -730,7 +728,7 @@ DESCRIPTION
view a channel
```
_See code: [src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/channel/view.ts)_
_See code: [src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/channel/view.ts)_
## `eas config`
@@ -751,7 +749,7 @@ DESCRIPTION
display project configuration (app.json + eas.json)
```
_See code: [src/commands/config.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/config.ts)_
_See code: [src/commands/config.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/config.ts)_
## `eas credentials`
@@ -768,7 +766,7 @@ DESCRIPTION
manage credentials
```
_See code: [src/commands/credentials.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/credentials.ts)_
_See code: [src/commands/credentials.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/credentials.ts)_
## `eas device:create`
@@ -782,7 +780,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/v6.0.0/src/commands/device/create.ts)_
_See code: [src/commands/device/create.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/device/create.ts)_
## `eas device:delete`
@@ -802,7 +800,7 @@ DESCRIPTION
remove a registered device from your account
```
_See code: [src/commands/device/delete.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/device/delete.ts)_
_See code: [src/commands/device/delete.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/device/delete.ts)_
## `eas device:list`
@@ -823,7 +821,7 @@ DESCRIPTION
list all registered devices for your account
```
_See code: [src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/device/list.ts)_
_See code: [src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/device/list.ts)_
## `eas device:rename`
@@ -844,7 +842,7 @@ DESCRIPTION
rename a registered device
```
_See code: [src/commands/device/rename.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/device/rename.ts)_
_See code: [src/commands/device/rename.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/device/rename.ts)_
## `eas device:view [UDID]`
@@ -858,7 +856,7 @@ DESCRIPTION
view a device for your project
```
_See code: [src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/device/view.ts)_
_See code: [src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/device/view.ts)_
## `eas diagnostics`
@@ -872,11 +870,11 @@ DESCRIPTION
display environment info
```
_See code: [src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/diagnostics.ts)_
_See code: [src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/diagnostics.ts)_
## `eas help [COMMAND]`
Display help for eas.
display help for eas-cli
```
USAGE
@@ -889,10 +887,10 @@ FLAGS
-n, --nested-commands Include all nested commands in the output.
DESCRIPTION
Display help for eas.
display help for eas-cli
```
_See code: [@expo/plugin-help](https://github.com/expo/oclif-plugin-help/blob/v5.1.23/src/commands/help.ts)_
_See code: [@expo/plugin-help](https://github.com/expo/oclif-plugin-help/blob/v5.1.22/src/commands/help.ts)_
## `eas init`
@@ -960,7 +958,7 @@ DESCRIPTION
validate the local store configuration
```
_See code: [src/commands/metadata/lint.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/metadata/lint.ts)_
_See code: [src/commands/metadata/lint.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/metadata/lint.ts)_
## `eas metadata:pull`
@@ -977,7 +975,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/v6.0.0/src/commands/metadata/pull.ts)_
_See code: [src/commands/metadata/pull.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/metadata/pull.ts)_
## `eas metadata:push`
@@ -994,7 +992,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/v6.0.0/src/commands/metadata/push.ts)_
_See code: [src/commands/metadata/push.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/metadata/push.ts)_
## `eas open`
@@ -1008,7 +1006,7 @@ DESCRIPTION
open the project page in a web browser
```
_See code: [src/commands/open.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/open.ts)_
_See code: [src/commands/open.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/open.ts)_
## `eas project:info`
@@ -1022,7 +1020,7 @@ DESCRIPTION
information about the current project
```
_See code: [src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/project/info.ts)_
_See code: [src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/project/info.ts)_
## `eas project:init`
@@ -1044,7 +1042,7 @@ ALIASES
$ eas init
```
_See code: [src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/project/init.ts)_
_See code: [src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/project/init.ts)_
## `eas secret:create`
@@ -1067,7 +1065,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/v6.0.0/src/commands/secret/create.ts)_
_See code: [src/commands/secret/create.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/secret/create.ts)_
## `eas secret:delete`
@@ -1085,7 +1083,7 @@ DESCRIPTION
delete an environment secret by ID
```
_See code: [src/commands/secret/delete.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/secret/delete.ts)_
_See code: [src/commands/secret/delete.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/secret/delete.ts)_
## `eas secret:list`
@@ -1099,7 +1097,7 @@ DESCRIPTION
list environment secrets available for your current app
```
_See code: [src/commands/secret/list.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/secret/list.ts)_
_See code: [src/commands/secret/list.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/secret/list.ts)_
## `eas secret:push`
@@ -1119,7 +1117,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/v6.0.0/src/commands/secret/push.ts)_
_See code: [src/commands/secret/push.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/secret/push.ts)_
## `eas submit`
@@ -1149,7 +1147,7 @@ ALIASES
$ eas build:submit
```
_See code: [src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/submit.ts)_
_See code: [src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/submit.ts)_
## `eas update`
@@ -1183,7 +1181,7 @@ DESCRIPTION
publish an update group
```
_See code: [src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/update/index.ts)_
_See code: [src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/update/index.ts)_
## `eas update:configure`
@@ -1201,7 +1199,7 @@ DESCRIPTION
configure the project to support EAS Update
```
_See code: [src/commands/update/configure.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/update/configure.ts)_
_See code: [src/commands/update/configure.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/update/configure.ts)_
## `eas update:delete GROUPID`
@@ -1209,7 +1207,7 @@ delete all the updates in an update group
```
USAGE
$ eas update:delete GROUPID [--json --non-interactive]
$ eas update:delete [GROUPID] [--json --non-interactive]
ARGUMENTS
GROUPID The ID of an update group to delete.
@@ -1222,7 +1220,7 @@ DESCRIPTION
delete all the updates in an update group
```
_See code: [src/commands/update/delete.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/update/delete.ts)_
_See code: [src/commands/update/delete.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/update/delete.ts)_
## `eas update:list`
@@ -1244,7 +1242,7 @@ DESCRIPTION
view the recent updates
```
_See code: [src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/update/list.ts)_
_See code: [src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/update/list.ts)_
## `eas update:republish`
@@ -1271,7 +1269,7 @@ DESCRIPTION
roll back to an existing update
```
_See code: [src/commands/update/republish.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/update/republish.ts)_
_See code: [src/commands/update/republish.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/update/republish.ts)_
## `eas update:roll-back-to-embedded`
@@ -1298,7 +1296,7 @@ DESCRIPTION
roll back to the embedded update
```
_See code: [src/commands/update/roll-back-to-embedded.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/update/roll-back-to-embedded.ts)_
_See code: [src/commands/update/roll-back-to-embedded.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/update/roll-back-to-embedded.ts)_
## `eas update:rollback`
@@ -1317,7 +1315,7 @@ DESCRIPTION
roll back to an embedded update or an existing update
```
_See code: [src/commands/update/rollback.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/update/rollback.ts)_
_See code: [src/commands/update/rollback.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/update/rollback.ts)_
## `eas update:view GROUPID`
@@ -1325,7 +1323,7 @@ update group details
```
USAGE
$ eas update:view GROUPID [--json]
$ eas update:view [GROUPID] [--json]
ARGUMENTS
GROUPID The ID of an update group.
@@ -1337,7 +1335,7 @@ DESCRIPTION
update group details
```
_See code: [src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/update/view.ts)_
_See code: [src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/update/view.ts)_
## `eas webhook:create`
@@ -1358,7 +1356,7 @@ DESCRIPTION
create a webhook
```
_See code: [src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/webhook/create.ts)_
_See code: [src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/webhook/create.ts)_
## `eas webhook:delete [ID]`
@@ -1378,7 +1376,7 @@ DESCRIPTION
delete a webhook
```
_See code: [src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/webhook/delete.ts)_
_See code: [src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/webhook/delete.ts)_
## `eas webhook:list`
@@ -1396,7 +1394,7 @@ DESCRIPTION
list webhooks
```
_See code: [src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/webhook/list.ts)_
_See code: [src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/webhook/list.ts)_
## `eas webhook:update`
@@ -1418,7 +1416,7 @@ DESCRIPTION
update a webhook
```
_See code: [src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/webhook/update.ts)_
_See code: [src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/webhook/update.ts)_
## `eas webhook:view ID`
@@ -1426,7 +1424,7 @@ view a webhook
```
USAGE
$ eas webhook:view ID
$ eas webhook:view [ID]
ARGUMENTS
ID ID of the webhook to view
@@ -1435,7 +1433,7 @@ DESCRIPTION
view a webhook
```
_See code: [src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v6.0.0/src/commands/webhook/view.ts)_
_See code: [src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v5.9.1/packages/eas-cli/src/commands/webhook/view.ts)_
## `eas whoami`
+16 -118
View File
@@ -1213,22 +1213,6 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "isDisabled",
"description": null,
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Boolean",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "isSSOEnabled",
"description": "Whether this account has SSO enabled. Can be queried by all members.",
@@ -1733,18 +1717,6 @@
"description": null,
"fields": null,
"inputFields": [
{
"name": "searchTerm",
"description": null,
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "sortByField",
"description": null,
@@ -3145,33 +3117,6 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "AccountUsageEASJobsMetadata",
"description": null,
"fields": [
{
"name": "resourceClassDisplayName",
"description": null,
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "UNION",
"name": "AccountUsageMetadata",
@@ -3185,11 +3130,6 @@
"kind": "OBJECT",
"name": "AccountUsageEASBuildMetadata",
"ofType": null
},
{
"kind": "OBJECT",
"name": "AccountUsageEASJobsMetadata",
"ofType": null
}
]
},
@@ -15004,18 +14944,6 @@
"name": "BuildAnnotation",
"description": null,
"fields": [
{
"name": "authorUsername",
"description": null,
"args": [],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "buildPhase",
"description": null,
@@ -15088,18 +15016,6 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "regexFlags",
"description": null,
"args": [],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "regexString",
"description": null,
@@ -15200,18 +15116,6 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "regexFlags",
"description": null,
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "regexString",
"description": null,
@@ -16642,6 +16546,18 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "buildMode",
"description": null,
"type": {
"kind": "ENUM",
"name": "BuildMode",
"ofType": null
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "buildProfile",
"description": null,
@@ -21175,12 +21091,6 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "JOBS",
"description": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "UPDATES",
"description": null,
@@ -21222,12 +21132,6 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "RUN_TIME",
"description": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "UNIQUE_UPDATERS",
"description": null,
@@ -37481,14 +37385,14 @@
{
"name": "EAS_BUILD_PROJECT_SOURCES",
"description": null,
"isDeprecated": true,
"deprecationReason": "Use EAS_BUILD_GCS_PROJECT_SOURCES instead."
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "EAS_SUBMIT_APP_ARCHIVE",
"description": null,
"isDeprecated": true,
"deprecationReason": "Use EAS_SUBMIT_GCS_APP_ARCHIVE instead."
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "EAS_SUBMIT_GCS_APP_ARCHIVE",
@@ -37626,12 +37530,6 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "MINUTE",
"description": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "REQUEST",
"description": null,
+7
View File
@@ -0,0 +1,7 @@
module.exports = {
...require('../../jest/jest.config.js'),
rootDir: __dirname,
roots: ['src', '__mocks__'],
globalSetup: './jest/global-setup.ts',
setupFilesAfterEnv: ['./jest/setup-after-env.ts'],
};
-14
View File
@@ -1,14 +0,0 @@
import type { Config } from 'jest';
// eslint-disable-next-line import/no-relative-packages
import baseConfig from '../../jest/jest.config';
const config: Config = {
...baseConfig,
rootDir: __dirname,
roots: ['src', '__mocks__'],
globalSetup: './jest/global-setup.ts',
setupFilesAfterEnv: ['./jest/setup-after-env.ts'],
};
export default config;
+39 -42
View File
@@ -1,7 +1,7 @@
{
"name": "eas-cli",
"description": "EAS command line tool",
"version": "6.0.0",
"version": "5.9.1",
"author": "Expo <[email protected]>",
"bin": {
"eas": "./bin/run"
@@ -13,13 +13,12 @@
"@expo/config": "8.1.2",
"@expo/config-plugins": "7.2.4",
"@expo/config-types": "49.0.0",
"@expo/eas-build-job": "1.0.56",
"@expo/eas-json": "6.0.0",
"@expo/eas-build-job": "1.0.48",
"@expo/eas-json": "5.7.0",
"@expo/json-file": "8.2.37",
"@expo/multipart-body-parser": "1.1.0",
"@expo/osascript": "2.0.33",
"@expo/package-manager": "1.1.2",
"@expo/pkcs12": "0.0.8",
"@expo/plist": "0.0.20",
"@expo/plugin-help": "5.1.23",
"@expo/plugin-warn-if-update-available": "2.5.1",
@@ -38,27 +37,26 @@
"ajv-formats": "2.1.1",
"better-opn": "3.0.2",
"chalk": "4.1.2",
"cli-progress": "3.12.0",
"cli-progress": "3.11.2",
"dateformat": "4.6.3",
"dotenv": "16.3.1",
"dotenv": "16.0.3",
"env-paths": "2.2.0",
"envinfo": "7.11.0",
"envinfo": "7.8.1",
"fast-deep-equal": "3.1.3",
"fast-glob": "3.3.2",
"fast-glob": "3.2.12",
"figures": "3.2.0",
"form-data": "4.0.0",
"fs-extra": "11.2.0",
"fs-extra": "10.1.0",
"getenv": "1.0.0",
"gradle-to-js": "2.0.1",
"graphql": "16.8.1",
"graphql-tag": "2.12.6",
"https-proxy-agent": "5.0.1",
"ignore": "5.3.0",
"ignore": "5.2.4",
"indent-string": "4.0.0",
"jks-js": "1.1.0",
"joi": "17.11.0",
"jsonwebtoken": "9.0.0",
"keychain": "1.5.0",
"joi": "17.7.0",
"keychain": "1.3.0",
"log-symbols": "4.1.0",
"mime": "3.0.0",
"minimatch": "5.1.2",
@@ -68,59 +66,59 @@
"nullthrows": "1.1.1",
"ora": "5.1.0",
"pkg-dir": "4.2.0",
"pngjs": "7.0.0",
"pngjs": "6.0.0",
"promise-limit": "2.7.0",
"promise-retry": "2.0.1",
"prompts": "2.4.2",
"qrcode-terminal": "0.12.0",
"resolve-from": "5.0.0",
"semver": "7.5.4",
"semver": "7.5.2",
"slash": "3.0.0",
"tar": "6.2.0",
"tar": "6.1.13",
"terminal-link": "2.1.1",
"tslib": "2.6.2",
"turndown": "7.1.2",
"tslib": "2.4.1",
"turndown": "7.1.1",
"untildify": "4.0.0",
"uuid": "9.0.1",
"uuid": "9.0.0",
"wrap-ansi": "7.0.0"
},
"devDependencies": {
"@graphql-codegen/cli": "5.0.0",
"@graphql-codegen/introspection": "4.0.0",
"@graphql-codegen/typescript": "4.0.1",
"@graphql-codegen/typescript-operations": "4.0.1",
"@types/cli-progress": "3.11.5",
"@graphql-codegen/cli": "2.16.3",
"@graphql-codegen/introspection": "2.2.3",
"@graphql-codegen/typescript": "2.8.7",
"@graphql-codegen/typescript-operations": "2.5.12",
"@types/cli-progress": "3.11.0",
"@types/dateformat": "3.0.1",
"@types/envinfo": "7.8.3",
"@types/envinfo": "7.8.1",
"@types/express": "4.17.15",
"@types/fs-extra": "11.0.4",
"@types/fs-extra": "9.0.13",
"@types/getenv": "^1.0.0",
"@types/jsonwebtoken": "8.5.1",
"@types/mime": "3.0.1",
"@types/node": "^18.6.0",
"@types/node-fetch": "2.6.2",
"@types/node-forge": "1.3.1",
"@types/pngjs": "6.0.4",
"@types/pngjs": "6.0.1",
"@types/promise-retry": "1.1.3",
"@types/prompts": "2.4.2",
"@types/semver": "7.5.6",
"@types/tar": "6.1.10",
"@types/semver": "7.3.13",
"@types/tar": "6.1.3",
"@types/tough-cookie": "4.0.2",
"@types/uuid": "9.0.7",
"@types/uuid": "9.0.0",
"@types/wrap-ansi": "3.0.0",
"axios": "0.27.2",
"eslint-plugin-graphql": "4.0.0",
"express": "4.18.2",
"memfs": "3.4.13",
"mockdate": "3.0.5",
"nock": "13.4.0",
"nock": "13.2.9",
"rimraf": "3.0.2",
"ts-deepmerge": "6.2.0",
"ts-deepmerge": "4.0.0",
"ts-mockito": "2.6.1",
"ts-node": "10.9.2",
"typescript": "5.3.3"
"ts-node": "10.9.1",
"typescript": "4.9.4"
},
"engines": {
"node": ">=16.0.0"
"node": ">=14.0.0"
},
"files": [
"/bin",
@@ -206,20 +204,19 @@
"scripts": {
"postpack": "rimraf oclif.manifest.json",
"prepack": "yarn rebuild && node ./scripts/prepack.js",
"rebuild": "rimraf build && yarn build",
"rebuild": "rimraf build && yarn build-ci",
"pretarball-ci": "./scripts/pretarball-ci.sh",
"build": "tsc --project tsconfig.build.json",
"build-allow-unused": "tsc --project tsconfig.allowUnused.json",
"build-ci": "tsc --project tsconfig.build-ci.json",
"watch": "yarn build --watch --preserveWatchOutput",
"watch-allow-unused": "yarn build-allow-unused --watch --preserveWatchOutput",
"typecheck": "tsc",
"typecheck": "tsc --project tsconfig.build-ci.json",
"test": "jest",
"version": "yarn oclif readme && node scripts/patch-readme && git add README.md",
"generate-graphql-code": "graphql-codegen --config graphql-codegen.yml",
"clean": "rimraf dist build tmp node_modules yarn-error.log"
},
"volta": {
"node": "20.11.0",
"yarn": "1.22.21"
"node": "18.6.0",
"yarn": "1.22.19"
}
}
@@ -1,11 +1,11 @@
import { AppVersionSource, EasJson } from '@expo/eas-json';
import chalk from 'chalk';
import { getMockEasJson, mockCommandContext, mockProjectId, mockTestCommand } from './utils';
import BuildVersionGetView from '../../commands/build/version/get';
import { AppVersionQuery } from '../../graphql/queries/AppVersionQuery';
import Log from '../../log';
import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
import { getMockEasJson, mockCommandContext, mockProjectId, mockTestCommand } from './utils';
jest.mock('../../project/applicationIdentifier');
jest.mock('fs');
@@ -2,6 +2,12 @@ import { AppVersionSource, EasJson } from '@expo/eas-json';
import fs from 'fs-extra';
import path from 'path';
import BuildVersionSetView from '../../commands/build/version/set';
import { AppVersionMutation } from '../../graphql/mutations/AppVersionMutation';
import { AppQuery } from '../../graphql/queries/AppQuery';
import { AppVersionQuery } from '../../graphql/queries/AppVersionQuery';
import Log from '../../log';
import * as prompts from '../../prompts';
import {
getMockAppFragment,
getMockEasJson,
@@ -9,12 +15,6 @@ import {
mockProjectId,
mockTestCommand,
} from './utils';
import BuildVersionSetView from '../../commands/build/version/set';
import { AppVersionMutation } from '../../graphql/mutations/AppVersionMutation';
import { AppQuery } from '../../graphql/queries/AppQuery';
import { AppVersionQuery } from '../../graphql/queries/AppVersionQuery';
import Log from '../../log';
import * as prompts from '../../prompts';
jest.mock('../../project/applicationIdentifier');
jest.mock('../../graphql/queries/AppVersionQuery');
@@ -3,13 +3,6 @@ import { AppVersionSource, EasJson } from '@expo/eas-json';
import fs from 'fs-extra';
import path from 'path';
import {
getMockAppFragment,
getMockEasJson,
mockCommandContext,
mockProjectId,
mockTestCommand,
} from './utils';
import { updateNativeVersionsAsync as updateAndroidNativeVersionsAsync } from '../../build/android/version';
import { updateNativeVersionsAsync as updateIosNativeVersionsAsync } from '../../build/ios/version';
import BuildVersionSyncView from '../../commands/build/version/sync';
@@ -21,6 +14,13 @@ import { getAppBuildGradleAsync } from '../../project/android/gradleUtils';
import { resolveTargetsAsync } from '../../project/ios/target';
import { resolveWorkflowAsync } from '../../project/workflow';
import * as prompts from '../../prompts';
import {
getMockAppFragment,
getMockEasJson,
mockCommandContext,
mockProjectId,
mockTestCommand,
} from './utils';
jest.mock('../../build/android/version');
jest.mock('../../build/ios/version');
@@ -59,7 +59,7 @@ export interface LocalProjectContext {
export function mockCommandContext<
C extends {
[name: string]: any;
} = object,
} = object
>(
commandClass: { contextDefinition: ContextInput<C> },
overrides: {
+1 -1
View File
@@ -1,7 +1,6 @@
import chalk from 'chalk';
import gql from 'graphql-tag';
import { BranchNotFoundError } from './utils';
import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
import { PaginatedQueryOptions } from '../commandUtils/pagination';
import { withErrorHandlingAsync } from '../graphql/client';
@@ -20,6 +19,7 @@ import {
paginatedQueryWithConfirmPromptAsync,
paginatedQueryWithSelectPromptAsync,
} from '../utils/queries';
import { BranchNotFoundError } from './utils';
export const BRANCHES_LIMIT = 50;
@@ -1,96 +0,0 @@
import { instance, mock } from 'ts-mockito';
import { v4 as uuid } from 'uuid';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
import { selectBuildToDeleteAsync } from '../../commands/build/delete';
import {
AppPlatform,
BuildFragment,
BuildPriority,
BuildResourceClass,
BuildStatus,
} from '../../graphql/generated';
import { BuildQuery } from '../../graphql/queries/BuildQuery';
import { confirmAsync, selectAsync } from '../../prompts';
jest.mock('../../ora', () => ({
ora: jest.fn().mockImplementation(() => ({
start: jest.fn().mockImplementation(() => ({
stop: jest.fn(),
fail: jest.fn(),
})),
})),
}));
jest.mock('../../prompts', () => {
return {
selectAsync: jest.fn(),
confirmAsync: jest.fn(),
};
});
jest.mock('../../graphql/queries/BuildQuery', () => {
const actual = jest.requireActual('../../graphql/queries/BuildQuery');
return {
BuildQuery: {
...actual.BuildQuery,
viewBuildsOnAppAsync: jest.fn(),
},
};
});
describe(selectBuildToDeleteAsync.name, () => {
const selectedBuildId = uuid();
const projectId = uuid();
beforeEach(() => {
jest
.mocked(BuildQuery.viewBuildsOnAppAsync)
.mockImplementation(async () => [
createMockBuildFragment({ projectId, buildId: selectedBuildId }),
]);
});
it('does not return build id when confirmation is rejected', async () => {
const graphqlClient = instance(mock<ExpoGraphqlClient>());
jest.mocked(confirmAsync).mockResolvedValueOnce(false);
expect(selectBuildToDeleteAsync(graphqlClient, projectId, 'blah')).resolves.toEqual(null);
});
it('returns build id when confirmation is confirmed', async () => {
const graphqlClient = instance(mock<ExpoGraphqlClient>());
jest.mocked(selectAsync).mockResolvedValueOnce(selectedBuildId);
jest.mocked(confirmAsync).mockResolvedValueOnce(true);
expect(selectBuildToDeleteAsync(graphqlClient, projectId, 'blah')).resolves.toEqual(
selectedBuildId
);
});
});
function createMockBuildFragment({
projectId,
buildId,
}: {
projectId: string;
buildId?: string;
}): BuildFragment {
return {
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
platform: AppPlatform.Android,
id: buildId ?? uuid(),
priority: BuildPriority.Normal,
project: {
__typename: 'App',
slug: 'test-project',
id: projectId,
name: 'test-project',
ownerAccount: {
__typename: 'Account',
id: uuid(),
name: 'test-account',
},
},
status: BuildStatus.InQueue,
resourceClass: BuildResourceClass.AndroidMedium,
};
}
+4 -4
View File
@@ -3,10 +3,6 @@ import { AppVersionSource } from '@expo/eas-json';
import chalk from 'chalk';
import nullthrows from 'nullthrows';
import { transformJob } from './graphql';
import { prepareJobAsync } from './prepareJob';
import { syncProjectConfigurationAsync } from './syncProjectConfiguration';
import { resolveRemoteVersionCodeAsync } from './version';
import AndroidCredentialsProvider, {
AndroidCredentials,
} from '../../credentials/android/AndroidCredentialsProvider';
@@ -33,6 +29,10 @@ import {
checkNodeEnvVariable,
validatePNGsForManagedProjectAsync,
} from '../validate';
import { transformJob } from './graphql';
import { prepareJobAsync } from './prepareJob';
import { syncProjectConfigurationAsync } from './syncProjectConfiguration';
import { resolveRemoteVersionCodeAsync } from './version';
export async function createAndroidContextAsync(
ctx: CommonContext<Platform.ANDROID>
@@ -6,13 +6,13 @@ import chalk from 'chalk';
import fs from 'fs-extra';
import path from 'path';
import { BumpStrategy, bumpVersionAsync, bumpVersionInAppJsonAsync } from './version';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
import Log from '../../log';
import { isExpoUpdatesInstalled } from '../../project/projectUtils';
import { resolveWorkflowAsync } from '../../project/workflow';
import { syncUpdatesConfigurationAsync } from '../../update/android/UpdatesModule';
import { Client } from '../../vcs/vcs';
import { BumpStrategy, bumpVersionAsync, bumpVersionInAppJsonAsync } from './version';
export async function syncProjectConfigurationAsync(
graphqlClient: ExpoGraphqlClient,
+21 -21
View File
@@ -7,26 +7,6 @@ import fs from 'fs-extra';
import { GraphQLError } from 'graphql/error';
import nullthrows from 'nullthrows';
import { BuildContext } from './context';
import {
EasBuildDownForMaintenanceError,
EasBuildFreeTierDisabledAndroidError,
EasBuildFreeTierDisabledError,
EasBuildFreeTierDisabledIOSError,
EasBuildFreeTierIosLimitExceededError,
EasBuildFreeTierLimitExceededError,
EasBuildLegacyResourceClassNotAvailableError,
EasBuildProjectArchiveUploadError,
EasBuildResourceClassNotAvailableInFreeTierError,
EasBuildTooManyPendingBuildsError,
RequestValidationError,
TurtleDeprecatedJobFormatError,
} from './errors';
import { transformMetadata } from './graphql';
import { LocalBuildMode, runLocalBuildAsync } from './local';
import { collectMetadataAsync } from './metadata';
import { printDeprecationWarnings } from './utils/printBuildInfo';
import { makeProjectTarballAsync, reviewAndCommitChangesAsync } from './utils/repository';
import { BuildEvent } from '../analytics/AnalyticsManager';
import { withAnalyticsAsync } from '../analytics/common';
import { getExpoWebsiteBaseUrl } from '../api';
@@ -54,6 +34,26 @@ import { formatBytes } from '../utils/files';
import { printJsonOnlyOutput } from '../utils/json';
import { createProgressTracker } from '../utils/progress';
import { sleepAsync } from '../utils/promise';
import { BuildContext } from './context';
import {
EasBuildDownForMaintenanceError,
EasBuildFreeTierDisabledAndroidError,
EasBuildFreeTierDisabledError,
EasBuildFreeTierDisabledIOSError,
EasBuildFreeTierIosLimitExceededError,
EasBuildFreeTierLimitExceededError,
EasBuildLegacyResourceClassNotAvailableError,
EasBuildProjectArchiveUploadError,
EasBuildResourceClassNotAvailableInFreeTierError,
EasBuildTooManyPendingBuildsError,
RequestValidationError,
TurtleDeprecatedJobFormatError,
} from './errors';
import { transformMetadata } from './graphql';
import { LocalBuildMode, runLocalBuildAsync } from './local';
import { collectMetadataAsync } from './metadata';
import { printDeprecationWarnings } from './utils/printBuildInfo';
import { makeProjectTarballAsync, reviewAndCommitChangesAsync } from './utils/repository';
export interface CredentialsResult<Credentials> {
source: CredentialsSource.LOCAL | CredentialsSource.REMOTE;
@@ -97,7 +97,7 @@ function resolveBuildParamsInput<T extends Platform>(
export async function prepareBuildRequestForPlatformAsync<
TPlatform extends Platform,
Credentials,
TJob extends Job,
TJob extends Job
>(builder: Builder<TPlatform, Credentials, TJob>): Promise<BuildRequestSender> {
const { ctx } = builder;
const credentialsResult = await withAnalyticsAsync(
+38 -3
View File
@@ -1,11 +1,13 @@
import { Platform, Workflow } from '@expo/eas-build-job';
import { EasJson, EasJsonAccessor } from '@expo/eas-json';
import chalk from 'chalk';
import fs from 'fs-extra';
import { maybeBailOnRepoStatusAsync, reviewAndCommitChangesAsync } from './utils/repository';
import Log, { learnMore } from '../log';
import { resolveWorkflowAsync } from '../project/workflow';
import { easCliVersion } from '../utils/easCli';
import { Client } from '../vcs/vcs';
import { maybeBailOnRepoStatusAsync, reviewAndCommitChangesAsync } from './utils/repository';
interface ConfigureParams {
projectDir: string;
@@ -52,7 +54,7 @@ async function configureAsync({
}
}
const EAS_JSON_DEFAULT: EasJson = {
const EAS_JSON_MANAGED_DEFAULT: EasJson = {
cli: {
version: `>= ${easCliVersion}`,
},
@@ -71,10 +73,43 @@ const EAS_JSON_DEFAULT: EasJson = {
},
};
const EAS_JSON_BARE_DEFAULT: EasJson = {
cli: {
version: `>= ${easCliVersion}`,
},
build: {
development: {
distribution: 'internal',
android: {
gradleCommand: ':app:assembleDebug',
},
ios: {
buildConfiguration: 'Debug',
},
},
preview: {
distribution: 'internal',
},
production: {},
},
submit: {
production: {},
},
};
async function createEasJsonAsync(projectDir: string, vcsClient: Client): Promise<void> {
const easJsonPath = EasJsonAccessor.formatEasJsonPath(projectDir);
await fs.writeFile(easJsonPath, `${JSON.stringify(EAS_JSON_DEFAULT, null, 2)}\n`);
const hasAndroidNativeProject =
(await resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient)) === Workflow.GENERIC;
const hasIosNativeProject =
(await resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient)) === Workflow.GENERIC;
const easJson =
hasAndroidNativeProject || hasIosNativeProject
? EAS_JSON_BARE_DEFAULT
: EAS_JSON_MANAGED_DEFAULT;
await fs.writeFile(easJsonPath, `${JSON.stringify(easJson, null, 2)}\n`);
await vcsClient.trackFileAsync(easJsonPath);
Log.withTick(
`Generated ${chalk.bold('eas.json')}. ${learnMore(
+1 -1
View File
@@ -3,7 +3,6 @@ import { Platform, Workflow } from '@expo/eas-build-job';
import { BuildProfile, EasJson } from '@expo/eas-json';
import { NodePackageManager } from '@expo/package-manager';
import { LocalBuildOptions } from './local';
import { Analytics, AnalyticsEventProperties } from '../analytics/AnalyticsManager';
import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
import { CredentialsContext } from '../credentials/context';
@@ -14,6 +13,7 @@ import { CustomBuildConfigMetadata } from '../project/customBuildConfig';
import { XcodeBuildContext } from '../project/ios/scheme';
import { Actor } from '../user/User';
import { Client } from '../vcs/vcs';
import { LocalBuildOptions } from './local';
export type CommonContext<T extends Platform> = Omit<BuildContext<T>, 'android' | 'ios'>;
+5 -5
View File
@@ -6,11 +6,6 @@ import getenv from 'getenv';
import resolveFrom from 'resolve-from';
import { v4 as uuidv4 } from 'uuid';
import { createAndroidContextAsync } from './android/build';
import { BuildContext, CommonContext } from './context';
import { createIosContextAsync } from './ios/build';
import { LocalBuildOptions } from './local';
import { resolveBuildResourceClassAsync } from './utils/resourceClass';
import { Analytics, AnalyticsEventProperties, BuildEvent } from '../analytics/AnalyticsManager';
import { DynamicConfigContextFn } from '../commandUtils/context/DynamicProjectConfigContextField';
import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
@@ -20,6 +15,11 @@ import { getOwnerAccountForProjectIdAsync } from '../project/projectUtils';
import { resolveWorkflowAsync } from '../project/workflow';
import { Actor } from '../user/User';
import { Client } from '../vcs/vcs';
import { createAndroidContextAsync } from './android/build';
import { BuildContext, CommonContext } from './context';
import { createIosContextAsync } from './ios/build';
import { LocalBuildOptions } from './local';
import { resolveBuildResourceClassAsync } from './utils/resourceClass';
export async function createBuildContextAsync<T extends Platform>({
buildProfileName,
+19 -14
View File
@@ -1,27 +1,30 @@
import {
ArchiveSource,
ArchiveSourceType,
BuildMode,
BuildTrigger,
Metadata,
Workflow,
} from '@expo/eas-build-job';
import assert from 'assert';
import {
BuildCredentialsSource,
BuildIosEnterpriseProvisioning,
BuildMetadataInput,
BuildMode,
BuildWorkflow,
DistributionType,
BuildMode as GraphQLBuildMode,
BuildTrigger as GraphQLBuildTrigger,
ProjectArchiveSourceInput,
ProjectArchiveSourceType,
} from '../graphql/generated';
export function transformProjectArchive(archiveSource: ArchiveSource): ProjectArchiveSourceInput {
if (archiveSource.type === ArchiveSourceType.GCS) {
if (archiveSource.type === ArchiveSourceType.S3) {
return {
type: ProjectArchiveSourceType.S3,
bucketKey: archiveSource.bucketKey,
};
} else if (archiveSource.type === ArchiveSourceType.GCS) {
return {
type: ProjectArchiveSourceType.Gcs,
bucketKey: archiveSource.bucketKey,
@@ -39,6 +42,7 @@ export function transformProjectArchive(archiveSource: ArchiveSource): ProjectAr
export function transformMetadata(metadata: Metadata): BuildMetadataInput {
return {
...metadata,
buildMode: metadata.buildMode && transformBuildMode(metadata.buildMode),
credentialsSource:
metadata.credentialsSource && transformCredentialsSource(metadata.credentialsSource),
distribution: metadata.distribution && transformDistribution(metadata.distribution),
@@ -87,16 +91,17 @@ export function transformIosEnterpriseProvisioning(
}
}
const buildModeToGraphQLBuildMode: Record<BuildMode, GraphQLBuildMode> = {
[BuildMode.BUILD]: GraphQLBuildMode.Build,
[BuildMode.CUSTOM]: GraphQLBuildMode.Custom,
[BuildMode.RESIGN]: GraphQLBuildMode.Resign,
};
export function transformBuildMode(buildMode: BuildMode): GraphQLBuildMode {
const graphQLBuildMode = buildModeToGraphQLBuildMode[buildMode];
assert(graphQLBuildMode, `Unsupported build mode: ${buildMode}`);
return graphQLBuildMode;
// TODO: check what in metadata
export function transformBuildMode(buildMode: string): BuildMode {
if (buildMode === 'build') {
return BuildMode.Build;
} else if (buildMode === 'resign') {
return BuildMode.Resign;
} else if (buildMode === 'custom') {
return BuildMode.Custom;
} else {
throw new Error(`Unsupported build mode: ${buildMode}`);
}
}
export function transformBuildTrigger(buildTrigger: BuildTrigger): GraphQLBuildTrigger {
@@ -62,7 +62,7 @@ describe(evaluateTemplateString, () => {
// bare workflow
describe(bumpVersionAsync, () => {
beforeEach(() => {
getPbxproj.mockImplementation((): any => {});
getPbxproj.mockImplementation(() => ({} as any));
});
afterEach(() => {
getXCBuildConfigurationFromPbxproj.mockReset();
@@ -76,7 +76,7 @@ describe(bumpVersionAsync, () => {
buildSettings: {
INFOPLIST_FILE: 'myproject/Info.plist',
},
}) as XCBuildConfiguration
} as XCBuildConfiguration)
);
await bumpVersionAsync({
bumpStrategy: BumpStrategy.BUILD_NUMBER,
@@ -112,7 +112,7 @@ describe(bumpVersionAsync, () => {
buildSettings: {
INFOPLIST_FILE: '$(SRCROOT)/myproject/Info2.plist',
},
}) as XCBuildConfiguration
} as XCBuildConfiguration)
);
await bumpVersionAsync({
bumpStrategy: BumpStrategy.BUILD_NUMBER,
@@ -147,7 +147,7 @@ describe(bumpVersionAsync, () => {
buildSettings: {
INFOPLIST_FILE: 'myproject/Info.plist',
},
}) as XCBuildConfiguration
} as XCBuildConfiguration)
);
await bumpVersionAsync({
bumpStrategy: BumpStrategy.APP_VERSION,
@@ -182,7 +182,7 @@ describe(bumpVersionAsync, () => {
buildSettings: {
INFOPLIST_FILE: 'myproject/Info.plist',
},
}) as XCBuildConfiguration
} as XCBuildConfiguration)
);
await bumpVersionAsync({
bumpStrategy: BumpStrategy.NOOP,
+5 -5
View File
@@ -1,11 +1,6 @@
import { Ios, Job, Metadata, Platform, Workflow } from '@expo/eas-build-job';
import { AppVersionSource } from '@expo/eas-json';
import { ensureIosCredentialsAsync } from './credentials';
import { transformJob } from './graphql';
import { prepareJobAsync } from './prepareJob';
import { syncProjectConfigurationAsync } from './syncProjectConfiguration';
import { resolveRemoteBuildNumberAsync } from './version';
import { IosCredentials } from '../../credentials/ios/types';
import { BuildParamsInput } from '../../graphql/generated';
import { BuildMutation, BuildResult } from '../../graphql/mutations/BuildMutation';
@@ -20,6 +15,11 @@ import {
checkNodeEnvVariable,
validatePNGsForManagedProjectAsync,
} from '../validate';
import { ensureIosCredentialsAsync } from './credentials';
import { transformJob } from './graphql';
import { prepareJobAsync } from './prepareJob';
import { syncProjectConfigurationAsync } from './syncProjectConfiguration';
import { resolveRemoteBuildNumberAsync } from './version';
export async function createIosContextAsync(
ctx: CommonContext<Platform.IOS>
@@ -2,13 +2,13 @@ import { ExpoConfig } from '@expo/config';
import { Platform, Workflow } from '@expo/eas-build-job';
import { IosVersionAutoIncrement } from '@expo/eas-json';
import { BumpStrategy, bumpVersionAsync, bumpVersionInAppJsonAsync } from './version';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
import { Target } from '../../credentials/ios/types';
import { isExpoUpdatesInstalled } from '../../project/projectUtils';
import { resolveWorkflowAsync } from '../../project/workflow';
import { syncUpdatesConfigurationAsync } from '../../update/ios/UpdatesModule';
import { Client } from '../../vcs/vcs';
import { BumpStrategy, bumpVersionAsync, bumpVersionInAppJsonAsync } from './version';
export async function syncProjectConfigurationAsync(
graphqlClient: ExpoGraphqlClient,
+1 -1
View File
@@ -6,7 +6,7 @@ import semver from 'semver';
import { ora } from '../ora';
const PLUGIN_PACKAGE_NAME = 'eas-cli-local-build-plugin';
const PLUGIN_PACKAGE_VERSION = '1.0.56';
const PLUGIN_PACKAGE_VERSION = '1.0.49';
export enum LocalBuildMode {
/**
+6 -5
View File
@@ -1,13 +1,9 @@
import { Updates } from '@expo/config-plugins';
import { Metadata, Platform, sanitizeMetadata } from '@expo/eas-build-job';
import { BuildMode, Metadata, Platform, sanitizeMetadata } from '@expo/eas-build-job';
import { IosEnterpriseProvisioning } from '@expo/eas-json';
import fs from 'fs-extra';
import resolveFrom from 'resolve-from';
import { maybeResolveVersionsAsync as maybeResolveAndroidVersionsAsync } from './android/version';
import { BuildContext } from './context';
import { maybeResolveVersionsAsync as maybeResolveIosVersionsAsync } from './ios/version';
import { LocalBuildMode } from './local';
import Log from '../log';
import { getUsername, isExpoUpdatesInstalled } from '../project/projectUtils';
import {
@@ -19,6 +15,10 @@ import {
readReleaseChannelSafelyAsync as readIosReleaseChannelSafelyAsync,
} from '../update/ios/UpdatesModule';
import { easCliVersion } from '../utils/easCli';
import { maybeResolveVersionsAsync as maybeResolveAndroidVersionsAsync } from './android/version';
import { BuildContext } from './context';
import { maybeResolveVersionsAsync as maybeResolveIosVersionsAsync } from './ios/version';
import { LocalBuildMode } from './local';
export async function collectMetadataAsync<T extends Platform>(
ctx: BuildContext<T>
@@ -59,6 +59,7 @@ export async function collectMetadataAsync<T extends Platform>(
}),
runWithNoWaitFlag: ctx.noWait,
runFromCI: ctx.runFromCI,
buildMode: ctx.buildProfile.config ? BuildMode.CUSTOM : BuildMode.BUILD,
customWorkflowName: ctx.customBuildConfigMetadata?.workflowName,
developmentClient: ctx.developmentClient,
requiredPackageManager: ctx.requiredPackageManager ?? undefined,
+1 -1
View File
@@ -1,6 +1,5 @@
import chalk from 'chalk';
import { formatGraphQLBuild } from './utils/formatBuild';
import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
import { PaginatedQueryOptions } from '../commandUtils/pagination';
import { AppPlatform, BuildFilter, BuildFragment } from '../graphql/generated';
@@ -12,6 +11,7 @@ import {
paginatedQueryWithConfirmPromptAsync,
paginatedQueryWithSelectPromptAsync,
} from '../utils/queries';
import { formatGraphQLBuild } from './utils/formatBuild';
export const BUILDS_LIMIT = 50;
+10 -10
View File
@@ -13,16 +13,6 @@ import assert from 'assert';
import chalk from 'chalk';
import nullthrows from 'nullthrows';
import { prepareAndroidBuildAsync } from './android/build';
import { BuildRequestSender, MaybeBuildFragment, waitForBuildEndAsync } from './build';
import { ensureProjectConfiguredAsync } from './configure';
import { BuildContext } from './context';
import { createBuildContextAsync } from './createContext';
import { prepareIosBuildAsync } from './ios/build';
import { LocalBuildOptions } from './local';
import { ensureExpoDevClientInstalledForDevClientBuildsAsync } from './utils/devClient';
import { printBuildResults, printLogsUrls } from './utils/printBuildInfo';
import { ensureRepoIsCleanAsync } from './utils/repository';
import { Analytics } from '../analytics/AnalyticsManager';
import { createAndLinkChannelAsync, doesChannelExistAsync } from '../channel/queries';
import { DynamicConfigContextFn } from '../commandUtils/context/DynamicProjectConfigContextField';
@@ -77,6 +67,16 @@ import { truthy } from '../utils/expodash/filter';
import { printJsonOnlyOutput } from '../utils/json';
import { ProfileData, getProfilesAsync } from '../utils/profiles';
import { Client } from '../vcs/vcs';
import { prepareAndroidBuildAsync } from './android/build';
import { BuildRequestSender, MaybeBuildFragment, waitForBuildEndAsync } from './build';
import { ensureProjectConfiguredAsync } from './configure';
import { BuildContext } from './context';
import { createBuildContextAsync } from './createContext';
import { prepareIosBuildAsync } from './ios/build';
import { LocalBuildOptions } from './local';
import { ensureExpoDevClientInstalledForDevClientBuildsAsync } from './utils/devClient';
import { printBuildResults, printLogsUrls } from './utils/printBuildInfo';
import { ensureRepoIsCleanAsync } from './utils/repository';
let metroConfigValidated = false;
let sdkVersionChecked = false;
@@ -3,7 +3,6 @@ import { Errors } from '@oclif/core';
import chalk from 'chalk';
import resolveFrom from 'resolve-from';
import { reviewAndCommitChangesAsync } from './repository';
import { toAppPlatform } from '../../graphql/types/AppPlatform';
import Log, { learnMore } from '../../log';
import { appPlatformDisplayNames } from '../../platform';
@@ -12,6 +11,7 @@ import { confirmAsync } from '../../prompts';
import { expoCommandAsync } from '../../utils/expoCli';
import { ProfileData } from '../../utils/profiles';
import { Client } from '../../vcs/vcs';
import { reviewAndCommitChangesAsync } from './repository';
export async function ensureExpoDevClientInstalledForDevClientBuildsAsync({
projectDir,
@@ -1,6 +1,5 @@
import chalk from 'chalk';
import { getBuildLogsUrl } from './url';
import {
AppPlatform,
BuildFragment,
@@ -8,6 +7,7 @@ import {
} from '../../graphql/generated';
import { appPlatformDisplayNames } from '../../platform';
import formatFields from '../../utils/formatFields';
import { getBuildLogsUrl } from './url';
export function formatGraphQLBuild(build: BuildFragment): string {
const actor = getActorName(build);
@@ -2,7 +2,6 @@ import assert from 'assert';
import indentString from 'indent-string';
import qrcodeTerminal from 'qrcode-terminal';
import { getBuildLogsUrl, getInternalDistributionInstallUrl } from './url';
import {
AppPlatform,
BuildError,
@@ -14,6 +13,7 @@ import {
} from '../../graphql/generated';
import Log, { learnMore, link } from '../../log';
import { appPlatformDisplayNames, appPlatformEmojis } from '../../platform';
import { getBuildLogsUrl, getInternalDistributionInstallUrl } from './url';
function terminalLinkFallback(url: string, text: string): string {
return `${text} (${url})`;
+1 -1
View File
@@ -3,9 +3,9 @@ import chalk from 'chalk';
import nullthrows from 'nullthrows';
import semver from 'semver';
import { updateAppJsonConfigAsync } from './appJson';
import Log from '../../log';
import { promptAsync } from '../../prompts';
import { updateAppJsonConfigAsync } from './appJson';
export function ensureStaticConfigExists(projectDir: string): void {
const paths = getConfigFilePaths(projectDir);
+1 -1
View File
@@ -4,9 +4,9 @@ import fs from 'fs-extra';
import path from 'path';
import semver from 'semver';
import { CommonContext } from './context';
import Log, { learnMore } from '../log';
import { isPNGAsync } from '../utils/image';
import { CommonContext } from './context';
export function checkNodeEnvVariable(ctx: CommonContext<Platform>): void {
if (ctx.buildProfile.env?.NODE_ENV === 'production') {
@@ -1,4 +1,3 @@
import { testChannelBasicInfo } from './branch-mapping-fixtures';
import {
emptyBranchMapping,
rolloutBranchMapping,
@@ -14,6 +13,7 @@ import {
isAlwaysTrueBranchMapping,
isEmptyBranchMapping,
} from '../branch-mapping';
import { testChannelBasicInfo } from './branch-mapping-fixtures';
describe(assertVersion, () => {
it('throws if the branch mapping is not the correct version', () => {
@@ -1,8 +1,8 @@
import { format } from '@expo/timeago.js';
import { testChannelObject, testUpdateBranch1, testUpdateBranch2 } from './fixtures';
import { getAlwaysTrueBranchMapping, getEmptyBranchMapping } from '../branch-mapping';
import { getDescriptionByBranchId } from '../print-utils';
import { testChannelObject, testUpdateBranch1, testUpdateBranch2 } from './fixtures';
describe(getDescriptionByBranchId, () => {
it('should get descriptions for multiple branches with multiple update groups', () => {
@@ -1,5 +1,5 @@
import { channelInfoWithBranches, testBasicBranchInfo1 } from './branch-mapping-fixtures';
import { getUpdateBranch } from '../utils';
import { channelInfoWithBranches, testBasicBranchInfo1 } from './branch-mapping-fixtures';
describe(getUpdateBranch, () => {
it('gets the update branch', () => {
@@ -41,7 +41,7 @@ export type AlwaysTrueBranchMapping = {
{
branchId: string;
branchMappingLogic: BranchMappingAlwaysTrue;
},
}
];
};
+26 -29
View File
@@ -1,6 +1,5 @@
import chalk from 'chalk';
import { assertVersion, hasEmptyBranchMap, hasStandardBranchMap } from './branch-mapping';
import { UpdateChannelObject } from '../graphql/queries/ChannelQuery';
import Log from '../log';
import { getRollout, isRollout } from '../rollout/branch-mapping';
@@ -9,6 +8,7 @@ import {
formatBranch,
getUpdateGroupDescriptionsWithBranch,
} from '../update/utils';
import { assertVersion, hasEmptyBranchMap, hasStandardBranchMap } from './branch-mapping';
/**
* Log all the branches associated with the channel and their most recent update group
@@ -38,34 +38,31 @@ export function logChannelDetails(channel: UpdateChannelObject): void {
export function getDescriptionByBranchId(
channel: UpdateChannelObject
): Record<string, FormattedBranchDescription> {
return channel.updateBranches.reduce(
(acc, branch) => {
const maybeRollout = isRollout(channel) ? getRollout(channel) : null;
let maybePercentOnBranch: number | undefined = undefined;
if (maybeRollout) {
maybePercentOnBranch =
maybeRollout.rolledOutBranchId === branch.id
? maybeRollout.percentRolledOut
: 100 - maybeRollout.percentRolledOut;
}
return channel.updateBranches.reduce((acc, branch) => {
const maybeRollout = isRollout(channel) ? getRollout(channel) : null;
let maybePercentOnBranch: number | undefined = undefined;
if (maybeRollout) {
maybePercentOnBranch =
maybeRollout.rolledOutBranchId === branch.id
? maybeRollout.percentRolledOut
: 100 - maybeRollout.percentRolledOut;
}
if (branch.updateGroups.length === 0) {
acc[branch.id] = { branch: branch.name, branchRolloutPercentage: maybePercentOnBranch };
return acc;
}
const updateGroupsWithBranchDescriptions = getUpdateGroupDescriptionsWithBranch(
branch.updateGroups
);
// display the most recent update group
const updateGroupWithBranchDescription = updateGroupsWithBranchDescriptions[0];
const { branch: branchName, ...updateGroup } = updateGroupWithBranchDescription;
acc[branch.id] = {
branch: branchName,
branchRolloutPercentage: maybePercentOnBranch,
update: updateGroup,
};
if (branch.updateGroups.length === 0) {
acc[branch.id] = { branch: branch.name, branchRolloutPercentage: maybePercentOnBranch };
return acc;
},
{} as Record<string, FormattedBranchDescription>
);
}
const updateGroupsWithBranchDescriptions = getUpdateGroupDescriptionsWithBranch(
branch.updateGroups
);
// display the most recent update group
const updateGroupWithBranchDescription = updateGroupsWithBranchDescriptions[0];
const { branch: branchName, ...updateGroup } = updateGroupWithBranchDescription;
acc[branch.id] = {
branch: branchName,
branchRolloutPercentage: maybePercentOnBranch,
update: updateGroup,
};
return acc;
}, {} as Record<string, FormattedBranchDescription>);
}
+3 -3
View File
@@ -2,9 +2,6 @@ import chalk from 'chalk';
import { print } from 'graphql';
import gql from 'graphql-tag';
import { ChannelNotFoundError } from './errors';
import { logChannelDetails } from './print-utils';
import { ChannelBasicInfo } from './utils';
import { createUpdateBranchOnAppAsync } from '../branch/queries';
import { BranchNotFoundError } from '../branch/utils';
import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
@@ -27,6 +24,9 @@ import {
paginatedQueryWithConfirmPromptAsync,
paginatedQueryWithSelectPromptAsync,
} from '../utils/queries';
import { ChannelNotFoundError } from './errors';
import { logChannelDetails } from './print-utils';
import { ChannelBasicInfo } from './utils';
export const CHANNELS_LIMIT = 25;
+10 -10
View File
@@ -3,6 +3,13 @@ import { CombinedError } from '@urql/core';
import { GraphQLError } from 'graphql/error';
import nullthrows from 'nullthrows';
import {
AnalyticsWithOrchestration,
CommandEvent,
createAnalyticsAsync,
} from '../analytics/AnalyticsManager';
import Log from '../log';
import SessionManager from '../user/SessionManager';
import AnalyticsContextField from './context/AnalyticsContextField';
import ContextField from './context/ContextField';
import {
@@ -17,18 +24,11 @@ import ProjectDirContextField from './context/ProjectDirContextField';
import SessionManagementContextField from './context/SessionManagementContextField';
import VcsClientContextField from './context/VcsClientContextField';
import { EasCommandError } from './errors';
import {
AnalyticsWithOrchestration,
CommandEvent,
createAnalyticsAsync,
} from '../analytics/AnalyticsManager';
import Log from '../log';
import SessionManager from '../user/SessionManager';
export type ContextInput<
T extends {
[name: string]: any;
} = object,
} = object
> = {
[P in keyof T]: ContextField<T[P]>;
};
@@ -36,7 +36,7 @@ export type ContextInput<
export type ContextOutput<
T extends {
[name: string]: any;
} = object,
} = object
> = {
[P in keyof T]: T[P];
};
@@ -136,7 +136,7 @@ export default abstract class EasCommand extends Command {
protected async getContextAsync<
C extends {
[name: string]: any;
} = object,
} = object
>(
commandClass: { contextDefinition: ContextInput<C> },
{ nonInteractive }: { nonInteractive: boolean }
@@ -1,99 +0,0 @@
import chalk from 'chalk';
import { ExpoGraphqlClient } from './context/contextUtils/createGraphqlClient';
import {
AppPlatform,
Build,
BuildFilter,
BuildFragment,
BuildStatus,
InputMaybe,
} from '../graphql/generated';
import { BuildQuery } from '../graphql/queries/BuildQuery';
import { RequestedPlatform, appPlatformEmojis } from '../platform';
const platformToAppPlatform: Record<
Exclude<RequestedPlatform, RequestedPlatform.All>,
AppPlatform
> = {
android: AppPlatform.Android,
ios: AppPlatform.Ios,
};
export async function ensureBuildExistsAsync(
graphqlClient: ExpoGraphqlClient,
buildId: string
): Promise<void> {
try {
await BuildQuery.byIdAsync(graphqlClient, buildId);
} catch {
throw new Error(`Couldn't find a build matching the id ${buildId}`);
}
}
export async function fetchBuildsAsync({
graphqlClient,
projectId,
filters,
}: {
graphqlClient: ExpoGraphqlClient;
projectId: string;
filters?: { statuses?: BuildStatus[]; platform?: RequestedPlatform; profile?: string };
}): Promise<BuildFragment[]> {
let builds: BuildFragment[];
const queryFilters: InputMaybe<BuildFilter> = {};
if (filters?.platform && filters.platform !== 'all') {
queryFilters['platform'] = platformToAppPlatform[filters.platform];
}
if (filters?.profile) {
queryFilters['buildProfile'] = filters.profile;
}
if (!filters?.statuses) {
builds = await BuildQuery.viewBuildsOnAppAsync(graphqlClient, {
appId: projectId,
offset: 0,
limit: 10,
filter: queryFilters ? queryFilters : undefined,
});
} else {
builds = (
await Promise.all(
filters.statuses.map(status =>
BuildQuery.viewBuildsOnAppAsync(graphqlClient, {
appId: projectId,
offset: 0,
limit: 10,
filter: queryFilters ? { ...queryFilters, status } : { status },
})
)
)
).flat();
}
builds.sort((buildA, buildB) => (buildA.createdAt > buildB.createdAt ? -1 : 1));
return builds;
}
export function formatBuild(
build: Pick<Build, 'id' | 'platform' | 'status' | 'createdAt'>
): string {
const platform = appPlatformEmojis[build.platform];
const startTime = new Date(build.createdAt).toLocaleString();
let statusText: string;
if (build.status === BuildStatus.New) {
statusText = 'new';
} else if (build.status === BuildStatus.InQueue) {
statusText = 'in queue';
} else if (build.status === BuildStatus.InProgress) {
statusText = 'in progress';
} else if (build.status === BuildStatus.Finished) {
statusText = 'finished';
} else if (build.status === BuildStatus.Errored) {
statusText = 'errored';
} else if ([BuildStatus.PendingCancel, BuildStatus.Canceled].includes(build.status)) {
statusText = 'canceled';
} else {
statusText = 'unknown';
}
const status = chalk.blue(statusText);
return `${platform} Started at: ${startTime}, Status: ${status}, Id: ${build.id}`;
}
@@ -1,5 +1,5 @@
import ContextField, { ContextOptions } from './ContextField';
import { Analytics } from '../../analytics/AnalyticsManager';
import ContextField, { ContextOptions } from './ContextField';
export default class AnalyticsContextField extends ContextField<Analytics> {
async getValueAsync({ analytics }: ContextOptions): Promise<Analytics> {
@@ -1,13 +1,13 @@
import { ExpoConfig } from '@expo/config-types';
import ContextField, { ContextOptions } from './ContextField';
import { findProjectDirAndVerifyProjectSetupAsync } from './contextUtils/findProjectDirAndVerifyProjectSetupAsync';
import { getProjectIdAsync } from './contextUtils/getProjectIdAsync';
import {
ExpoConfigOptions,
getPrivateExpoConfig,
getPublicExpoConfig,
} from '../../project/expoConfig';
import ContextField, { ContextOptions } from './ContextField';
import { findProjectDirAndVerifyProjectSetupAsync } from './contextUtils/findProjectDirAndVerifyProjectSetupAsync';
import { getProjectIdAsync } from './contextUtils/getProjectIdAsync';
export type DynamicConfigContextFn = (options?: ExpoConfigOptions) => Promise<{
projectId: string;
@@ -1,8 +1,8 @@
import ContextField, { ContextOptions } from './ContextField';
import { ExpoGraphqlClient, createGraphqlClient } from './contextUtils/createGraphqlClient';
import { Actor } from '../../user/User';
import FeatureGateEnvOverrides from '../gating/FeatureGateEnvOverrides';
import FeatureGating from '../gating/FeatureGating';
import ContextField, { ContextOptions } from './ContextField';
import { ExpoGraphqlClient, createGraphqlClient } from './contextUtils/createGraphqlClient';
export default class LoggedInContextField extends ContextField<{
actor: Actor;
@@ -1,8 +1,8 @@
import ContextField, { ContextOptions } from './ContextField';
import { ExpoGraphqlClient, createGraphqlClient } from './contextUtils/createGraphqlClient';
import { Actor } from '../../user/User';
import FeatureGateEnvOverrides from '../gating/FeatureGateEnvOverrides';
import FeatureGating from '../gating/FeatureGating';
import ContextField, { ContextOptions } from './ContextField';
import { ExpoGraphqlClient, createGraphqlClient } from './contextUtils/createGraphqlClient';
export default class MaybeLoggedInContextField extends ContextField<{
actor: Actor | null;
@@ -1,10 +1,10 @@
import { ExpoConfig } from '@expo/config-types';
import { InvalidEasJsonError } from '@expo/eas-json/build/errors';
import { getPrivateExpoConfig } from '../../project/expoConfig';
import ContextField, { ContextOptions } from './ContextField';
import { findProjectDirAndVerifyProjectSetupAsync } from './contextUtils/findProjectDirAndVerifyProjectSetupAsync';
import { getProjectIdAsync } from './contextUtils/getProjectIdAsync';
import { getPrivateExpoConfig } from '../../project/expoConfig';
export class OptionalPrivateProjectConfigContextField extends ContextField<
| {
@@ -1,9 +1,9 @@
import { ExpoConfig } from '@expo/config-types';
import { getPrivateExpoConfig } from '../../project/expoConfig';
import ContextField, { ContextOptions } from './ContextField';
import { findProjectDirAndVerifyProjectSetupAsync } from './contextUtils/findProjectDirAndVerifyProjectSetupAsync';
import { getProjectIdAsync } from './contextUtils/getProjectIdAsync';
import { getPrivateExpoConfig } from '../../project/expoConfig';
export class PrivateProjectConfigContextField extends ContextField<{
projectId: string;
@@ -1,5 +1,5 @@
import ContextField, { ContextOptions } from './ContextField';
import SessionManager from '../../user/SessionManager';
import ContextField, { ContextOptions } from './ContextField';
export default class SessionManagementContextField extends ContextField<SessionManager> {
async getValueAsync({ sessionManager }: ContextOptions): Promise<SessionManager> {
@@ -1,6 +1,6 @@
import ContextField from './ContextField';
import { getVcsClient } from '../../vcs';
import { Client } from '../../vcs/vcs';
import ContextField from './ContextField';
export default class VcsClientContextField extends ContextField<Client> {
async getValueAsync(): Promise<Client> {
@@ -3,8 +3,6 @@ import { ExpoConfig } from '@expo/config-types';
import { Env } from '@expo/eas-build-job';
import chalk from 'chalk';
import { createGraphqlClient } from './createGraphqlClient';
import { findProjectRootAsync } from './findProjectDirAndVerifyProjectSetupAsync';
import { AppQuery } from '../../../graphql/queries/AppQuery';
import Log, { learnMore } from '../../../log';
import { ora } from '../../../ora';
@@ -13,6 +11,8 @@ import { fetchOrCreateProjectIDForWriteToConfigWithConfirmationAsync } from '../
import { toAppPrivacy } from '../../../project/projectUtils';
import SessionManager from '../../../user/SessionManager';
import { Actor, getActorUsername } from '../../../user/User';
import { createGraphqlClient } from './createGraphqlClient';
import { findProjectRootAsync } from './findProjectDirAndVerifyProjectSetupAsync';
/**
* Save an EAS project ID to the appropriate field in the app config.
@@ -1,7 +1,7 @@
import nullthrows from 'nullthrows';
import { FeatureGateKey } from './FeatureGateKey';
import env from '../../env';
import { FeatureGateKey } from './FeatureGateKey';
function parseFeatureGateEnvVariableValue(value: string | undefined): string[] {
if (!value) {
+58 -41
View File
@@ -1,8 +1,7 @@
import { Flags } from '@oclif/core';
import chalk from 'chalk';
import gql from 'graphql-tag';
import EasCommand from '../../commandUtils/EasCommand';
import { ensureBuildExistsAsync, fetchBuildsAsync, formatBuild } from '../../commandUtils/builds';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
import { EASNonInteractiveFlag } from '../../commandUtils/flags';
import { withErrorHandlingAsync } from '../../graphql/client';
@@ -12,9 +11,10 @@ import {
CancelBuildMutation,
CancelBuildMutationVariables,
} from '../../graphql/generated';
import { BuildQuery } from '../../graphql/queries/BuildQuery';
import Log from '../../log';
import { ora } from '../../ora';
import { RequestedPlatform } from '../../platform';
import { appPlatformEmojis } from '../../platform';
import { getDisplayNameForProjectIdAsync } from '../../project/projectUtils';
import { confirmAsync, selectAsync } from '../../prompts';
@@ -42,28 +42,54 @@ async function cancelBuildAsync(
return data.build!.cancel;
}
function formatUnfinishedBuild(
build: Pick<Build, 'id' | 'platform' | 'status' | 'createdAt'>
): string {
const platform = appPlatformEmojis[build.platform];
const startTime = new Date(build.createdAt).toLocaleString();
let statusText: string;
if (build.status === BuildStatus.New) {
statusText = 'new';
} else if (build.status === BuildStatus.InQueue) {
statusText = 'in queue';
} else {
statusText = 'in progress';
}
const status = chalk.blue(statusText);
return `${platform} Started at: ${startTime}, Status: ${status}, Id: ${build.id}`;
}
export async function selectBuildToCancelAsync(
graphqlClient: ExpoGraphqlClient,
projectId: string,
projectDisplayName: string,
filters?: {
platform?: RequestedPlatform;
profile?: string;
}
projectDisplayName: string
): Promise<string | null> {
const spinner = ora().start('Fetching the uncompleted builds…');
let builds;
try {
builds = await fetchBuildsAsync({
graphqlClient,
projectId,
filters: {
...filters,
statuses: [BuildStatus.New, BuildStatus.InQueue, BuildStatus.InProgress],
},
});
const [newBuilds, inQueueBuilds, inProgressBuilds] = await Promise.all([
BuildQuery.viewBuildsOnAppAsync(graphqlClient, {
appId: projectId,
offset: 0,
limit: 10,
filter: { status: BuildStatus.New },
}),
BuildQuery.viewBuildsOnAppAsync(graphqlClient, {
appId: projectId,
offset: 0,
limit: 10,
filter: { status: BuildStatus.InQueue },
}),
BuildQuery.viewBuildsOnAppAsync(graphqlClient, {
appId: projectId,
offset: 0,
limit: 10,
filter: { status: BuildStatus.InProgress },
}),
]);
spinner.stop();
builds = [...newBuilds, ...inQueueBuilds, ...inProgressBuilds];
} catch (error) {
spinner.fail(
`Something went wrong and we couldn't fetch the builds for the project ${projectDisplayName}.`
@@ -71,13 +97,13 @@ export async function selectBuildToCancelAsync(
throw error;
}
if (builds.length === 0) {
Log.warn(`We couldn't find any uncompleted builds for the project ${projectDisplayName}.`);
Log.warn(`There aren't any uncompleted builds for the project ${projectDisplayName}.`);
return null;
} else {
const buildId = await selectAsync<string>(
'Which build do you want to cancel?',
builds.map(build => ({
title: formatBuild(build),
title: formatUnfinishedBuild(build),
value: build.id,
}))
);
@@ -90,6 +116,17 @@ export async function selectBuildToCancelAsync(
}
}
async function ensureBuildExistsAsync(
graphqlClient: ExpoGraphqlClient,
buildId: string
): Promise<void> {
try {
await BuildQuery.byIdAsync(graphqlClient, buildId);
} catch {
throw new Error(`Couldn't find a build matching the id ${buildId}`);
}
}
export default class BuildCancel extends EasCommand {
static override description = 'cancel a build';
@@ -97,16 +134,6 @@ export default class BuildCancel extends EasCommand {
static override flags = {
...EASNonInteractiveFlag,
platform: Flags.enum({
char: 'p',
description: 'Filter builds by the platform if build ID is not provided',
options: Object.values(RequestedPlatform),
}),
profile: Flags.string({
char: 'e',
description: 'Filter builds by build profile if build ID is not provided',
helpValue: 'PROFILE_NAME',
}),
};
static override contextDefinition = {
@@ -118,15 +145,8 @@ export default class BuildCancel extends EasCommand {
async runAsync(): Promise<void> {
const {
args: { BUILD_ID: buildIdFromArg },
flags: { 'non-interactive': nonInteractive, platform, profile },
flags: { 'non-interactive': nonInteractive },
} = await this.parse(BuildCancel);
if (buildIdFromArg && (platform || profile)) {
throw new Error(
'Build ID cannot be used together with platform and profile flags. They are used to filter the list of builds when not providing the build ID'
);
}
const {
privateProjectConfig: { projectId },
loggedIn: { graphqlClient },
@@ -143,13 +163,10 @@ export default class BuildCancel extends EasCommand {
let buildId: string | null = buildIdFromArg;
if (!buildId) {
if (nonInteractive) {
throw new Error('Build ID must be provided in non-interactive mode');
throw new Error('BUILD_ID must not be empty in non-interactive mode');
}
buildId = await selectBuildToCancelAsync(graphqlClient, projectId, displayName, {
platform,
profile,
});
buildId = await selectBuildToCancelAsync(graphqlClient, projectId, displayName);
if (!buildId) {
return;
}
@@ -1,148 +0,0 @@
import { Flags } from '@oclif/core';
import gql from 'graphql-tag';
import EasCommand from '../../commandUtils/EasCommand';
import { ensureBuildExistsAsync, fetchBuildsAsync, formatBuild } from '../../commandUtils/builds';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
import { EASNonInteractiveFlag } from '../../commandUtils/flags';
import { withErrorHandlingAsync } from '../../graphql/client';
import { Build, DeleteBuildMutation, DeleteBuildMutationVariables } from '../../graphql/generated';
import Log from '../../log';
import { ora } from '../../ora';
import { RequestedPlatform } from '../../platform';
import { getDisplayNameForProjectIdAsync } from '../../project/projectUtils';
import { confirmAsync, selectAsync } from '../../prompts';
async function deleteBuildAsync(
graphqlClient: ExpoGraphqlClient,
buildId: string
): Promise<Pick<Build, 'id'>> {
const data = await withErrorHandlingAsync(
graphqlClient
.mutation<DeleteBuildMutation, DeleteBuildMutationVariables>(
gql`
mutation DeleteBuildMutation($buildId: ID!) {
build(buildId: $buildId) {
deleteBuild(buildId: $buildId) {
id
}
}
}
`,
{ buildId }
)
.toPromise()
);
return data.build!.deleteBuild;
}
export async function selectBuildToDeleteAsync(
graphqlClient: ExpoGraphqlClient,
projectId: string,
projectDisplayName: string,
filters?: {
platform?: RequestedPlatform;
profile?: string;
}
): Promise<string | null> {
const spinner = ora().start('Fetching builds…');
let builds;
try {
builds = await fetchBuildsAsync({ graphqlClient, projectId, filters });
spinner.stop();
} catch (error) {
spinner.fail(
`Something went wrong and we couldn't fetch the builds for the project ${projectDisplayName}.`
);
throw error;
}
if (builds.length === 0) {
Log.warn(`We couldn't find any builds for the project ${projectDisplayName}.`);
return null;
} else {
const buildId = await selectAsync<string>(
'Which build do you want to delete?',
builds.map(build => ({
title: formatBuild(build),
value: build.id,
}))
);
return (await confirmAsync({
message: 'Are you sure you want to delete it?',
}))
? buildId
: null;
}
}
export default class BuildDelete extends EasCommand {
static override description = 'delete a build';
static override args = [{ name: 'BUILD_ID' }];
static override flags = {
...EASNonInteractiveFlag,
platform: Flags.enum({
char: 'p',
description: 'Filter builds by the platform if build ID is not provided',
options: Object.values(RequestedPlatform),
}),
profile: Flags.string({
char: 'e',
description: 'Filter builds by build profile if build ID is not provided',
helpValue: 'PROFILE_NAME',
}),
};
static override contextDefinition = {
...this.ContextOptions.ProjectConfig,
...this.ContextOptions.LoggedIn,
...this.ContextOptions.Vcs,
};
async runAsync(): Promise<void> {
const {
args: { BUILD_ID: buildIdFromArg },
flags: { 'non-interactive': nonInteractive, platform, profile },
} = await this.parse(BuildDelete);
if (buildIdFromArg && (platform || profile)) {
throw new Error(
'Build ID cannot be used together with platform and profile flags. They are used to filter the list of builds when not providing the build ID'
);
}
const {
privateProjectConfig: { projectId },
loggedIn: { graphqlClient },
} = await this.getContextAsync(BuildDelete, { nonInteractive });
const displayName = await getDisplayNameForProjectIdAsync(graphqlClient, projectId);
if (buildIdFromArg) {
await ensureBuildExistsAsync(graphqlClient, buildIdFromArg);
}
let buildId: string | null = buildIdFromArg;
if (!buildId) {
if (nonInteractive) {
throw new Error('Build ID must be provided in non-interactive mode');
}
buildId = await selectBuildToDeleteAsync(graphqlClient, projectId, displayName, {
platform,
profile,
});
if (!buildId) {
return;
}
}
const spinner = ora().start('Deleting the build...');
try {
await deleteBuildAsync(graphqlClient, buildId);
spinner.succeed('Build deleted');
} catch (error) {
spinner.fail(`Something went wrong and we couldn't delete your build ${buildId}`);
throw error;
}
}
}
+3 -1
View File
@@ -50,7 +50,9 @@ export default class Config extends EasCommand {
maybeProfile ??
(await selectAsync(
'Select build profile',
(await EasJsonUtils.getBuildProfileNamesAsync(accessor)).map(profileName => ({
(
await EasJsonUtils.getBuildProfileNamesAsync(accessor)
).map(profileName => ({
title: profileName,
value: profileName,
}))
+1
View File
@@ -37,6 +37,7 @@ export default class Open extends EasCommand {
} else {
spinner.fail(failedMessage);
}
return;
} catch (error) {
spinner.fail(failedMessage);
throw error;
@@ -29,7 +29,6 @@ import {
collectAssetsAsync,
defaultPublishPlatforms,
filterExportedPlatformsByFlag,
generateEasMetadataAsync,
getBranchNameForCommandAsync,
getRequestedPlatform,
getRuntimeToPlatformMappingFromRuntimeVersions,
@@ -41,7 +40,7 @@ import {
uploadAssetsAsync,
} from '../../project/publish';
import { ensureEASUpdateIsConfiguredAsync } from '../../update/configure';
import { getUpdateJsonInfosForUpdates } from '../../update/utils';
import { getUpdateGroupJsonInfo } from '../../update/utils';
import {
checkManifestBodyAgainstUpdateInfoGroup,
getCodeSigningInfoAsync,
@@ -469,11 +468,8 @@ export default class UpdatePublish extends EasCommand {
throw e;
}
if (!skipBundler) {
await generateEasMetadataAsync(distRoot, getUpdateJsonInfosForUpdates(newUpdates));
}
if (jsonFlag) {
printJsonOnlyOutput(getUpdateJsonInfosForUpdates(newUpdates));
printJsonOnlyOutput(getUpdateGroupJsonInfo(newUpdates));
} else {
if (new Set(newUpdates.map(update => update.group)).size > 1) {
Log.addNewLineIfNone();
@@ -515,7 +511,7 @@ export default class UpdatePublish extends EasCommand {
? [{ label: 'Android update ID', value: newAndroidUpdate.id }]
: []),
...(newIosUpdate ? [{ label: 'iOS update ID', value: newIosUpdate.id }] : []),
{ label: 'Message', value: updateMessage ?? '' },
{ label: 'Message', value: updateMessage },
...(gitCommitHash
? [
{
@@ -293,12 +293,7 @@ async function askUpdatesFromChannelNameAsync(
nonInteractive,
}: { projectId: string; channelName: string; json: boolean; nonInteractive: boolean }
): Promise<UpdateToRepublish[]> {
const branchName = await getBranchNameFromChannelNameAsync(
graphqlClient,
projectId,
channelName,
{ json, nonInteractive, offset: 0 }
);
const branchName = await getBranchNameFromChannelNameAsync(graphqlClient, projectId, channelName);
return await askUpdatesFromBranchNameAsync(graphqlClient, {
projectId,
@@ -34,7 +34,7 @@ import {
getUpdateMessageForCommandAsync,
} from '../../project/publish';
import { ensureEASUpdateIsConfiguredAsync } from '../../update/configure';
import { getUpdateJsonInfosForUpdates } from '../../update/utils';
import { getUpdateGroupJsonInfo } from '../../update/utils';
import {
CodeSigningInfo,
checkDirectiveBodyAgainstUpdateInfoGroup,
@@ -228,7 +228,7 @@ export default class UpdateRollBackToEmbedded extends EasCommand {
}
if (jsonFlag) {
printJsonOnlyOutput(getUpdateJsonInfosForUpdates(newUpdates));
printJsonOnlyOutput(getUpdateGroupJsonInfo(newUpdates));
} else {
if (new Set(newUpdates.map(update => update.group)).size > 1) {
Log.addNewLineIfNone();
@@ -270,7 +270,7 @@ export default class UpdateRollBackToEmbedded extends EasCommand {
? [{ label: 'Android update ID', value: newAndroidUpdate.id }]
: []),
...(newIosUpdate ? [{ label: 'iOS update ID', value: newIosUpdate.id }] : []),
{ label: 'Message', value: updateMessage ?? '' },
{ label: 'Message', value: updateMessage },
...(gitCommitHash
? [
{
@@ -300,7 +300,7 @@ export default class UpdateRollBackToEmbedded extends EasCommand {
graphqlClient: ExpoGraphqlClient;
isGitWorkingTreeDirty: boolean | undefined;
gitCommitHash: string | undefined;
updateMessage: string | undefined;
updateMessage: string;
branchId: string;
codeSigningInfo: CodeSigningInfo | undefined;
runtimeVersions: { platform: string; runtimeVersion: string }[];
@@ -1,9 +1,9 @@
import { Flags } from '@oclif/core';
import UpdateRepublish from './republish';
import UpdateRollBackToEmbedded from './roll-back-to-embedded';
import EasCommand from '../../commandUtils/EasCommand';
import { promptAsync } from '../../prompts';
import UpdateRepublish from './republish';
import UpdateRollBackToEmbedded from './roll-back-to-embedded';
export default class UpdateRollback extends EasCommand {
static override description = 'roll back to an embedded update or an existing update';
+2 -2
View File
@@ -7,7 +7,7 @@ import Log from '../../log';
import {
formatUpdateGroup,
getUpdateGroupDescriptions,
getUpdateJsonInfosForUpdates,
getUpdateGroupJsonInfo,
} from '../../update/utils';
import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
@@ -47,7 +47,7 @@ export default class UpdateView extends EasCommand {
const updatesByGroup = await UpdateQuery.viewUpdateGroupAsync(graphqlClient, { groupId });
if (jsonFlag) {
printJsonOnlyOutput(getUpdateJsonInfosForUpdates(updatesByGroup));
printJsonOnlyOutput(getUpdateGroupJsonInfo(updatesByGroup));
} else {
const [updateGroupDescription] = getUpdateGroupDescriptions([updatesByGroup]);
@@ -1,9 +1,3 @@
import {
testKeystore2Base64,
testKeystoreBase64,
testPKCS12KeystoreBase64,
testPKCS12KeystoreEmptyPasswordBase64,
} from './fixtures-base64-data';
import {
AndroidAppBuildCredentialsFragment,
AndroidFcmFragment,
@@ -17,6 +11,12 @@ import {
} from '../../graphql/generated';
import * as AndroidGraphqlClient from '../android/api/GraphqlClient';
import { Keystore } from '../android/credentials';
import {
testKeystore2Base64,
testKeystoreBase64,
testPKCS12KeystoreBase64,
testPKCS12KeystoreEmptyPasswordBase64,
} from './fixtures-base64-data';
const now = new Date();
@@ -1,10 +1,10 @@
import merge from 'ts-deepmerge';
import { CredentialsContext } from '../context';
import { getNewAndroidApiMock } from './fixtures-android';
import { getAppstoreMock } from './fixtures-appstore';
import { testAppJson, testUsername } from './fixtures-constants';
import { getNewIosApiMock } from './fixtures-ios';
import { CredentialsContext } from '../context';
export function createCtxMock(mockOverride: Record<string, any> = {}): CredentialsContext {
const defaultMock = {
@@ -1,6 +1,5 @@
import { UserRole } from '@expo/apple-utils';
import { testProvisioningProfileBase64 } from './fixtures-base64-data';
import {
AppFragment,
AppStoreConnectApiKeyFragment,
@@ -22,6 +21,7 @@ import {
ProvisioningProfile,
} from '../ios/appstore/Credentials.types';
import { Target } from '../ios/types';
import { testProvisioningProfileBase64 } from './fixtures-base64-data';
const now = new Date();
@@ -2,12 +2,12 @@ import { Platform } from '@expo/eas-build-job';
import { CredentialsSource } from '@expo/eas-json';
import nullthrows from 'nullthrows';
import { SetUpBuildCredentials } from './actions/SetUpBuildCredentials';
import { AppLookupParams } from './api/GraphqlClient';
import { Keystore } from './credentials';
import { AndroidAppBuildCredentialsFragment } from '../../graphql/generated';
import { CredentialsContext } from '../context';
import * as credentialsJsonReader from '../credentialsJson/read';
import { SetUpBuildCredentials } from './actions/SetUpBuildCredentials';
import { AppLookupParams } from './api/GraphqlClient';
import { Keystore } from './credentials';
export interface AndroidCredentials {
keystore: Keystore;
@@ -20,10 +20,7 @@ interface Options {
export default class AndroidCredentialsProvider {
public readonly platform = Platform.ANDROID;
constructor(
private ctx: CredentialsContext,
private options: Options
) {}
constructor(private ctx: CredentialsContext, private options: Options) {}
public async getCredentialsAsync(
src: CredentialsSource.LOCAL | CredentialsSource.REMOTE
@@ -1,11 +1,11 @@
import chalk from 'chalk';
import { BackupKeystore } from './DownloadKeystore';
import { AndroidAppBuildCredentialsFragment } from '../../../graphql/generated';
import Log from '../../../log';
import { confirmAsync } from '../../../prompts';
import { CredentialsContext } from '../../context';
import { AppLookupParams } from '../api/GraphqlClient';
import { BackupKeystore } from './DownloadKeystore';
export class RemoveKeystore {
constructor(private app: AppLookupParams) {}
@@ -1,11 +1,5 @@
import nullthrows from 'nullthrows';
import {
canCopyLegacyCredentialsAsync,
createOrUpdateDefaultAndroidAppBuildCredentialsAsync,
promptUserAndCopyLegacyCredentialsAsync,
} from './BuildCredentialsUtils';
import { CreateKeystore } from './CreateKeystore';
import {
AndroidAppBuildCredentialsFragment,
AndroidKeystoreFragment,
@@ -15,6 +9,12 @@ import { ora } from '../../../ora';
import { CredentialsContext } from '../../context';
import { MissingCredentialsNonInteractiveError } from '../../errors';
import { AppLookupParams } from '../api/GraphqlClient';
import {
canCopyLegacyCredentialsAsync,
createOrUpdateDefaultAndroidAppBuildCredentialsAsync,
promptUserAndCopyLegacyCredentialsAsync,
} from './BuildCredentialsUtils';
import { CreateKeystore } from './CreateKeystore';
interface Options {
app: AppLookupParams;
@@ -1,4 +1,3 @@
import { BackupKeystore } from './DownloadKeystore';
import {
AndroidAppBuildCredentialsFragment,
AndroidKeystoreType,
@@ -13,6 +12,7 @@ import {
} from '../../manager/SelectAndroidBuildCredentials';
import { AppLookupParams } from '../api/GraphqlClient';
import { getKeystoreWithType } from '../utils/keystoreNew';
import { BackupKeystore } from './DownloadKeystore';
export class SetUpBuildCredentialsFromCredentialsJson {
constructor(private app: AppLookupParams) {}
@@ -1,8 +1,5 @@
import nullthrows from 'nullthrows';
import { AssignGoogleServiceAccountKey } from './AssignGoogleServiceAccountKey';
import { CreateGoogleServiceAccountKey } from './CreateGoogleServiceAccountKey';
import { UseExistingGoogleServiceAccountKey } from './UseExistingGoogleServiceAccountKey';
import {
CommonAndroidAppCredentialsFragment,
GoogleServiceAccountKeyFragment,
@@ -12,6 +9,9 @@ import { promptAsync } from '../../../prompts';
import { CredentialsContext } from '../../context';
import { MissingCredentialsNonInteractiveError } from '../../errors';
import { AppLookupParams } from '../api/GraphqlClient';
import { AssignGoogleServiceAccountKey } from './AssignGoogleServiceAccountKey';
import { CreateGoogleServiceAccountKey } from './CreateGoogleServiceAccountKey';
import { UseExistingGoogleServiceAccountKey } from './UseExistingGoogleServiceAccountKey';
export class SetUpGoogleServiceAccountKey {
constructor(private app: AppLookupParams) {}
@@ -1,10 +1,3 @@
import { AndroidAppBuildCredentialsMutation } from './graphql/mutations/AndroidAppBuildCredentialsMutation';
import { AndroidAppCredentialsMutation } from './graphql/mutations/AndroidAppCredentialsMutation';
import { AndroidFcmMutation } from './graphql/mutations/AndroidFcmMutation';
import { AndroidKeystoreMutation } from './graphql/mutations/AndroidKeystoreMutation';
import { GoogleServiceAccountKeyMutation } from './graphql/mutations/GoogleServiceAccountKeyMutation';
import { AndroidAppCredentialsQuery } from './graphql/queries/AndroidAppCredentialsQuery';
import { GoogleServiceAccountKeyQuery } from './graphql/queries/GoogleServiceAccountKeyQuery';
import { ExpoGraphqlClient } from '../../../commandUtils/context/contextUtils/createGraphqlClient';
import {
AccountFragment,
@@ -18,6 +11,13 @@ import {
} from '../../../graphql/generated';
import { AppQuery } from '../../../graphql/queries/AppQuery';
import { GoogleServiceAccountKey, KeystoreWithType } from '../credentials';
import { AndroidAppBuildCredentialsMutation } from './graphql/mutations/AndroidAppBuildCredentialsMutation';
import { AndroidAppCredentialsMutation } from './graphql/mutations/AndroidAppCredentialsMutation';
import { AndroidFcmMutation } from './graphql/mutations/AndroidFcmMutation';
import { AndroidKeystoreMutation } from './graphql/mutations/AndroidKeystoreMutation';
import { GoogleServiceAccountKeyMutation } from './graphql/mutations/GoogleServiceAccountKeyMutation';
import { AndroidAppCredentialsQuery } from './graphql/queries/AndroidAppCredentialsQuery';
import { GoogleServiceAccountKeyQuery } from './graphql/queries/GoogleServiceAccountKeyQuery';
export interface AppLookupParams {
account: AccountFragment;
@@ -0,0 +1,210 @@
import {
getAsn1Hash,
getCertificateFingerprint,
getFormattedSerialNumber,
getX509Asn1ByFriendlyName,
getX509Certificate,
getX509CertificateByFriendlyName,
parsePKCS12,
} from '../pkcs12';
// https://pkijs.org/examples/PKCS12SimpleExample.html
// PKCS#12 With Password-Based Integrity Protection And No Privacy Protection
// A PKCS#12 file with one key and one certificate (most common case)
const conventionalP12 = {
base64EncodedP12:
'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',
password: 'test',
serialNumber: '1',
md5Fingerprint: '2557d902372f89802767249fc6d65113',
sha1Fingerprint: '02ec75a7181c575757baa931fe3105b7125ff10a',
sha256Fingerprint: 'fba434e1877fbbf48cd041389ef9e1c0b511d1426c69d6d110e7d2a7db6b5890',
};
// Generated by: keytool -genkey -alias test-alias -keystore keystore.p12 -storetype PKCS12 -keyalg RSA -storepass password -validity 730 -keysize 2048
// A Keystore in a PKCS#12 file, where all entries are under aliases
// This particular PKCS#12 has one key and one certificate under 'test-alias'
const keystoreP12 = {
base64EncodedP12:
'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',
password: 'password',
alias: 'test-alias',
// Expected fingerprints derived from: keytool -list -v -keystore [keystore-path]
md5Fingerprint: 'ccd9d0fd20a862b1e67ea838c99dd0c5',
sha1Fingerprint: '2ef9743a1bf12189af5503787b54bfd3254b46a8',
sha256Fingerprint: 'eecdd35e90bb272d52ec261b4063c5d586980795452340525f9c8cc56db53e2b',
};
// keytool -genkey -alias UPPERCASE -keystore keystore.p12 -storetype PKCS12 -keyalg RSA -storepass password -validity 730 -keysize 2048
const uppercaseAliasKeystoreP12 = {
base64EncodedP12:
'MIITawIBAzCCEyQGCSqGSIb3DQEHAaCCExUEghMRMIITDTCCCskGCSqGSIb3DQEHAaCCCroEggq2MIIKsjCCBVYGCyqGSIb3DQEMCgECoIIE+zCCBPcwKQYKKoZIhvcNAQwBAzAbBBT5CPXUtTFIhZO3Cpdw39WK9cZenQIDAMNQBIIEyPG/T570+fv3FyUiwm7Nwk2p6jMyCmlyO8iYsFuCaTW6vbA2KMHa/A7A6CtpRZdnOB4rOJDx8kCTi+vf3KxHM9GWitFkKhsnYIxf9t6tGEQUPpHetSbe2dr+/F/C3GhmLLh7lWP+dt3V4RqC8otu8IBA+nfHN7AYx7Sg/VCh7wi7gxdZ1q7A7pnvEM/bxZic3W9OOgspgCfEkyu09uZVmxix4Ri3lZpVXPcOazsSFa5mr1wTfsXvrveW/p5aSZ4FGwPyVL8yGaCLL4ggpmHGAcq81SEoZSf6r5sldtZnMYc+rVM8Jjt+E0NDa9lxum4QOodniPUy4iQXm2r8DA0h8aKD5ndjcyyM2ppvJwSiK2CX+X8bqY/yBUTNeFjzIxaEVk4p/BD5SiO/YOWTFTPftPOWDWltue63pmKQXUHPCGr5WAAE7tOCf2kofvJ7EbBmeqPSSj3o2nPOcBkiWem0yLXLDVZUi/G5qBDeogGN8hVWx14MGp6Pe4x+6DZUlSaDrqlPKJ8O0JhyUZ2WrnMzrtQ8W+5MWhVtxU7YLtfq3/eAzXTQJ0vhA/ZjqGQqyA3H+WndQ5hQWJUBewRsjX9qthfrrIHM5TnI4eWy6OAkXCq0fNcx0eJoDlViUgfRy7yvb7D+sokXkyN3di+DNHNvqplK8P2UH0wzfaDBows5/nQqWnRBuR07ujAge+5tEDEjDUul1BFTce2yMkP1jM1jf2JOxkmGCqXGlfK/rbBWiH7ToV1pDHUKf3s4D0Xybs3aOp2xD1jpja6z88GYZvC/8xwjCM8RyirOtYG5ULnaqqLKf5Yo4QyUJVJiDG5EEixQ7Kvn61lwYAg1Jbk5jh5IHn8xnkLaGVfE5nocnCUdy5rn2QQ3GsljIqudqlsVPQx9TdQofw9spoC+STDPUCZeQ0zu9WuYZpEJIMq6ZyDZwZq5S672Xb0emUFI6xvQDg7tLc5Xxo6keYJpxP+kSxlNq6YMg68xRoLhWLQaZhUCV9lSGmoaweDaYNFbc4dr8IVin3QGjjDgxcLuAPhdN0KR/yT1POxAMw6Pit9QIUCUnHOYxucFvwA/INRzN7xGITxrTSRNwtXUbGguxDBtHeAn19LDB860mGauKHZROc9nlFS8iKOhB9eZoEqccuyir+asf4uzuChMEaXBl2A74a/w1opi4q+6sKZkkpV9jCo2A606lXxZ9AUe2moyNjbxDusxrL6X/Fyvpdro7CE+jqw7YE4Uqcnu/muV7juJWDjUKJTi3H91NTE4Ud1IKUEsmmWKCj/tL1aae6r4ZbsbiBn0MP5WWB4sgiXy4ZvXpeCkBeszUx+zbZC11/ag7Jkc7rlIPxMTopQgRS9KIQ/9tIzYHBad8ro45DgFig37KyX2GMZ0pr7KbuZ8RWDTqEHmNnto4aAwGoI+ypKfDMHrqNhAUtvGZzFCjwjEvJFXhFLScvTjyiVzbeU8cIPU2sXIoYQRfavp2vUp+jNKX2SIkQ4Nh3n8YBfOoCW/YNjVJFeDVObwSmiv65XEd+HwXl2cLe8jJXDMXN9ZNdnxWUcgpTF9dp3Zxhr0TmRVJCngL9HjgWrFL9hReZTX3C/Qwnk4rCG7aH2uuDNP5g9Stt1ZDJ0TlUY+hjShVVDSXzFIMCMGCSqGSIb3DQEJFDEWHhQAdABlAHMAdAAtAGEAbABpAGEAczAhBgkqhkiG9w0BCRUxFAQSVGltZSAxNjAzNjA2OTEwMTg0MIIFVAYLKoZIhvcNAQwKAQKgggT7MIIE9zApBgoqhkiG9w0BDAEDMBsEFMdpD/HFDCPc6Fw7bT/BarWYBo2BAgMAw1AEggTI0iM7OfSWxze0x6rLReXZqRxei+0GdHAvPHGYCYq1Y3TQVFy6IOwBqDJD3Ou0dHbeZYoAGmXHfY3MWqKZMqoO7aEJAhrK5BO+GKjoFnxFxA/OTfiApCqdGpOQyqF1cQSmb9Dsq93Fk1bUGB8ovrKkunGH+8r7VfDQa8oGMxuyqd4EvwbrEKJ/kV+Z0ASXYjY0ub0wV9ECqNwdakAPYlg8q+F63oQsxYsls69uGE6TCH68BbSWKgMUXTvtwpEfxiru3OFBCWQZ2YRAG3uqEF0uYse8syXbbosEZ6nWlr4kBFGgr4xGIZ1FQ4/o3JgAbXoRHv3OLjVKbU2QYmxnEYkQ8iz+u37EUUKjenLQtgA3/sWYR9bGOa8q0LddyY+QQg1eRS6ZkOvJTbHnWHxC/2Iw/hwFOLzARSXjto+feWObWxGmjL7/5/PQKfg0+WK+ZWqOBe1rBuKgtOKLU7pNBtZcyD/gS1LZ1kdv7UgR3CUOoEDTy+vUjX5d2tmkInqM5woqBSbi2voP3EbhzCeWB6LvZbiFK/OyTSZ2ihgK1NS97BlULcMXuLcVSHKJCpl6Sw24pSkwqIMihUamO/XJbDLrnOfp99aiJeOVfMdWXpBCeztFs9yvF8/w2+w/quJQjs53pTiIXtxC/Ozs9rtPWfva5+C7MaYn822zaWFKkIcahqHDuqMucG/UZtjyPIhiCIPTc9az2fxHjS4Epzj6Exp/h8BmB5qcfQuuhjC+vqq4qqNVrUUEBEsp7voQL80IfMxuiOOIcrsy4D5gIhq2ZYOQeQZ9DGBUGmL6JFpmJZq0O9hd+DMsxEp7uXcYrUP6z/BrZgv22M0UAUSaszmd6WtgRXiCNliMEDee2MOgEEgNRqEcv2/L7VlLztPNZfitb4Ebpt8nNRqgpW5rAVKWBx53s4pW9XbdJT1T/H39o5JG8H0K/7Ra8AWt8byH+vp9MSuGsFojx1YSMrFyYqasaOvteebTxd6b068AKNIZTEgcE1MDZVmVWFTefiWW5D20jdc1CT/z1MDoyux25/kp/vWDa5fy3akXwNWmS5kAe4HY9Ms23Xm9NPwKqIXIqn25bjcZbWW4fqXUE1LUa0fNsMUj3AYnE5Nkwzx6Tnnx+qdOgJ3RySpmvpeK7xtzAnqIjkOuBj8hW4CXn0SjRS8jWuqSpGqn7wPoobwQLEDoIzIxXXrHkjkjxFcwynzkvwc1CpSagGnNIzaoFCdO1BJeyqPu/0DFlbfn6+NKu+C0YhRmS9bo9G56B1BF6gob3PyyA2o3S3B5L/0FPuseW0PF4lb+JRBV3WCW/BPiwXLMiuuZJaA1PvsTzMVEYciFYVw9cw+sNWu5D+7mkd5j/MO5las+5/jVAlQXR5qNDZynU+K8LCct56uS3ewPHoL5ZIommJo2s23aalmTUO5yuagA6IC/Elfcsc+rE79sp6WCmf+eWoTmKCO/AEEx3bMe+0socN9hHRw14Qn2rXv4w1gSR/tbAYThY22tstTsfzDcAJH0szZVhOGnIxjVfRILoUcQ8QhCagltQI6aQICWyKuJHvm5zBU8ifcrPksYhjLlt5simoEwIEUGfUdDDmQ1XfTVJkedTd3FR3LTgk0JedTnWd5kJmxh096yZNnQMUYwIQYJKoZIhvcNAQkUMRQeEgB1AHAAcABlAHIAYwBhAHMAZTAhBgkqhkiG9w0BCRUxFAQSVGltZSAxNjAzNjA4NjkxNzY4MIIIPAYJKoZIhvcNAQcGoIIILTCCCCkCAQAwgggiBgkqhkiG9w0BBwEwKQYKKoZIhvcNAQwBBjAbBBSwPJdg3O5zbJ1XueAQj2uQB/JMAwIDAMNQgIIH6O4I9P0S2ThumqriXDBWrfUyOc7GIdQRaagFG8+39Hye0a5G7lpkaDFNHrgv6XLAOYHrBNpEK9MSTsrSlfBYUX1jNAaQgsCJPOH1h11PBp7Fm2193cgpwxDIlkjLfnOZCBsTMs21mLRei5h6/0ks9wnBBpPb+w6nNs9qsFObSTq0LyuJb+yL7uH2Cxm4e43S1ZwTANs3dSsLJk8a73LsBj9H7w5I300bbHuhhtM6efvkKwGbOQHoceLmCnu8Qm6YX9hqUbg6hbEnXfAY2Mp+X3qGoCI8xNukocFbwBLiz72TIf2kJKmahvtVI17qZS44bQ9K0UMd9G8oBba7F0liJdvf9lXV0WDfR+L+IfO+EJqf8dx3ZsundJ2z9CBpK/7ZXhXKUaNeLMtG2NK/rfkQxoeIOaFbI8we+YnEba+92HV7O3+yvx1naq4pOxP4Iy2c9K/O3Xx+Sb8zOaYgYDiQ41wZPRccGYzCPtLKCGhDQrMpB40O/YMF7eeUfYJiae5fuq6hwy65jKlGcH7hZEPitp8eDIfJFwMJ/dSwOP6Bta51H+sXrYilpPnFtjTAzVM7KcIqAO/aaMCm2N5Nv32V3mCL4A3XjuPMyuxevrsBIq7B3n6uKWcFzsLHLMcp2IoqEmzRftgJvCS22SaPyvkeRVWO32nw8eUE5eKKxPFkub5yEsuIGx9FAezvC7rltwABqMVQXw92osRHcfmFi6LIOFysyPRU9chFEaLItm7gpwnfZ8MDftu5+rwOnbpE4rKZhIL9oySDu99VSa4QjzdAOe5YdSIKHEBhTC6t+FAVvIlM6knv4GpxoNIb8O4b4vVYgmTxcgX+bk321oxAl+tzuEYe1UOtdc6RREHTXn/DjfYfwGPZbQD/7D2eYA5vVrLPSQKzZBix/KVaqkoNrnOsqFb4zSVyEuUjG1ejwzMl9ItoVMKxDNPslnLWO8It18nAGUve8O2pXhcTRAYzWaLCiTv69UEqZ7EtBLaViSsWHOHjrjaZ6ZVDP6Okbvt86VIG9GpE81USq1I9i9yvTxek+52sq/XxZsevhkJuBJTs7TqLcUNVVknfq4JA8omMjW/tAPrkIWrb88WVTcucDtAr2BU70G1rx+8WelBG4phYugYPwukXx3GJQRkkZALine truncated
password: 'password',
alias: 'UPPERCASE',
};
/**
* Generate DSA certificate:
* openssl dsaparam -out params.pem 3072
* openssl gendsa -out key.pem params.pem
* openssl req -new -key key.pem -out req.pem
* openssl x509 -req -in req.pem -signkey key.pem -out certificate.cer
*
* Package into a PKCS#12 keystore:
* keytool -import -alias test -file certificate.cer -keystore dsapkcs.keystore -storetype pkcs12
*
* node-forge only supports RSA certificates, so this certificate will be 'unknown'
*/
const dsaKeystoreP12 = {
base64EncodedP12:
'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',
password: 'password',
alias: 'test',
// Expected fingerprints derived from: keytool -list -v -keystore [keystore-path]
md5Fingerprint: 'f1371f2a5cd89d813882aebce8f609a4',
sha1Fingerprint: '10c530286a74e0c2e6e6ecf6845edbf686da2aee',
sha256Fingerprint: '822007287d1c8759e5900c34337339bc88a0112feecb4e01e6c74adc830ce3c5',
};
describe('computing fingerprints of X.509 certificates', () => {
it('computes fingerprints of certificates in conventional p12 files', async () => {
const {
base64EncodedP12,
password,
md5Fingerprint: expectedMd5Fingerprint,
sha1Fingerprint: expectedSha1Fingerprint,
sha256Fingerprint: expectedSha256Fingerprint,
} = conventionalP12;
const p12 = parsePKCS12(base64EncodedP12, password);
const certificate = getX509Certificate(p12);
const md5Fingerprint = getCertificateFingerprint(certificate, {
hashAlgorithm: 'md5',
});
const sha1Fingerprint = getCertificateFingerprint(certificate, {
hashAlgorithm: 'sha1',
});
const sha256Fingerprint = getCertificateFingerprint(certificate, {
hashAlgorithm: 'sha256',
});
expect(md5Fingerprint).toEqual(expectedMd5Fingerprint);
expect(sha1Fingerprint).toEqual(expectedSha1Fingerprint);
expect(sha256Fingerprint).toEqual(expectedSha256Fingerprint);
});
it('computes fingerprints of certificates in p12 keystores', async () => {
const {
base64EncodedP12,
password,
alias,
md5Fingerprint: expectedMd5Fingerprint,
sha1Fingerprint: expectedSha1Fingerprint,
sha256Fingerprint: expectedSha256Fingerprint,
} = keystoreP12;
const p12 = parsePKCS12(base64EncodedP12, password);
const certificate = getX509CertificateByFriendlyName(p12, alias);
expect(certificate).toBeDefined();
const md5Fingerprint = getCertificateFingerprint(certificate!, {
hashAlgorithm: 'md5',
});
const sha1Fingerprint = getCertificateFingerprint(certificate!, {
hashAlgorithm: 'sha1',
});
const sha256Fingerprint = getCertificateFingerprint(certificate!, {
hashAlgorithm: 'sha256',
});
expect(md5Fingerprint).toEqual(expectedMd5Fingerprint);
expect(sha1Fingerprint).toEqual(expectedSha1Fingerprint);
expect(sha256Fingerprint).toEqual(expectedSha256Fingerprint);
});
});
describe('computing fingerprints from the ASN.1 representation of an X.509 certificate', () => {
it.each([
['supported RSA certificates', keystoreP12],
['unsupported DSA certificates', dsaKeystoreP12],
])(
'computes fingerprints of %s using their ASN.1 values in PKCS #12 keystores',
async (_description, keystoreP12) => {
const {
base64EncodedP12,
password,
alias,
md5Fingerprint: expectedMd5Fingerprint,
sha1Fingerprint: expectedSha1Fingerprint,
sha256Fingerprint: expectedSha256Fingerprint,
} = keystoreP12;
const p12 = parsePKCS12(base64EncodedP12, password);
const asn1 = getX509Asn1ByFriendlyName(p12, alias);
expect(asn1).toBeDefined();
const md5Fingerprint = getAsn1Hash(asn1!, {
hashAlgorithm: 'md5',
});
const sha1Fingerprint = getAsn1Hash(asn1!, {
hashAlgorithm: 'sha1',
});
const sha256Fingerprint = getAsn1Hash(asn1!, {
hashAlgorithm: 'sha256',
});
expect(md5Fingerprint).toEqual(expectedMd5Fingerprint);
expect(sha1Fingerprint).toEqual(expectedSha1Fingerprint);
expect(sha256Fingerprint).toEqual(expectedSha256Fingerprint);
}
);
});
describe('getting the ASN.1 representation of a X.509 certificate from PKCS#12 files', () => {
it.each([
['supported RSA certificates', keystoreP12],
['unsupported DSA certificates', dsaKeystoreP12],
])('gets the ASN.1 value of %s from PKCS #12 keystores', async (_description, keystoreP12) => {
const { base64EncodedP12, password, alias } = keystoreP12;
const p12 = parsePKCS12(base64EncodedP12, password);
const asn1 = getX509Asn1ByFriendlyName(p12, alias);
expect(asn1).toMatchSnapshot();
});
});
describe('reading X.509 certificates from PKCS#12 files', () => {
it('is unable to parse a DSA X.509 certificate (limitation)', async () => {
const { base64EncodedP12, password, alias } = dsaKeystoreP12;
const p12 = parsePKCS12(base64EncodedP12, password);
expect(() => {
getX509CertificateByFriendlyName(p12, alias);
}).toThrowError();
});
it('reads X.509 certificate serial numbers from conventional p12 files', async () => {
const { base64EncodedP12, password, serialNumber: expectedSerialNumber } = conventionalP12;
const p12 = parsePKCS12(base64EncodedP12, password);
const certificate = getX509Certificate(p12);
const serialNumber = getFormattedSerialNumber(certificate);
expect(serialNumber).toEqual(expectedSerialNumber);
});
it('reads X.509 certificates from conventional p12 files using #getX509Certificate', async () => {
const { base64EncodedP12, password } = conventionalP12;
const p12 = parsePKCS12(base64EncodedP12, password);
const certificate = getX509Certificate(p12);
expect(certificate).toMatchSnapshot();
});
it('reads X.509 certificates from p12 keystores using #getX509Certificate', async () => {
const { base64EncodedP12, password } = keystoreP12;
const p12 = parsePKCS12(base64EncodedP12, password);
// gets an arbitrary certificate from the keystore
const certificate = getX509Certificate(p12);
expect(certificate).toMatchSnapshot();
});
it('reads X.509 certificates from p12 keystores using #getX509CertificateByFriendlyName', async () => {
const { base64EncodedP12, password, alias } = keystoreP12;
const p12 = parsePKCS12(base64EncodedP12, password);
const certificate = getX509CertificateByFriendlyName(p12, alias);
expect(certificate).toMatchSnapshot();
});
it('returns null if there are no X.509 certificates under friendly name for p12 keystores using #getX509CertificateByFriendlyName', async () => {
const { base64EncodedP12, password } = conventionalP12;
const p12 = parsePKCS12(base64EncodedP12, password);
const certificate = getX509CertificateByFriendlyName(p12, 'no keystore here :(');
expect(certificate).toBe(null);
});
it('reads X.509 certificates from p12 keystores with uppercase alias using #getX509CertificateByFriendlyName', async () => {
const { base64EncodedP12, password, alias } = uppercaseAliasKeystoreP12;
const p12 = parsePKCS12(base64EncodedP12, password);
const certificate = getX509CertificateByFriendlyName(p12, alias);
expect(certificate).toMatchSnapshot();
});
});
@@ -1,10 +1,10 @@
import { getX509Asn1ByFriendlyName, parsePKCS12 } from '@expo/pkcs12';
import jks from 'jks-js';
import { asn1 } from 'node-forge';
import { AndroidKeystoreType } from '../../../graphql/generated';
import Log from '../../../log';
import { Keystore, KeystoreWithType } from '../credentials';
import { getX509Asn1ByFriendlyName, parsePKCS12 } from './pkcs12';
export function getKeystoreWithType(keystore: Keystore): KeystoreWithType {
const type = getKeystoreType(keystore);
@@ -0,0 +1,144 @@
import crypto, { HexBase64Latin1Encoding, Utf8AsciiLatin1Encoding } from 'crypto';
import forge from 'node-forge';
/**
* Returns the serial number of the given X.509 certificate as an uppercased hexadecimal string
*/
export function getFormattedSerialNumber(certificate: forge.pki.Certificate): string | null {
const { serialNumber } = certificate;
return serialNumber ? serialNumber.replace(/^0+/, '').toUpperCase() : null;
}
/**
* Extracts a certificate from PKCS#12
* This is assumed to be a conventional PKCS#12 where there is exactly one certificate and one key
*/
export function getX509Certificate(p12: forge.pkcs12.Pkcs12Pfx): forge.pki.Certificate {
const certBagType = forge.pki.oids.certBag;
const bags = p12.getBags({ bagType: certBagType })[certBagType];
if (!bags || bags.length === 0) {
throw new Error(`PKCS12: No certificates found`);
}
return getX509CertificateFromBag(bags[0]);
}
/**
* Extracts a certificate from PKCS#12
* This is assumed to be a PKCS#12 containing a keystore where the friendlyName (alias) contains a PrivateKeyEntry
* A PrivateKeyEntry contains exactly one certificate and one key
* https://docs.oracle.com/javase/7/docs/api/java/security/KeyStore.PrivateKeyEntry.html
*/
export function getX509CertificateByFriendlyName(
p12: forge.pkcs12.Pkcs12Pfx,
friendlyName: string
): forge.pki.Certificate | null {
const certBagType = forge.pki.oids.certBag;
// node-forge converts friendly names to lowercase, so we search by lowercase
const bags = p12.getBags({
friendlyName: friendlyName.toLowerCase(),
bagType: certBagType,
}).friendlyName;
if (!bags || bags.length === 0) {
return null;
}
return getX509CertificateFromBag(bags[0]);
}
function getX509CertificateFromBag(bag: forge.pkcs12.Bag): forge.pki.Certificate {
const { cert, asn1 } = bag;
if (!cert && asn1) {
// if asn1 is present but certificate isnt, the certificate type was unknown
// github.com/digitalbazaar/forge/blob/1887cfce43a8f5ca9cb5c256168cf12ce1715ecf/lib/pkcs12.js#L703
throw new Error('PKCS12: unknown X.509 certificate type');
}
if (!cert) {
throw new Error('PKCS12: bag is not a certificate');
}
return cert;
}
export function getX509Asn1ByFriendlyName(
p12: forge.pkcs12.Pkcs12Pfx,
friendlyName: string
): forge.asn1.Asn1 | null {
const certBagType = forge.pki.oids.certBag;
// node-forge converts friendly names to lowercase, so we search by lowercase
const bags = p12.getBags({
friendlyName: friendlyName.toLowerCase(),
bagType: certBagType,
}).friendlyName;
if (!bags || bags.length === 0) {
return null;
}
const { cert, asn1 } = bags[0];
if (cert) {
return forge.pki.certificateToAsn1(cert);
}
// if asn1 is present but certificate isnt, the certificate type was unknown
// github.com/digitalbazaar/forge/blob/1887cfce43a8f5ca9cb5c256168cf12ce1715ecf/lib/pkcs12.js#L703
return asn1 ?? null;
}
export function parsePKCS12(
p12BufferOrBase64String: Buffer | string,
maybePassword: string | null
): forge.pkcs12.Pkcs12Pfx {
const base64EncodedP12 = Buffer.isBuffer(p12BufferOrBase64String)
? p12BufferOrBase64String.toString('base64')
: p12BufferOrBase64String;
const password = String(maybePassword ?? '');
const p12Der = forge.util.decode64(base64EncodedP12);
const p12Asn1 = forge.asn1.fromDer(p12Der);
return forge.pkcs12.pkcs12FromAsn1(p12Asn1, password);
}
function getHash(
data: string,
{
hashAlgorithm,
hashEncoding,
inputEncoding,
}: {
hashAlgorithm?: string;
hashEncoding?: HexBase64Latin1Encoding;
inputEncoding?: Utf8AsciiLatin1Encoding;
}
): string {
const hash = crypto.createHash(hashAlgorithm ?? 'sha1');
if (inputEncoding) {
hash.update(data, inputEncoding);
} else {
hash.update(data); // use Node's default inputEncoding
}
return hash.digest(hashEncoding ?? 'hex');
}
export function getAsn1Hash(
asn1: forge.asn1.Asn1,
{
hashAlgorithm,
}: {
hashAlgorithm?: string;
}
): string {
const certDer = forge.asn1.toDer(asn1).getBytes(); // binary encoded string
return getHash(certDer, {
hashAlgorithm,
hashEncoding: 'hex',
inputEncoding: 'latin1', // latin1 is an alias for binary
});
}
export function getCertificateFingerprint(
certificate: forge.pki.Certificate,
{
hashAlgorithm,
}: {
hashAlgorithm?: string;
}
): string {
const certAsn1 = forge.pki.certificateToAsn1(certificate);
return getAsn1Hash(certAsn1, {
hashAlgorithm,
});
}
+4 -4
View File
@@ -3,10 +3,6 @@ import { Env } from '@expo/eas-build-job';
import { EasJson } from '@expo/eas-json';
import chalk from 'chalk';
import * as AndroidGraphqlClient from './android/api/GraphqlClient';
import * as IosGraphqlClient from './ios/api/GraphqlClient';
import AppStoreApi from './ios/appstore/AppStoreApi';
import { AuthenticationMode } from './ios/appstore/authenticateTypes';
import { Analytics } from '../analytics/AnalyticsManager';
import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
import Log from '../log';
@@ -14,6 +10,10 @@ import { getPrivateExpoConfig } from '../project/expoConfig';
import { confirmAsync } from '../prompts';
import { Actor } from '../user/User';
import { Client } from '../vcs/vcs';
import * as AndroidGraphqlClient from './android/api/GraphqlClient';
import * as IosGraphqlClient from './ios/api/GraphqlClient';
import AppStoreApi from './ios/appstore/AppStoreApi';
import { AuthenticationMode } from './ios/appstore/authenticateTypes';
export type CredentialsContextProjectInfo = {
exp: ExpoConfig;
@@ -1,6 +1,7 @@
import fs from 'fs-extra';
import path from 'path';
import { Target } from '../ios/types';
import {
AndroidCredentials,
CredentialsJson,
@@ -11,7 +12,6 @@ import {
IosTargetCredentials,
} from './types';
import { getCredentialsJsonPath } from './utils';
import { Target } from '../ios/types';
export async function readAndroidCredentialsAsync(projectDir: string): Promise<AndroidCredentials> {
const credentialsJson = await readAsync(projectDir);
@@ -2,13 +2,6 @@ import fs from 'fs-extra';
import nullthrows from 'nullthrows';
import path from 'path';
import { readRawAsync } from './read';
import {
CredentialsJson,
CredentialsJsonIosCredentials,
CredentialsJsonIosTargetCredentials,
} from './types';
import { getCredentialsJsonPath } from './utils';
import { AndroidAppBuildCredentialsFragment, IosDistributionType } from '../../graphql/generated';
import Log from '../../log';
import { findApplicationTarget, findTargetByName } from '../../project/ios/target';
@@ -17,6 +10,13 @@ import GitClient from '../../vcs/clients/git';
import { Client } from '../../vcs/vcs';
import { CredentialsContext } from '../context';
import { App, Target, TargetCredentials } from '../ios/types';
import { readRawAsync } from './read';
import {
CredentialsJson,
CredentialsJsonIosCredentials,
CredentialsJsonIosTargetCredentials,
} from './types';
import { getCredentialsJsonPath } from './utils';
/**
* Update Android credentials.json with values from www, content of credentials.json
@@ -1,7 +1,7 @@
import path from 'path';
import { IosCredentials } from './types';
import { Target } from '../ios/types';
import { IosCredentials } from './types';
export function getCredentialsJsonPath(projectDir: string): string {
return path.join(projectDir, 'credentials.json');
+1 -4
View File
@@ -11,10 +11,7 @@ export class MissingCredentialsError extends Error {
}
export class UnsupportedCredentialsChoiceError extends Error {
constructor(
message: string,
public choice: string
) {
constructor(message: string, public choice: string) {
super(message);
}
}
@@ -6,11 +6,6 @@ import {
IosEnterpriseProvisioning,
} from '@expo/eas-json';
import { getAppFromContextAsync } from './actions/BuildCredentialsUtils';
import { SetUpBuildCredentials } from './actions/SetUpBuildCredentials';
import { SetUpPushKey } from './actions/SetUpPushKey';
import { App, IosCredentials, Target } from './types';
import { isAdHocProfile, isEnterpriseUniversalProfile } from './utils/provisioningProfile';
import { CommonIosAppCredentialsFragment } from '../../graphql/generated';
import Log from '../../log';
import { findApplicationTarget } from '../../project/ios/target';
@@ -18,6 +13,11 @@ import { selectAsync } from '../../prompts';
import { CredentialsContext } from '../context';
import * as credentialsJsonReader from '../credentialsJson/read';
import { ensureAllTargetsAreConfigured } from '../credentialsJson/utils';
import { getAppFromContextAsync } from './actions/BuildCredentialsUtils';
import { SetUpBuildCredentials } from './actions/SetUpBuildCredentials';
import { SetUpPushKey } from './actions/SetUpPushKey';
import { App, IosCredentials, Target } from './types';
import { isAdHocProfile, isEnterpriseUniversalProfile } from './utils/provisioningProfile';
interface Options {
app: App;
@@ -35,10 +35,7 @@ enum PushNotificationSetupOption {
export default class IosCredentialsProvider {
public readonly platform = Platform.IOS;
constructor(
private ctx: CredentialsContext,
private options: Options
) {}
constructor(private ctx: CredentialsContext, private options: Options) {}
public async getCredentialsAsync(
src: CredentialsSource.LOCAL | CredentialsSource.REMOTE
@@ -3,7 +3,6 @@ import fs from 'fs-extra';
import { nanoid } from 'nanoid';
import path from 'path';
import { formatAppleTeam } from './AppleTeamFormatting';
import { AccountFragment, AppStoreConnectApiKeyFragment } from '../../../graphql/generated';
import Log, { learnMore } from '../../../log';
import { confirmAsync, promptAsync } from '../../../prompts';
@@ -21,6 +20,7 @@ import {
ascApiKeyIssuerIdSchema,
} from '../credentials';
import { isAscApiKeyValidAndTrackedAsync } from '../validators/validateAscApiKey';
import { formatAppleTeam } from './AppleTeamFormatting';
export enum AppStoreApiKeyPurpose {
SUBMISSION_SERVICE = 'EAS Submit',
@@ -1,5 +1,3 @@
import { resolveAppleTeamIfAuthenticatedAsync } from './AppleTeamUtils';
import { AppStoreApiKeyPurpose } from './AscApiKeyUtils';
import {
AppStoreConnectApiKeyFragment,
CommonIosAppCredentialsFragment,
@@ -7,6 +5,8 @@ import {
import Log from '../../../log';
import { CredentialsContext } from '../../context';
import { AppLookupParams } from '../api/graphql/types/AppLookupParams';
import { resolveAppleTeamIfAuthenticatedAsync } from './AppleTeamUtils';
import { AppStoreApiKeyPurpose } from './AscApiKeyUtils';
export class AssignAscApiKey {
constructor(private app: AppLookupParams) {}
@@ -1,8 +1,8 @@
import { resolveAppleTeamIfAuthenticatedAsync } from './AppleTeamUtils';
import { ApplePushKeyFragment, CommonIosAppCredentialsFragment } from '../../../graphql/generated';
import Log from '../../../log';
import { CredentialsContext } from '../../context';
import { AppLookupParams } from '../api/graphql/types/AppLookupParams';
import { resolveAppleTeamIfAuthenticatedAsync } from './AppleTeamUtils';
export class AssignPushKey {
constructor(private app: AppLookupParams) {}
@@ -1,6 +1,5 @@
import nullthrows from 'nullthrows';
import { resolveAppleTeamIfAuthenticatedAsync } from './AppleTeamUtils';
import {
AppleDistributionCertificateFragment,
AppleProvisioningProfileFragment,
@@ -12,6 +11,7 @@ import { getOwnerAccountForProjectIdAsync } from '../../../project/projectUtils'
import { CredentialsContext } from '../../context';
import { AppLookupParams } from '../api/graphql/types/AppLookupParams';
import { App, Target } from '../types';
import { resolveAppleTeamIfAuthenticatedAsync } from './AppleTeamUtils';
export async function getAllBuildCredentialsAsync(
ctx: CredentialsContext,
@@ -1,7 +1,7 @@
import { AppStoreApiKeyPurpose, provideOrGenerateAscApiKeyAsync } from './AscApiKeyUtils';
import { AccountFragment, AppStoreConnectApiKeyFragment } from '../../../graphql/generated';
import Log from '../../../log';
import { CredentialsContext } from '../../context';
import { AppStoreApiKeyPurpose, provideOrGenerateAscApiKeyAsync } from './AscApiKeyUtils';
export class CreateAscApiKey {
constructor(private account: AccountFragment) {}
@@ -1,8 +1,8 @@
import { provideOrGenerateDistributionCertificateAsync } from './DistributionCertificateUtils';
import { AccountFragment } from '../../../graphql/generated';
import Log from '../../../log';
import { CredentialsContext } from '../../context';
import { AppleDistributionCertificateMutationResult } from '../api/graphql/mutations/AppleDistributionCertificateMutation';
import { provideOrGenerateDistributionCertificateAsync } from './DistributionCertificateUtils';
export class CreateDistributionCertificate {
constructor(private account: AccountFragment) {}
@@ -1,8 +1,6 @@
import assert from 'assert';
import nullthrows from 'nullthrows';
import { resolveAppleTeamIfAuthenticatedAsync } from './AppleTeamUtils';
import { generateProvisioningProfileAsync } from './ProvisioningProfileUtils';
import { AppleDistributionCertificateFragment } from '../../../graphql/generated';
import Log from '../../../log';
import { CredentialsContext } from '../../context';
@@ -14,6 +12,8 @@ import { ProvisioningProfile } from '../appstore/Credentials.types';
import { AuthCtx } from '../appstore/authenticateTypes';
import { provisioningProfileSchema } from '../credentials';
import { Target } from '../types';
import { resolveAppleTeamIfAuthenticatedAsync } from './AppleTeamUtils';
import { generateProvisioningProfileAsync } from './ProvisioningProfileUtils';
export class CreateProvisioningProfile {
constructor(
@@ -1,7 +1,7 @@
import { provideOrGeneratePushKeyAsync } from './PushKeyUtils';
import { AccountFragment, ApplePushKeyFragment } from '../../../graphql/generated';
import Log from '../../../log';
import { CredentialsContext } from '../../context';
import { provideOrGeneratePushKeyAsync } from './PushKeyUtils';
export class CreatePushKey {
constructor(private account: AccountFragment) {}
@@ -1,6 +1,6 @@
import { promptAsync } from '../.././../prompts';
import { AppleDevice, AppleDeviceFragment } from '../../../graphql/generated';
import { APPLE_DEVICE_CLASS_LABELS } from '../../../graphql/types/credentials/AppleDevice';
import { promptAsync } from '../.././../prompts';
export async function chooseDevicesAsync(
allDevices: AppleDeviceFragment[],
@@ -2,7 +2,6 @@ import assert from 'assert';
import chalk from 'chalk';
import dateformat from 'dateformat';
import { formatAppleTeam } from './AppleTeamFormatting';
import { AccountFragment, AppleDistributionCertificateFragment } from '../../../graphql/generated';
import Log, { learnMore } from '../../../log';
import { promptAsync } from '../../../prompts';
@@ -18,6 +17,7 @@ import { filterRevokedDistributionCertsFromEasServers } from '../appstore/Creden
import { AppleTooManyCertsError } from '../appstore/distributionCertificate';
import { distributionCertificateSchema } from '../credentials';
import { validateDistributionCertificateAsync } from '../validators/validateDistributionCertificate';
import { formatAppleTeam } from './AppleTeamFormatting';
export function formatDistributionCertificate(
distributionCertificate: AppleDistributionCertificateFragment,
Loaded 100 of 221 files, more files were not shown because too many files have changed in this diff. Show more