mirror of
https://github.com/expo/eas-cli.git
synced 2026-11-14 10:08:06 -10:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1a7d05eb25 | ||
|
|
e8ead3c021 |
No files matched your search
@@ -69,22 +69,16 @@ jobs:
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 20
|
||||
- run: brew install python-setuptools
|
||||
env:
|
||||
HOMEBREW_NO_AUTO_UPDATE: 1
|
||||
- run: yarn install --frozen-lockfile --check-files
|
||||
- run: yarn build
|
||||
- name: Build tarballs
|
||||
working-directory: ${{ github.workspace }}/packages/eas-cli
|
||||
run: |
|
||||
yarn pretarball-ci
|
||||
yarn oclif pack:tarballs --no-xz --targets darwin-x64,darwin-arm64
|
||||
yarn oclif pack:tarballs --no-xz --targets darwin-x64
|
||||
- id: x64
|
||||
run: echo "filename=$(ls eas-*-x64.tar.gz)" >> $GITHUB_OUTPUT
|
||||
working-directory: ${{ github.workspace }}/packages/eas-cli/dist
|
||||
- id: arm64
|
||||
run: echo "filename=$(ls eas-*-arm64.tar.gz)" >> $GITHUB_OUTPUT
|
||||
working-directory: ${{ github.workspace }}/packages/eas-cli/dist
|
||||
- name: Upload darwin-x64 tarball
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
@@ -94,15 +88,6 @@ jobs:
|
||||
asset_path: packages/eas-cli/dist/${{ steps.x64.outputs.filename }}
|
||||
asset_name: ${{ steps.x64.outputs.filename }}
|
||||
asset_content_type: application/gzip
|
||||
- name: Upload darwin-arm64 tarball
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ needs.release.outputs.upload_url }}
|
||||
asset_path: packages/eas-cli/dist/${{ steps.arm64.outputs.filename }}
|
||||
asset_name: ${{ steps.arm64.outputs.filename }}
|
||||
asset_content_type: application/gzip
|
||||
build-windows:
|
||||
name: Build for Windows
|
||||
runs-on: ubuntu-latest
|
||||
@@ -226,16 +211,3 @@ jobs:
|
||||
SLACK_USERNAME: 'EAS CLI CI'
|
||||
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
|
||||
SLACK_FOOTER: ''
|
||||
open-pr-in-universe:
|
||||
name: Open a PR with `@expo/eas-json` bump in universe
|
||||
needs: publish-to-npm
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Open a PR with `@expo/eas-json` version bump in universe
|
||||
uses: benc-uk/workflow-dispatch@v1
|
||||
with:
|
||||
repo: expo/universe
|
||||
ref: main
|
||||
workflow: update-eas-json.yml
|
||||
token: ${{ secrets.EXPO_BOT_PAT }}
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node: ['18', '20', '22']
|
||||
node: ['16', '18', '20']
|
||||
include:
|
||||
- node: '20'
|
||||
coverage: true
|
||||
|
||||
+3
-183
@@ -8,195 +8,15 @@ This is the log of notable changes to EAS CLI and related packages.
|
||||
|
||||
### 🎉 New features
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Remove any mentions of deleted Xcode < 15 images. ([#2438](https://github.com/expo/eas-cli/pull/2438) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
|
||||
## [10.0.2](https://github.com/expo/eas-cli/releases/tag/v10.0.2) - 2024-06-17
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
- Fix parsing of `build.gradle` file by `gradle-to-js` parser by filtering out empty single line comments. ([#2435](https://github.com/expo/eas-cli/pull/2435) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
|
||||
## [10.0.1](https://github.com/expo/eas-cli/releases/tag/v10.0.1) - 2024-06-17
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Add clarification to private-key flag in command line help. ([#2432](https://github.com/expo/eas-cli/pull/2432) by [@quinlanj](https://github.com/quinlanj))
|
||||
|
||||
## [10.0.0](https://github.com/expo/eas-cli/releases/tag/v10.0.0) - 2024-06-13
|
||||
|
||||
### 🛠 Breaking changes
|
||||
|
||||
- Drop support for Node 16. ([#2413](https://github.com/expo/eas-cli/pull/2413) by [@byCedric](https://github.com/byCedric))
|
||||
- Update [`eas-build`](https://github.com/expo/eas-build) dependencies to the version requiring Node 18 as minimal Node version. ([#2416](https://github.com/expo/eas-cli/pull/2416) by [@expo-bot](https://github.com/expo-bot))
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
- Resolve correct submit profile configuration for `eas build` command with `--auto-submit-with-profile` flag. ([#2425](https://github.com/expo/eas-cli/pull/2425) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
- Correctly parse the EXPO_APPLE_PROVIER_ID environment variable. ([#2349](https://github.com/expo/eas-cli/pull/2349) by [@louix](https://github.com/louix))
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Update lockfile to only include `@types/[email protected]`. ([#2412](https://github.com/expo/eas-cli/pull/2412) by [@byCedric](https://github.com/byCedric))
|
||||
- Update test workflow Node versions to 18, 20, and 22. ([#2413](https://github.com/expo/eas-cli/pull/2413) by [@byCedric](https://github.com/byCedric))
|
||||
|
||||
## [9.2.0](https://github.com/expo/eas-cli/releases/tag/v9.2.0) - 2024-06-06
|
||||
|
||||
### 🎉 New features
|
||||
|
||||
- Add `target-profile` and `source-profile` flags to the `eas build:resign` command. ([#2410](https://github.com/expo/eas-cli/pull/2410) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
- Display build profile in the output of `eas build:list`. ([#2408](https://github.com/expo/eas-cli/pull/2408) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
- Use the correct app config for no GitHub flow in `init:onboarding`. ([#2397](https://github.com/expo/eas-cli/pull/2397) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
- Disallow picking expired builds as submit archive source. ([#2406](https://github.com/expo/eas-cli/pull/2406) by [@sjchmiela](https://github.com/sjchmiela))
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Print network error message if present. ([#2407](https://github.com/expo/eas-cli/pull/2407) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
- Make flags for `eas build:list` command more aligned with flags for rest of the commands. ([#2409](https://github.com/expo/eas-cli/pull/2409) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
|
||||
## [9.1.0](https://github.com/expo/eas-cli/releases/tag/v9.1.0) - 2024-05-23
|
||||
|
||||
### 🎉 New features
|
||||
|
||||
- Make `eas init:onboarding` command public. ([#2399](https://github.com/expo/eas-cli/pull/2399) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
|
||||
## [9.0.10](https://github.com/expo/eas-cli/releases/tag/v9.0.10) - 2024-05-22
|
||||
|
||||
## [9.0.9](https://github.com/expo/eas-cli/releases/tag/v9.0.9) - 2024-05-22
|
||||
|
||||
## [9.0.8](https://github.com/expo/eas-cli/releases/tag/v9.0.8) - 2024-05-21
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies. ([#2387](https://github.com/expo/eas-cli/pull/2387) by [@expo-bot](https://github.com/expo-bot))
|
||||
- Improve displaying of device registration QR code. ([#2391](https://github.com/expo/eas-cli/pull/2391) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
|
||||
## [9.0.7](https://github.com/expo/eas-cli/releases/tag/v9.0.7) - 2024-05-17
|
||||
|
||||
## [9.0.6](https://github.com/expo/eas-cli/releases/tag/v9.0.6) - 2024-05-15
|
||||
|
||||
## [9.0.5](https://github.com/expo/eas-cli/releases/tag/v9.0.5) - 2024-05-13
|
||||
|
||||
## [9.0.4](https://github.com/expo/eas-cli/releases/tag/v9.0.4) - 2024-05-13
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Add loader and progress information to the `diagnostics` command. ([#2378](https://github.com/expo/eas-cli/pull/2378) by [@simek](https://github.com/simek))
|
||||
|
||||
## [9.0.3](https://github.com/expo/eas-cli/releases/tag/v9.0.3) - 2024-05-10
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies. ([#2372](https://github.com/expo/eas-cli/pull/2372) by [@expo-bot](https://github.com/expo-bot))
|
||||
|
||||
## [9.0.2](https://github.com/expo/eas-cli/releases/tag/v9.0.2) - 2024-05-09
|
||||
|
||||
## [9.0.1](https://github.com/expo/eas-cli/releases/tag/v9.0.1) - 2024-05-09
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Update image tags in `eas.schema.json`. ([#2363](https://github.com/expo/eas-cli/pull/2363) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
|
||||
## [9.0.0](https://github.com/expo/eas-cli/releases/tag/v9.0.0) - 2024-05-08
|
||||
|
||||
### 🛠 Breaking changes
|
||||
|
||||
- Allow modification of provisioning profile in CI, add --freeze-credentials flag. ([#2347](https://github.com/expo/eas-cli/pull/2347) by [@quinlanj](https://github.com/quinlanj))
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
- Pass env from process.env and build profile to expo-updates CLI calls where applicable. ([#2359](https://github.com/expo/eas-cli/pull/2359) by [@wschurman](https://github.com/wschurman))
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Remove more classic updates code. ([#2357](https://github.com/expo/eas-cli/pull/2357) by [@wschurman](https://github.com/wschurman))
|
||||
- Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies. ([#2360](https://github.com/expo/eas-cli/pull/2360) by [@expo-bot](https://github.com/expo-bot))
|
||||
- Don't pass custom global `"expoCli"` version set in `eas.json` to EAS Build process and warn users when setting it. ([#2361](https://github.com/expo/eas-cli/pull/2361) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
|
||||
## [8.0.0](https://github.com/expo/eas-cli/releases/tag/v8.0.0) - 2024-05-01
|
||||
|
||||
### 🛠 Breaking changes
|
||||
|
||||
- Stop creating a channel on `eas update` and `eas update:roll-back-to-embedded` unless the `--channel` flag is specified. ([#2346](https://github.com/expo/eas-cli/pull/2346) by [@quinlanj](https://github.com/quinlanj))
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
- Improve login info message for other login options. ([#2352](https://github.com/expo/eas-cli/pull/2352) by [@wschurman](https://github.com/wschurman))
|
||||
- Show the -s, --sso option in the login command help. ([#2353](https://github.com/expo/eas-cli/pull/2353) by [@lzkb](https://github.com/lzkb))
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies. ([#2351](https://github.com/expo/eas-cli/pull/2351) by [@expo-bot](https://github.com/expo-bot))
|
||||
- Don't prompt users to set push notifications by default if they don't have the `expo-notifications` installed. ([#2343](https://github.com/expo/eas-cli/pull/2343) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
|
||||
## [7.8.5](https://github.com/expo/eas-cli/releases/tag/v7.8.5) - 2024-04-26
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
- Add explicit workflow arg to expo-update CLI calls. ([#2340](https://github.com/expo/eas-cli/pull/2340) by [@wschurman](https://github.com/wschurman))
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Improve error message if the server returns `UNAUTHORIZED_ERROR`. ([#2345](https://github.com/expo/eas-cli/pull/2345) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
- Fill in min expo-updates version for expo-updates CLI. ([#2344](https://github.com/expo/eas-cli/pull/2344) by [@wschurman](https://github.com/wschurman))
|
||||
|
||||
## [7.8.4](https://github.com/expo/eas-cli/releases/tag/v7.8.4) - 2024-04-24
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Update the list of available Android images. ([#2337](https://github.com/expo/eas-cli/pull/2337) by [@radoslawkrzemien](https://github.com/radoslawkrzemien))
|
||||
- Make multi-select for revoking distribution certificates more readable. ([#2342](https://github.com/expo/eas-cli/pull/2342) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
- Improve error message displayed when EAS CLI version doesn't satisfy minimal version required specified in eas.json. ([#2341](https://github.com/expo/eas-cli/pull/2341) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
|
||||
## [7.8.3](https://github.com/expo/eas-cli/releases/tag/v7.8.3) - 2024-04-23
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
- Don't prompt to set `android.package` and `ios.bundleIdentifier` values when running in non-interactive mode. ([#2336](https://github.com/expo/eas-cli/pull/2336) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Amend credential removal wording. ([#2334](https://github.com/expo/eas-cli/pull/2334) by [@quinlanj](https://github.com/quinlanj))
|
||||
|
||||
## [7.8.2](https://github.com/expo/eas-cli/releases/tag/v7.8.2) - 2024-04-15
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
- Fix display of errors when expo-updates CLI command fails. ([#2324](https://github.com/expo/eas-cli/pull/2324) by [@wschurman](https://github.com/wschurman))
|
||||
- Move credentials endpoints to paginated counterparts. ([#2327](https://github.com/expo/eas-cli/pull/2327) by [@quinlanj](https://github.com/quinlanj))
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Add progress bar for fetching paginated datasets. ([#2326](https://github.com/expo/eas-cli/pull/2326) by [@quinlanj](https://github.com/quinlanj))
|
||||
|
||||
## [7.8.1](https://github.com/expo/eas-cli/releases/tag/v7.8.1) - 2024-04-11
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
- Fix command source files URLs in autogenerated `README`. ([#2318](https://github.com/expo/eas-cli/pull/2318) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies. ([#2316](https://github.com/expo/eas-cli/pull/2316) by [@expo-bot](https://github.com/expo-bot))
|
||||
- Stop querying `Build.resourceClass` field. ([#2320](https://github.com/expo/eas-cli/pull/2320) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
|
||||
## [7.8.0](https://github.com/expo/eas-cli/releases/tag/v7.8.0) - 2024-04-08
|
||||
|
||||
### 🎉 New features
|
||||
|
||||
- Add `auto`, `sdk-50` and `sdk-49` image tags. ([#2298](https://github.com/expo/eas-cli/pull/2298) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
- Add `--build-logger-level` flag to `eas build` command. ([#2313](https://github.com/expo/eas-cli/pull/2313) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Deprecate the `default` image tag. ([#2298](https://github.com/expo/eas-cli/pull/2298) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
- Deprecate iOS images with Xcode version lower then 15. ([#2298](https://github.com/expo/eas-cli/pull/2298) by [@szdziedzic](https://github.com/szdziedzic))
|
||||
- Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies. ([#2315](https://github.com/expo/eas-cli/pull/2315) by [@expo-bot](https://github.com/expo-bot))
|
||||
|
||||
## [7.7.0](https://github.com/expo/eas-cli/releases/tag/v7.7.0) - 2024-04-05
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"npmClient": "yarn",
|
||||
"version": "10.0.2",
|
||||
"version": "7.7.0",
|
||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json"
|
||||
}
|
||||
+105
-188
@@ -94,17 +94,14 @@ eas --help COMMAND
|
||||
* [`eas diagnostics`](#eas-diagnostics)
|
||||
* [`eas help [COMMAND]`](#eas-help-command)
|
||||
* [`eas init`](#eas-init)
|
||||
* [`eas init:onboarding [TARGET_PROJECT_DIRECTORY]`](#eas-initonboarding-target_project_directory)
|
||||
* [`eas login`](#eas-login)
|
||||
* [`eas logout`](#eas-logout)
|
||||
* [`eas metadata:lint`](#eas-metadatalint)
|
||||
* [`eas metadata:pull`](#eas-metadatapull)
|
||||
* [`eas metadata:push`](#eas-metadatapush)
|
||||
* [`eas onboarding [TARGET_PROJECT_DIRECTORY]`](#eas-onboarding-target_project_directory)
|
||||
* [`eas open`](#eas-open)
|
||||
* [`eas project:info`](#eas-projectinfo)
|
||||
* [`eas project:init`](#eas-projectinit)
|
||||
* [`eas project:onboarding [TARGET_PROJECT_DIRECTORY]`](#eas-projectonboarding-target_project_directory)
|
||||
* [`eas secret:create`](#eas-secretcreate)
|
||||
* [`eas secret:delete`](#eas-secretdelete)
|
||||
* [`eas secret:list`](#eas-secretlist)
|
||||
@@ -131,10 +128,7 @@ log in with your Expo account
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ eas account:login [-s]
|
||||
|
||||
FLAGS
|
||||
-s, --sso Login with SSO
|
||||
$ eas account:login
|
||||
|
||||
DESCRIPTION
|
||||
log in with your Expo account
|
||||
@@ -143,7 +137,7 @@ ALIASES
|
||||
$ eas login
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/account/login.ts)_
|
||||
_See code: [src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/account/login.ts)_
|
||||
|
||||
## `eas account:logout`
|
||||
|
||||
@@ -160,7 +154,7 @@ ALIASES
|
||||
$ eas logout
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/account/logout.ts)_
|
||||
_See code: [src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/account/logout.ts)_
|
||||
|
||||
## `eas account:view`
|
||||
|
||||
@@ -177,7 +171,7 @@ ALIASES
|
||||
$ eas whoami
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/account/view.ts)_
|
||||
_See code: [src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/account/view.ts)_
|
||||
|
||||
## `eas analytics [STATUS]`
|
||||
|
||||
@@ -191,7 +185,7 @@ DESCRIPTION
|
||||
display or change analytics settings
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/analytics.ts)_
|
||||
_See code: [src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/analytics.ts)_
|
||||
|
||||
## `eas autocomplete [SHELL]`
|
||||
|
||||
@@ -222,7 +216,7 @@ EXAMPLES
|
||||
$ eas autocomplete --refresh-cache
|
||||
```
|
||||
|
||||
_See code: [@oclif/plugin-autocomplete](https://github.com/oclif/plugin-autocomplete/blob/v2.3.10/packages/eas-cli/src/commands/autocomplete/index.ts)_
|
||||
_See code: [@oclif/plugin-autocomplete](https://github.com/oclif/plugin-autocomplete/blob/v2.3.10/src/commands/autocomplete/index.ts)_
|
||||
|
||||
## `eas branch:create [NAME]`
|
||||
|
||||
@@ -243,7 +237,7 @@ DESCRIPTION
|
||||
create a branch
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/branch/create.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/branch/create.ts)_
|
||||
_See code: [src/commands/branch/create.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/branch/create.ts)_
|
||||
|
||||
## `eas branch:delete [NAME]`
|
||||
|
||||
@@ -264,7 +258,7 @@ DESCRIPTION
|
||||
delete a branch
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/branch/delete.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/branch/delete.ts)_
|
||||
_See code: [src/commands/branch/delete.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/branch/delete.ts)_
|
||||
|
||||
## `eas branch:list`
|
||||
|
||||
@@ -284,7 +278,7 @@ DESCRIPTION
|
||||
list all branches
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/branch/list.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/branch/list.ts)_
|
||||
_See code: [src/commands/branch/list.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/branch/list.ts)_
|
||||
|
||||
## `eas branch:rename`
|
||||
|
||||
@@ -304,7 +298,7 @@ DESCRIPTION
|
||||
rename a branch
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/branch/rename.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/branch/rename.ts)_
|
||||
_See code: [src/commands/branch/rename.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/branch/rename.ts)_
|
||||
|
||||
## `eas branch:view [NAME]`
|
||||
|
||||
@@ -327,7 +321,7 @@ DESCRIPTION
|
||||
view a branch
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/branch/view.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/branch/view.ts)_
|
||||
_See code: [src/commands/branch/view.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/branch/view.ts)_
|
||||
|
||||
## `eas build`
|
||||
|
||||
@@ -336,35 +330,28 @@ start a build
|
||||
```
|
||||
USAGE
|
||||
$ eas build [-p android|ios|all] [-e <value>] [--local] [--output <value>] [--wait] [--clear-cache]
|
||||
[--auto-submit | --auto-submit-with-profile <value>] [-m <value>] [--build-logger-level
|
||||
trace|debug|info|warn|error|fatal] [--freeze-credentials] [--json --non-interactive]
|
||||
[--auto-submit | --auto-submit-with-profile <value>] [-m <value>] [--json --non-interactive]
|
||||
|
||||
FLAGS
|
||||
-e, --profile=PROFILE_NAME Name of the build profile from eas.json. Defaults to
|
||||
"production" if defined in eas.json.
|
||||
-m, --message=<value> A short message describing the build
|
||||
-e, --profile=PROFILE_NAME Name of the build profile from eas.json. Defaults to "production" if defined
|
||||
in eas.json.
|
||||
-m, --message=<value> A short message describing the build
|
||||
-p, --platform=(android|ios|all)
|
||||
--auto-submit Submit on build complete using the submit profile with the
|
||||
same name as the build profile
|
||||
--auto-submit-with-profile=PROFILE_NAME Submit on build complete using the submit profile with
|
||||
provided name
|
||||
--build-logger-level=(trace|debug|info|warn|error|fatal) The level of logs to output during the build process.
|
||||
Defaults to "info".
|
||||
--clear-cache Clear cache before the build
|
||||
--freeze-credentials Prevent the build from updating credentials in
|
||||
non-interactive mode
|
||||
--json Enable JSON output, non-JSON messages will be printed to
|
||||
stderr.
|
||||
--local Run build locally [experimental]
|
||||
--non-interactive Run the command in non-interactive mode.
|
||||
--output=<value> Output path for local build
|
||||
--[no-]wait Wait for build(s) to complete
|
||||
--auto-submit Submit on build complete using the submit profile with the same name as the
|
||||
build profile
|
||||
--auto-submit-with-profile=PROFILE_NAME Submit on build complete using the submit profile with provided name
|
||||
--clear-cache Clear cache before the build
|
||||
--json Enable JSON output, non-JSON messages will be printed to stderr.
|
||||
--local Run build locally [experimental]
|
||||
--non-interactive Run the command in non-interactive mode.
|
||||
--output=<value> Output path for local build
|
||||
--[no-]wait Wait for build(s) to complete
|
||||
|
||||
DESCRIPTION
|
||||
start a build
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/build/index.ts)_
|
||||
_See code: [src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/build/index.ts)_
|
||||
|
||||
## `eas build:cancel [BUILD_ID]`
|
||||
|
||||
@@ -383,7 +370,7 @@ DESCRIPTION
|
||||
cancel a build
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/build/cancel.ts)_
|
||||
_See code: [src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/build/cancel.ts)_
|
||||
|
||||
## `eas build:configure`
|
||||
|
||||
@@ -400,7 +387,7 @@ DESCRIPTION
|
||||
configure the project to support EAS Build
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/build/configure.ts)_
|
||||
_See code: [src/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/build/configure.ts)_
|
||||
|
||||
## `eas build:delete [BUILD_ID]`
|
||||
|
||||
@@ -419,7 +406,7 @@ DESCRIPTION
|
||||
delete a build
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/delete.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/build/delete.ts)_
|
||||
_See code: [src/commands/build/delete.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/build/delete.ts)_
|
||||
|
||||
## `eas build:inspect`
|
||||
|
||||
@@ -454,7 +441,7 @@ DESCRIPTION
|
||||
inspect the state of the project at specific build stages, useful for troubleshooting
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/inspect.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/build/inspect.ts)_
|
||||
_See code: [src/commands/build/inspect.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/build/inspect.ts)_
|
||||
|
||||
## `eas build:list`
|
||||
|
||||
@@ -462,27 +449,20 @@ list all builds for your project
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ eas build:list [-p android|ios|all] [--status
|
||||
$ eas build:list [--platform all|android|ios] [--status
|
||||
new|in-queue|in-progress|pending-cancel|errored|finished|canceled] [--distribution store|internal|simulator]
|
||||
[--channel <value>] [--app-version <value>] [--app-build-version <value>] [--sdk-version <value>] [--runtime-version
|
||||
<value>] [--app-identifier <value>] [-e <value>] [--git-commit-hash <value>] [--offset <value>] [--limit <value>]
|
||||
[--json --non-interactive] [--simulator]
|
||||
[--channel <value>] [--appVersion <value>] [--appBuildVersion <value>] [--sdkVersion <value>] [--runtimeVersion
|
||||
<value>] [--appIdentifier <value>] [--buildProfile <value>] [--gitCommitHash <value>] [--offset <value>] [--limit
|
||||
<value>] [--json --non-interactive] [--simulator]
|
||||
|
||||
FLAGS
|
||||
-e, --build-profile=<value> Filter only builds created with the
|
||||
specified build profile
|
||||
-p, --platform=(android|ios|all)
|
||||
--app-build-version=<value> Filter only builds created with the
|
||||
specified app build version
|
||||
--app-identifier=<value> Filter only builds created with the
|
||||
specified app identifier
|
||||
--app-version=<value> Filter only builds created with the
|
||||
specified main app version
|
||||
--appBuildVersion=<value>
|
||||
--appIdentifier=<value>
|
||||
--appVersion=<value>
|
||||
--buildProfile=<value>
|
||||
--channel=<value>
|
||||
--distribution=(store|internal|simulator) Filter only builds with the specified
|
||||
distribution type
|
||||
--git-commit-hash=<value> Filter only builds created with the
|
||||
specified git commit hash
|
||||
--distribution=(store|internal|simulator)
|
||||
--gitCommitHash=<value>
|
||||
--json Enable JSON output, non-JSON messages
|
||||
will be printed to stderr.
|
||||
--limit=<value> The number of items to fetch each query.
|
||||
@@ -490,21 +470,19 @@ FLAGS
|
||||
--non-interactive Run the command in non-interactive mode.
|
||||
--offset=<value> Start queries from specified index. Use
|
||||
for paginating results. Defaults to 0.
|
||||
--runtime-version=<value> Filter only builds created with the
|
||||
specified runtime version
|
||||
--sdk-version=<value> Filter only builds created with the
|
||||
specified Expo SDK version
|
||||
--platform=(all|android|ios)
|
||||
--runtimeVersion=<value>
|
||||
--sdkVersion=<value>
|
||||
--simulator Filter only iOS simulator builds. Can
|
||||
only be used with --platform flag set to
|
||||
"ios"
|
||||
--status=(new|in-queue|in-progress|pending-cancel|errored|finished|canceled) Filter only builds with the specified
|
||||
status
|
||||
--status=(new|in-queue|in-progress|pending-cancel|errored|finished|canceled)
|
||||
|
||||
DESCRIPTION
|
||||
list all builds for your project
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/build/list.ts)_
|
||||
_See code: [src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/build/list.ts)_
|
||||
|
||||
## `eas build:resign`
|
||||
|
||||
@@ -512,28 +490,25 @@ re-sign a build archive
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ eas build:resign [-p android|ios] [-e <value>] [--source-profile <value>] [--wait] [--id <value>] [--offset
|
||||
<value>] [--limit <value>] [--json --non-interactive]
|
||||
$ eas build:resign [-p android|ios] [-e <value>] [--wait] [--id <value>] [--offset <value>] [--limit <value>]
|
||||
[--json --non-interactive]
|
||||
|
||||
FLAGS
|
||||
-e, --target-profile=PROFILE_NAME Name of the target build profile from eas.json. Credentials and environment
|
||||
variables from this profile will be used when re-signing. Defaults to "production"
|
||||
if defined in eas.json.
|
||||
-e, --profile=PROFILE_NAME Name of the build profile from eas.json. Defaults to "production" if defined in
|
||||
eas.json.
|
||||
-p, --platform=(android|ios)
|
||||
--id=<value> ID of the build to re-sign.
|
||||
--json Enable JSON output, non-JSON messages will be printed to stderr.
|
||||
--limit=<value> The number of items to fetch each query. Defaults to 50 and is capped at 100.
|
||||
--non-interactive Run the command in non-interactive mode.
|
||||
--offset=<value> Start queries from specified index. Use for paginating results. Defaults to 0.
|
||||
--source-profile=PROFILE_NAME Name of the source build profile from eas.json. Used to filter builds eligible for
|
||||
re-signing.
|
||||
--[no-]wait Wait for build(s) to complete.
|
||||
--id=<value> ID of the build to re-sign.
|
||||
--json Enable JSON output, non-JSON messages will be printed to stderr.
|
||||
--limit=<value> The number of items to fetch each query. Defaults to 50 and is capped at 100.
|
||||
--non-interactive Run the command in non-interactive mode.
|
||||
--offset=<value> Start queries from specified index. Use for paginating results. Defaults to 0.
|
||||
--[no-]wait Wait for build(s) to complete.
|
||||
|
||||
DESCRIPTION
|
||||
re-sign a build archive
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/resign.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/build/resign.ts)_
|
||||
_See code: [src/commands/build/resign.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/build/resign.ts)_
|
||||
|
||||
## `eas build:run`
|
||||
|
||||
@@ -559,7 +534,7 @@ DESCRIPTION
|
||||
run simulator/emulator builds from eas-cli
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/run.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/build/run.ts)_
|
||||
_See code: [src/commands/build/run.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/build/run.ts)_
|
||||
|
||||
## `eas build:submit`
|
||||
|
||||
@@ -609,7 +584,7 @@ DESCRIPTION
|
||||
get the latest version from EAS servers
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/version/get.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/build/version/get.ts)_
|
||||
_See code: [src/commands/build/version/get.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/build/version/get.ts)_
|
||||
|
||||
## `eas build:version:set`
|
||||
|
||||
@@ -628,7 +603,7 @@ DESCRIPTION
|
||||
update version of an app
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/version/set.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/build/version/set.ts)_
|
||||
_See code: [src/commands/build/version/set.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/build/version/set.ts)_
|
||||
|
||||
## `eas build:version:sync`
|
||||
|
||||
@@ -647,7 +622,7 @@ DESCRIPTION
|
||||
update a version in native code with a value stored on EAS servers
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/version/sync.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/build/version/sync.ts)_
|
||||
_See code: [src/commands/build/version/sync.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/build/version/sync.ts)_
|
||||
|
||||
## `eas build:view [BUILD_ID]`
|
||||
|
||||
@@ -664,7 +639,7 @@ DESCRIPTION
|
||||
view a build for your project
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/build/view.ts)_
|
||||
_See code: [src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/build/view.ts)_
|
||||
|
||||
## `eas channel:create [NAME]`
|
||||
|
||||
@@ -685,7 +660,7 @@ DESCRIPTION
|
||||
create a channel
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/channel/create.ts)_
|
||||
_See code: [src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/channel/create.ts)_
|
||||
|
||||
## `eas channel:edit [NAME]`
|
||||
|
||||
@@ -707,7 +682,7 @@ DESCRIPTION
|
||||
point a channel at a new branch
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/channel/edit.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/channel/edit.ts)_
|
||||
_See code: [src/commands/channel/edit.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/channel/edit.ts)_
|
||||
|
||||
## `eas channel:list`
|
||||
|
||||
@@ -727,7 +702,7 @@ DESCRIPTION
|
||||
list all channels
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/channel/list.ts)_
|
||||
_See code: [src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/channel/list.ts)_
|
||||
|
||||
## `eas channel:rollout [CHANNEL]`
|
||||
|
||||
@@ -752,15 +727,14 @@ FLAGS
|
||||
--action=create
|
||||
--private-key-path=<value> File containing the PEM-encoded private key corresponding to the certificate
|
||||
in expo-updates' configuration. Defaults to a file named "private-key.pem" in
|
||||
the certificate's directory. Only relevant if you are using code signing:
|
||||
https://docs.expo.dev/eas-update/code-signing/
|
||||
the certificate's directory.
|
||||
--runtime-version=<value> Runtime version to target. Use with --action=create
|
||||
|
||||
DESCRIPTION
|
||||
Roll a new branch out on a channel incrementally.
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/channel/rollout.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/channel/rollout.ts)_
|
||||
_See code: [src/commands/channel/rollout.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/channel/rollout.ts)_
|
||||
|
||||
## `eas channel:view [NAME]`
|
||||
|
||||
@@ -783,7 +757,7 @@ DESCRIPTION
|
||||
view a channel
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/channel/view.ts)_
|
||||
_See code: [src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/channel/view.ts)_
|
||||
|
||||
## `eas config`
|
||||
|
||||
@@ -804,7 +778,7 @@ DESCRIPTION
|
||||
display project configuration (app.json + eas.json)
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/config.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/config.ts)_
|
||||
_See code: [src/commands/config.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/config.ts)_
|
||||
|
||||
## `eas credentials`
|
||||
|
||||
@@ -821,7 +795,7 @@ DESCRIPTION
|
||||
manage credentials
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/credentials/index.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/credentials/index.ts)_
|
||||
_See code: [src/commands/credentials/index.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/credentials/index.ts)_
|
||||
|
||||
## `eas credentials:configure-build`
|
||||
|
||||
@@ -839,7 +813,7 @@ DESCRIPTION
|
||||
Set up credentials for building your project.
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/credentials/configure-build.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/credentials/configure-build.ts)_
|
||||
_See code: [src/commands/credentials/configure-build.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/credentials/configure-build.ts)_
|
||||
|
||||
## `eas device:create`
|
||||
|
||||
@@ -853,7 +827,7 @@ DESCRIPTION
|
||||
register new Apple Devices to use for internal distribution
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/device/create.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/device/create.ts)_
|
||||
_See code: [src/commands/device/create.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/device/create.ts)_
|
||||
|
||||
## `eas device:delete`
|
||||
|
||||
@@ -873,7 +847,7 @@ DESCRIPTION
|
||||
remove a registered device from your account
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/device/delete.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/device/delete.ts)_
|
||||
_See code: [src/commands/device/delete.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/device/delete.ts)_
|
||||
|
||||
## `eas device:list`
|
||||
|
||||
@@ -894,7 +868,7 @@ DESCRIPTION
|
||||
list all registered devices for your account
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/device/list.ts)_
|
||||
_See code: [src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/device/list.ts)_
|
||||
|
||||
## `eas device:rename`
|
||||
|
||||
@@ -915,7 +889,7 @@ DESCRIPTION
|
||||
rename a registered device
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/device/rename.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/device/rename.ts)_
|
||||
_See code: [src/commands/device/rename.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/device/rename.ts)_
|
||||
|
||||
## `eas device:view [UDID]`
|
||||
|
||||
@@ -929,7 +903,7 @@ DESCRIPTION
|
||||
view a device for your project
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/device/view.ts)_
|
||||
_See code: [src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/device/view.ts)_
|
||||
|
||||
## `eas diagnostics`
|
||||
|
||||
@@ -943,7 +917,7 @@ DESCRIPTION
|
||||
display environment info
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/diagnostics.ts)_
|
||||
_See code: [src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/diagnostics.ts)_
|
||||
|
||||
## `eas help [COMMAND]`
|
||||
|
||||
@@ -963,7 +937,7 @@ DESCRIPTION
|
||||
Display help for eas.
|
||||
```
|
||||
|
||||
_See code: [@expo/plugin-help](https://github.com/expo/oclif-plugin-help/blob/v5.1.23/packages/eas-cli/src/commands/help.ts)_
|
||||
_See code: [@expo/plugin-help](https://github.com/expo/oclif-plugin-help/blob/v5.1.23/src/commands/help.ts)_
|
||||
|
||||
## `eas init`
|
||||
|
||||
@@ -985,32 +959,13 @@ ALIASES
|
||||
$ eas init
|
||||
```
|
||||
|
||||
## `eas init:onboarding [TARGET_PROJECT_DIRECTORY]`
|
||||
|
||||
continue onboarding process started on the https://expo.new website.
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ eas init:onboarding [TARGET_PROJECT_DIRECTORY]
|
||||
|
||||
DESCRIPTION
|
||||
continue onboarding process started on the https://expo.new website.
|
||||
|
||||
ALIASES
|
||||
$ eas init:onboarding
|
||||
$ eas onboarding
|
||||
```
|
||||
|
||||
## `eas login`
|
||||
|
||||
log in with your Expo account
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ eas login [-s]
|
||||
|
||||
FLAGS
|
||||
-s, --sso Login with SSO
|
||||
$ eas login
|
||||
|
||||
DESCRIPTION
|
||||
log in with your Expo account
|
||||
@@ -1050,7 +1005,7 @@ DESCRIPTION
|
||||
validate the local store configuration
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/metadata/lint.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/metadata/lint.ts)_
|
||||
_See code: [src/commands/metadata/lint.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/metadata/lint.ts)_
|
||||
|
||||
## `eas metadata:pull`
|
||||
|
||||
@@ -1067,7 +1022,7 @@ DESCRIPTION
|
||||
generate the local store configuration from the app stores
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/metadata/pull.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/metadata/pull.ts)_
|
||||
_See code: [src/commands/metadata/pull.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/metadata/pull.ts)_
|
||||
|
||||
## `eas metadata:push`
|
||||
|
||||
@@ -1084,23 +1039,7 @@ DESCRIPTION
|
||||
sync the local store configuration to the app stores
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/metadata/push.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/metadata/push.ts)_
|
||||
|
||||
## `eas onboarding [TARGET_PROJECT_DIRECTORY]`
|
||||
|
||||
continue onboarding process started on the https://expo.new website.
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ eas onboarding [TARGET_PROJECT_DIRECTORY]
|
||||
|
||||
DESCRIPTION
|
||||
continue onboarding process started on the https://expo.new website.
|
||||
|
||||
ALIASES
|
||||
$ eas init:onboarding
|
||||
$ eas onboarding
|
||||
```
|
||||
_See code: [src/commands/metadata/push.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/metadata/push.ts)_
|
||||
|
||||
## `eas open`
|
||||
|
||||
@@ -1114,7 +1053,7 @@ DESCRIPTION
|
||||
open the project page in a web browser
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/open.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/open.ts)_
|
||||
_See code: [src/commands/open.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/open.ts)_
|
||||
|
||||
## `eas project:info`
|
||||
|
||||
@@ -1128,7 +1067,7 @@ DESCRIPTION
|
||||
information about the current project
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/project/info.ts)_
|
||||
_See code: [src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/project/info.ts)_
|
||||
|
||||
## `eas project:init`
|
||||
|
||||
@@ -1150,25 +1089,7 @@ ALIASES
|
||||
$ eas init
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/project/init.ts)_
|
||||
|
||||
## `eas project:onboarding [TARGET_PROJECT_DIRECTORY]`
|
||||
|
||||
continue onboarding process started on the https://expo.new website.
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ eas project:onboarding [TARGET_PROJECT_DIRECTORY]
|
||||
|
||||
DESCRIPTION
|
||||
continue onboarding process started on the https://expo.new website.
|
||||
|
||||
ALIASES
|
||||
$ eas init:onboarding
|
||||
$ eas onboarding
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/project/onboarding.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/project/onboarding.ts)_
|
||||
_See code: [src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/project/init.ts)_
|
||||
|
||||
## `eas secret:create`
|
||||
|
||||
@@ -1191,7 +1112,7 @@ DESCRIPTION
|
||||
create an environment secret on the current project or owner account
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/secret/create.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/secret/create.ts)_
|
||||
_See code: [src/commands/secret/create.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/secret/create.ts)_
|
||||
|
||||
## `eas secret:delete`
|
||||
|
||||
@@ -1209,7 +1130,7 @@ DESCRIPTION
|
||||
delete an environment secret by ID
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/secret/delete.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/secret/delete.ts)_
|
||||
_See code: [src/commands/secret/delete.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/secret/delete.ts)_
|
||||
|
||||
## `eas secret:list`
|
||||
|
||||
@@ -1223,7 +1144,7 @@ DESCRIPTION
|
||||
list environment secrets available for your current app
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/secret/list.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/secret/list.ts)_
|
||||
_See code: [src/commands/secret/list.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/secret/list.ts)_
|
||||
|
||||
## `eas secret:push`
|
||||
|
||||
@@ -1243,7 +1164,7 @@ DESCRIPTION
|
||||
read environment secrets from env file and store on the server
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/secret/push.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/secret/push.ts)_
|
||||
_See code: [src/commands/secret/push.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/secret/push.ts)_
|
||||
|
||||
## `eas submit`
|
||||
|
||||
@@ -1274,7 +1195,7 @@ ALIASES
|
||||
$ eas build:submit
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/submit.ts)_
|
||||
_See code: [src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/submit.ts)_
|
||||
|
||||
## `eas update`
|
||||
|
||||
@@ -1299,8 +1220,7 @@ FLAGS
|
||||
--non-interactive Run the command in non-interactive mode.
|
||||
--private-key-path=<value> File containing the PEM-encoded private key corresponding to the certificate in
|
||||
expo-updates' configuration. Defaults to a file named "private-key.pem" in the
|
||||
certificate's directory. Only relevant if you are using code signing:
|
||||
https://docs.expo.dev/eas-update/code-signing/
|
||||
certificate's directory.
|
||||
--republish Republish an update group (deprecated, see republish command)
|
||||
--skip-bundler Skip running Expo CLI to bundle the app before publishing
|
||||
|
||||
@@ -1308,7 +1228,7 @@ DESCRIPTION
|
||||
publish an update group
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/update/index.ts)_
|
||||
_See code: [src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/update/index.ts)_
|
||||
|
||||
## `eas update:configure`
|
||||
|
||||
@@ -1326,7 +1246,7 @@ DESCRIPTION
|
||||
configure the project to support EAS Update
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/configure.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/update/configure.ts)_
|
||||
_See code: [src/commands/update/configure.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/update/configure.ts)_
|
||||
|
||||
## `eas update:delete GROUPID`
|
||||
|
||||
@@ -1347,7 +1267,7 @@ DESCRIPTION
|
||||
delete all the updates in an update group
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/delete.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/update/delete.ts)_
|
||||
_See code: [src/commands/update/delete.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/update/delete.ts)_
|
||||
|
||||
## `eas update:list`
|
||||
|
||||
@@ -1369,7 +1289,7 @@ DESCRIPTION
|
||||
view the recent updates
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/update/list.ts)_
|
||||
_See code: [src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/update/list.ts)_
|
||||
|
||||
## `eas update:republish`
|
||||
|
||||
@@ -1390,14 +1310,13 @@ FLAGS
|
||||
--non-interactive Run the command in non-interactive mode.
|
||||
--private-key-path=<value> File containing the PEM-encoded private key corresponding to the certificate in
|
||||
expo-updates' configuration. Defaults to a file named "private-key.pem" in the
|
||||
certificate's directory. Only relevant if you are using code signing:
|
||||
https://docs.expo.dev/eas-update/code-signing/
|
||||
certificate's directory.
|
||||
|
||||
DESCRIPTION
|
||||
roll back to an existing update
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/republish.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/update/republish.ts)_
|
||||
_See code: [src/commands/update/republish.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/update/republish.ts)_
|
||||
|
||||
## `eas update:roll-back-to-embedded`
|
||||
|
||||
@@ -1418,14 +1337,13 @@ FLAGS
|
||||
--non-interactive Run the command in non-interactive mode.
|
||||
--private-key-path=<value> File containing the PEM-encoded private key corresponding to the certificate in
|
||||
expo-updates' configuration. Defaults to a file named "private-key.pem" in the
|
||||
certificate's directory. Only relevant if you are using code signing:
|
||||
https://docs.expo.dev/eas-update/code-signing/
|
||||
certificate's directory.
|
||||
|
||||
DESCRIPTION
|
||||
roll back to the embedded update
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/roll-back-to-embedded.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/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/v7.7.0/src/commands/update/roll-back-to-embedded.ts)_
|
||||
|
||||
## `eas update:rollback`
|
||||
|
||||
@@ -1438,14 +1356,13 @@ USAGE
|
||||
FLAGS
|
||||
--private-key-path=<value> File containing the PEM-encoded private key corresponding to the certificate in
|
||||
expo-updates' configuration. Defaults to a file named "private-key.pem" in the
|
||||
certificate's directory. Only relevant if you are using code signing:
|
||||
https://docs.expo.dev/eas-update/code-signing/
|
||||
certificate's directory.
|
||||
|
||||
DESCRIPTION
|
||||
roll back to an embedded update or an existing update
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/rollback.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/update/rollback.ts)_
|
||||
_See code: [src/commands/update/rollback.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/update/rollback.ts)_
|
||||
|
||||
## `eas update:view GROUPID`
|
||||
|
||||
@@ -1465,7 +1382,7 @@ DESCRIPTION
|
||||
update group details
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/update/view.ts)_
|
||||
_See code: [src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/update/view.ts)_
|
||||
|
||||
## `eas webhook:create`
|
||||
|
||||
@@ -1486,7 +1403,7 @@ DESCRIPTION
|
||||
create a webhook
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/webhook/create.ts)_
|
||||
_See code: [src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/webhook/create.ts)_
|
||||
|
||||
## `eas webhook:delete [ID]`
|
||||
|
||||
@@ -1506,7 +1423,7 @@ DESCRIPTION
|
||||
delete a webhook
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/webhook/delete.ts)_
|
||||
_See code: [src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/webhook/delete.ts)_
|
||||
|
||||
## `eas webhook:list`
|
||||
|
||||
@@ -1524,7 +1441,7 @@ DESCRIPTION
|
||||
list webhooks
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/webhook/list.ts)_
|
||||
_See code: [src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/webhook/list.ts)_
|
||||
|
||||
## `eas webhook:update`
|
||||
|
||||
@@ -1546,7 +1463,7 @@ DESCRIPTION
|
||||
update a webhook
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/webhook/update.ts)_
|
||||
_See code: [src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/webhook/update.ts)_
|
||||
|
||||
## `eas webhook:view ID`
|
||||
|
||||
@@ -1563,7 +1480,7 @@ DESCRIPTION
|
||||
view a webhook
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v10.0.2/packages/eas-cli/src/commands/webhook/view.ts)_
|
||||
_See code: [src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v7.7.0/src/commands/webhook/view.ts)_
|
||||
|
||||
## `eas whoami`
|
||||
|
||||
|
||||
Generated
+1249
-4394
File diff suppressed because it is too large.
Load diff
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "eas-cli",
|
||||
"description": "EAS command line tool",
|
||||
"version": "10.0.2",
|
||||
"version": "7.7.0",
|
||||
"author": "Expo <[email protected]>",
|
||||
"bin": {
|
||||
"eas": "./bin/run"
|
||||
@@ -13,10 +13,9 @@
|
||||
"@expo/config": "8.5.4",
|
||||
"@expo/config-plugins": "7.8.4",
|
||||
"@expo/config-types": "50.0.0",
|
||||
"@expo/eas-build-job": "1.0.117",
|
||||
"@expo/eas-json": "10.0.0",
|
||||
"@expo/eas-build-job": "1.0.95",
|
||||
"@expo/eas-json": "7.7.0",
|
||||
"@expo/json-file": "8.2.37",
|
||||
"@expo/logger": "1.0.117",
|
||||
"@expo/multipart-body-parser": "1.1.0",
|
||||
"@expo/osascript": "2.0.33",
|
||||
"@expo/package-manager": "1.1.2",
|
||||
@@ -28,7 +27,7 @@
|
||||
"@expo/results": "1.0.0",
|
||||
"@expo/rudder-sdk-node": "1.1.1",
|
||||
"@expo/spawn-async": "1.7.0",
|
||||
"@expo/steps": "1.0.118",
|
||||
"@expo/steps": "1.0.95",
|
||||
"@expo/timeago.js": "1.0.0",
|
||||
"@oclif/core": "^1.26.2",
|
||||
"@oclif/plugin-autocomplete": "^2.3.10",
|
||||
@@ -77,7 +76,7 @@
|
||||
"resolve-from": "5.0.0",
|
||||
"semver": "7.5.4",
|
||||
"slash": "3.0.0",
|
||||
"tar": "6.2.1",
|
||||
"tar": "6.2.0",
|
||||
"terminal-link": "2.1.1",
|
||||
"tslib": "2.6.2",
|
||||
"turndown": "7.1.2",
|
||||
@@ -121,7 +120,7 @@
|
||||
"typescript": "5.3.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
"node": ">=16.0.0"
|
||||
},
|
||||
"files": [
|
||||
"/bin",
|
||||
|
||||
@@ -3,7 +3,8 @@ const fs = require('fs/promises');
|
||||
(async () => {
|
||||
// Patch `oclif readme` path and link generation
|
||||
let readmeContent = await fs.readFile('README.md', 'utf8');
|
||||
readmeContent = readmeContent.replace(/src\/commands/g, 'packages/eas-cli/src/commands');
|
||||
readmeContent = readmeContent.replace(/\[build\//g, '[src/');
|
||||
readmeContent = readmeContent.replace(/build\/commands/g, 'packages/eas-cli/src/commands');
|
||||
await fs.writeFile('README.md', readmeContent);
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
|
||||
@@ -24,7 +24,6 @@ export function getMockAppFragment(): AppFragment {
|
||||
return {
|
||||
id: mockProjectId,
|
||||
slug: 'testapp',
|
||||
name: 'testapp',
|
||||
fullName: '@testuser/testpp',
|
||||
ownerAccount: {
|
||||
id: 'test-account-id',
|
||||
|
||||
@@ -3,7 +3,13 @@ import { v4 as uuid } from 'uuid';
|
||||
|
||||
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
import { selectBuildToCancelAsync } from '../../commands/build/cancel';
|
||||
import { AppPlatform, BuildFragment, BuildPriority, BuildStatus } from '../../graphql/generated';
|
||||
import {
|
||||
AppPlatform,
|
||||
BuildFragment,
|
||||
BuildPriority,
|
||||
BuildResourceClass,
|
||||
BuildStatus,
|
||||
} from '../../graphql/generated';
|
||||
import { BuildQuery } from '../../graphql/queries/BuildQuery';
|
||||
import { confirmAsync, selectAsync } from '../../prompts';
|
||||
|
||||
@@ -85,6 +91,7 @@ function createMockBuildFragment({
|
||||
},
|
||||
},
|
||||
status: BuildStatus.InQueue,
|
||||
resourceClass: BuildResourceClass.AndroidMedium,
|
||||
isForIosSimulator: false,
|
||||
};
|
||||
}
|
||||
@@ -3,7 +3,13 @@ import { v4 as uuid } from 'uuid';
|
||||
|
||||
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
import { selectBuildToDeleteAsync } from '../../commands/build/delete';
|
||||
import { AppPlatform, BuildFragment, BuildPriority, BuildStatus } from '../../graphql/generated';
|
||||
import {
|
||||
AppPlatform,
|
||||
BuildFragment,
|
||||
BuildPriority,
|
||||
BuildResourceClass,
|
||||
BuildStatus,
|
||||
} from '../../graphql/generated';
|
||||
import { BuildQuery } from '../../graphql/queries/BuildQuery';
|
||||
import { confirmAsync, selectAsync } from '../../prompts';
|
||||
|
||||
@@ -85,6 +91,7 @@ function createMockBuildFragment({
|
||||
},
|
||||
},
|
||||
status: BuildStatus.InQueue,
|
||||
resourceClass: BuildResourceClass.AndroidMedium,
|
||||
isForIosSimulator: false,
|
||||
};
|
||||
}
|
||||
@@ -107,7 +107,6 @@ export async function prepareAndroidBuildAsync(
|
||||
? false
|
||||
: ctx.buildProfile.autoIncrement,
|
||||
vcsClient: ctx.vcsClient,
|
||||
env: ctx.buildProfile.env,
|
||||
});
|
||||
},
|
||||
prepareJobAsync: async (
|
||||
|
||||
@@ -2,7 +2,6 @@ import { Android } from '@expo/eas-build-job';
|
||||
|
||||
import { AndroidBuildType, AndroidJobInput } from '../../graphql/generated';
|
||||
import {
|
||||
loggerLevelToGraphQLWorkerLoggerLevel,
|
||||
transformBuildMode,
|
||||
transformBuildTrigger,
|
||||
transformProjectArchive,
|
||||
@@ -15,6 +14,7 @@ export function transformJob(job: Android.Job): AndroidJobInput {
|
||||
triggeredBy: transformBuildTrigger(job.triggeredBy),
|
||||
projectArchive: transformProjectArchive(job.projectArchive),
|
||||
projectRootDirectory: job.projectRootDirectory,
|
||||
releaseChannel: job.releaseChannel,
|
||||
updates: job.updates,
|
||||
secrets: job.secrets,
|
||||
builderEnvironment: job.builderEnvironment,
|
||||
@@ -29,9 +29,6 @@ export function transformJob(job: Android.Job): AndroidJobInput {
|
||||
experimental: job.experimental,
|
||||
mode: transformBuildMode(job.mode),
|
||||
customBuildConfig: job.customBuildConfig,
|
||||
loggerLevel: job.loggerLevel
|
||||
? loggerLevelToGraphQLWorkerLoggerLevel[job.loggerLevel]
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -56,15 +56,6 @@ export async function prepareJobAsync(
|
||||
? getCustomBuildConfigPathForJob(buildProfile.config)
|
||||
: undefined;
|
||||
|
||||
let buildMode;
|
||||
if (ctx.repack) {
|
||||
buildMode = BuildMode.REPACK;
|
||||
} else if (buildProfile.config) {
|
||||
buildMode = BuildMode.CUSTOM;
|
||||
} else {
|
||||
buildMode = BuildMode.BUILD;
|
||||
}
|
||||
|
||||
const job: Android.Job = {
|
||||
type: ctx.workflow,
|
||||
platform: Platform.ANDROID,
|
||||
@@ -77,6 +68,7 @@ export async function prepareJobAsync(
|
||||
bun: buildProfile.bun,
|
||||
yarn: buildProfile.yarn,
|
||||
ndk: buildProfile.ndk,
|
||||
expoCli: buildProfile.expoCli,
|
||||
env: buildProfile.env,
|
||||
},
|
||||
cache: {
|
||||
@@ -87,6 +79,7 @@ export async function prepareJobAsync(
|
||||
secrets: {
|
||||
...buildCredentials,
|
||||
},
|
||||
releaseChannel: buildProfile.releaseChannel,
|
||||
updates: { channel: buildProfile.channel },
|
||||
developmentClient: buildProfile.developmentClient,
|
||||
gradleCommand: buildProfile.gradleCommand,
|
||||
@@ -102,19 +95,13 @@ export async function prepareJobAsync(
|
||||
experimental: {
|
||||
prebuildCommand: buildProfile.prebuildCommand,
|
||||
},
|
||||
mode: buildMode,
|
||||
mode: buildProfile.config ? BuildMode.CUSTOM : BuildMode.BUILD,
|
||||
triggeredBy: BuildTrigger.EAS_CLI,
|
||||
...(maybeCustomBuildConfigPath && {
|
||||
customBuildConfig: {
|
||||
path: maybeCustomBuildConfigPath,
|
||||
},
|
||||
}),
|
||||
...(ctx.repack && {
|
||||
customBuildConfig: {
|
||||
path: '__eas/repack.yml',
|
||||
},
|
||||
}),
|
||||
loggerLevel: ctx.loggerLevel,
|
||||
};
|
||||
|
||||
return sanitizeBuildJob(job) as Android.Job;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ExpoConfig } from '@expo/config';
|
||||
import { AndroidConfig } from '@expo/config-plugins';
|
||||
import { Env, Platform, Workflow } from '@expo/eas-build-job';
|
||||
import { Platform, Workflow } from '@expo/eas-build-job';
|
||||
import { AndroidVersionAutoIncrement } from '@expo/eas-json';
|
||||
import chalk from 'chalk';
|
||||
import fs from 'fs-extra';
|
||||
@@ -18,13 +18,11 @@ export async function syncProjectConfigurationAsync({
|
||||
exp,
|
||||
localAutoIncrement,
|
||||
vcsClient,
|
||||
env,
|
||||
}: {
|
||||
projectDir: string;
|
||||
exp: ExpoConfig;
|
||||
localAutoIncrement?: AndroidVersionAutoIncrement;
|
||||
vcsClient: Client;
|
||||
env: Env | undefined;
|
||||
}): Promise<void> {
|
||||
const workflow = await resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient);
|
||||
const versionBumpStrategy = resolveVersionBumpStrategy(localAutoIncrement ?? false);
|
||||
@@ -32,7 +30,7 @@ export async function syncProjectConfigurationAsync({
|
||||
if (workflow === Workflow.GENERIC) {
|
||||
await cleanUpOldEasBuildGradleScriptAsync(projectDir);
|
||||
if (isExpoUpdatesInstalled(projectDir)) {
|
||||
await syncUpdatesConfigurationAsync({ projectDir, exp, workflow, env });
|
||||
await syncUpdatesConfigurationAsync(projectDir, exp);
|
||||
}
|
||||
await bumpVersionAsync({ projectDir, exp, bumpStrategy: versionBumpStrategy });
|
||||
} else {
|
||||
|
||||
@@ -275,23 +275,20 @@ async function uploadProjectAsync<TPlatform extends Platform>(
|
||||
}
|
||||
|
||||
projectTarballPath = projectTarball.path;
|
||||
const [bucketKey, { metadataLocation }] = await Promise.all([
|
||||
uploadFileAtPathToGCSAsync(
|
||||
ctx.graphqlClient,
|
||||
UploadSessionType.EasBuildGcsProjectSources,
|
||||
projectTarball.path,
|
||||
createProgressTracker({
|
||||
total: projectTarball.size,
|
||||
message: ratio =>
|
||||
`Uploading to EAS Build (${formatBytes(
|
||||
projectTarball.size * ratio
|
||||
)} / ${formatBytes(projectTarball.size)})`,
|
||||
completedMessage: (duration: string) => `Uploaded to EAS ${chalk.dim(duration)}`,
|
||||
})
|
||||
),
|
||||
uploadMetadataFileAsync<TPlatform>(projectTarball, ctx),
|
||||
]);
|
||||
|
||||
const bucketKey = await uploadFileAtPathToGCSAsync(
|
||||
ctx.graphqlClient,
|
||||
UploadSessionType.EasBuildGcsProjectSources,
|
||||
projectTarball.path,
|
||||
createProgressTracker({
|
||||
total: projectTarball.size,
|
||||
message: ratio =>
|
||||
`Uploading to EAS Build (${formatBytes(projectTarball.size * ratio)} / ${formatBytes(
|
||||
projectTarball.size
|
||||
)})`,
|
||||
completedMessage: (duration: string) => `Uploaded to EAS ${chalk.dim(duration)}`,
|
||||
})
|
||||
);
|
||||
const { metadataLocation } = await uploadMetadataFileAsync<TPlatform>(projectTarball, ctx);
|
||||
if (metadataLocation) {
|
||||
return { bucketKey, metadataLocation };
|
||||
}
|
||||
@@ -330,7 +327,15 @@ async function uploadMetadataFileAsync<TPlatform extends Platform>(
|
||||
const metadataLocation = await uploadFileAtPathToGCSAsync(
|
||||
ctx.graphqlClient,
|
||||
UploadSessionType.EasBuildGcsProjectMetadata,
|
||||
projectMetadataFile.path
|
||||
projectMetadataFile.path,
|
||||
createProgressTracker({
|
||||
total: projectMetadataFile.size,
|
||||
message: ratio =>
|
||||
`Uploading metadata to EAS Build (${formatBytes(
|
||||
projectMetadataFile!.size * ratio
|
||||
)} / ${formatBytes(projectMetadataFile!.size)})`,
|
||||
completedMessage: (duration: string) => `Uploaded to EAS ${chalk.dim(duration)}`,
|
||||
})
|
||||
);
|
||||
return { metadataLocation };
|
||||
} catch (err: any) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { ExpoConfig } from '@expo/config';
|
||||
import { Platform, Workflow } from '@expo/eas-build-job';
|
||||
import { BuildProfile, EasJson } from '@expo/eas-json';
|
||||
import { LoggerLevel } from '@expo/logger';
|
||||
import { NodePackageManager } from '@expo/package-manager';
|
||||
|
||||
import { LocalBuildOptions } from './local';
|
||||
@@ -61,6 +60,4 @@ export interface BuildContext<T extends Platform> {
|
||||
developmentClient: boolean;
|
||||
requiredPackageManager: NodePackageManager['name'] | null;
|
||||
vcsClient: Client;
|
||||
loggerLevel?: LoggerLevel;
|
||||
repack: boolean;
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
import { Platform } from '@expo/eas-build-job';
|
||||
import { BuildProfile, EasJson, ResourceClass } from '@expo/eas-json';
|
||||
import JsonFile from '@expo/json-file';
|
||||
import { LoggerLevel } from '@expo/logger';
|
||||
import { resolvePackageManager } from '@expo/package-manager';
|
||||
import getenv from 'getenv';
|
||||
import resolveFrom from 'resolve-from';
|
||||
@@ -40,9 +39,6 @@ export async function createBuildContextAsync<T extends Platform>({
|
||||
vcsClient,
|
||||
getDynamicPrivateProjectConfigAsync,
|
||||
customBuildConfigMetadata,
|
||||
buildLoggerLevel,
|
||||
freezeCredentials,
|
||||
repack,
|
||||
}: {
|
||||
buildProfileName: string;
|
||||
buildProfile: BuildProfile<T>;
|
||||
@@ -61,9 +57,6 @@ export async function createBuildContextAsync<T extends Platform>({
|
||||
vcsClient: Client;
|
||||
getDynamicPrivateProjectConfigAsync: DynamicConfigContextFn;
|
||||
customBuildConfigMetadata?: CustomBuildConfigMetadata;
|
||||
buildLoggerLevel?: LoggerLevel;
|
||||
freezeCredentials: boolean;
|
||||
repack: boolean;
|
||||
}): Promise<BuildContext<T>> {
|
||||
const { exp, projectId } = await getDynamicPrivateProjectConfigAsync({ env: buildProfile.env });
|
||||
const projectName = exp.slug;
|
||||
@@ -90,7 +83,6 @@ export async function createBuildContextAsync<T extends Platform>({
|
||||
env: buildProfile.env,
|
||||
easJsonCliConfig,
|
||||
vcsClient,
|
||||
freezeCredentials,
|
||||
});
|
||||
|
||||
const devClientProperties = getDevClientEventProperties({
|
||||
@@ -144,8 +136,6 @@ export async function createBuildContextAsync<T extends Platform>({
|
||||
customBuildConfigMetadata,
|
||||
developmentClient,
|
||||
requiredPackageManager,
|
||||
loggerLevel: buildLoggerLevel,
|
||||
repack,
|
||||
};
|
||||
if (platform === Platform.ANDROID) {
|
||||
const common = commonContext as CommonContext<Platform.ANDROID>;
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
Metadata,
|
||||
Workflow,
|
||||
} from '@expo/eas-build-job';
|
||||
import { LoggerLevel } from '@expo/logger';
|
||||
import assert from 'assert';
|
||||
|
||||
import {
|
||||
@@ -19,7 +18,6 @@ import {
|
||||
BuildTrigger as GraphQLBuildTrigger,
|
||||
ProjectArchiveSourceInput,
|
||||
ProjectArchiveSourceType,
|
||||
WorkerLoggerLevel,
|
||||
} from '../graphql/generated';
|
||||
|
||||
export function transformProjectArchive(archiveSource: ArchiveSource): ProjectArchiveSourceInput {
|
||||
@@ -94,7 +92,6 @@ const buildModeToGraphQLBuildMode: Record<BuildMode, GraphQLBuildMode> = {
|
||||
[BuildMode.BUILD]: GraphQLBuildMode.Build,
|
||||
[BuildMode.CUSTOM]: GraphQLBuildMode.Custom,
|
||||
[BuildMode.RESIGN]: GraphQLBuildMode.Resign,
|
||||
[BuildMode.REPACK]: GraphQLBuildMode.Repack,
|
||||
};
|
||||
|
||||
export function transformBuildMode(buildMode: BuildMode): GraphQLBuildMode {
|
||||
@@ -111,12 +108,3 @@ export function transformBuildTrigger(buildTrigger: BuildTrigger): GraphQLBuildT
|
||||
}
|
||||
throw new Error('Unknown build trigger');
|
||||
}
|
||||
|
||||
export const loggerLevelToGraphQLWorkerLoggerLevel: Record<LoggerLevel, WorkerLoggerLevel> = {
|
||||
[LoggerLevel.TRACE]: WorkerLoggerLevel.Trace,
|
||||
[LoggerLevel.DEBUG]: WorkerLoggerLevel.Debug,
|
||||
[LoggerLevel.INFO]: WorkerLoggerLevel.Info,
|
||||
[LoggerLevel.WARN]: WorkerLoggerLevel.Warn,
|
||||
[LoggerLevel.ERROR]: WorkerLoggerLevel.Error,
|
||||
[LoggerLevel.FATAL]: WorkerLoggerLevel.Fatal,
|
||||
};
|
||||
@@ -89,7 +89,6 @@ export async function prepareIosBuildAsync(
|
||||
? false
|
||||
: ctx.buildProfile.autoIncrement,
|
||||
vcsClient: ctx.vcsClient,
|
||||
env: ctx.buildProfile.env,
|
||||
});
|
||||
},
|
||||
prepareJobAsync: async (
|
||||
|
||||
@@ -3,7 +3,6 @@ import nullthrows from 'nullthrows';
|
||||
|
||||
import { IosJobInput, IosJobSecretsInput } from '../../graphql/generated';
|
||||
import {
|
||||
loggerLevelToGraphQLWorkerLoggerLevel,
|
||||
transformBuildMode,
|
||||
transformBuildTrigger,
|
||||
transformProjectArchive,
|
||||
@@ -16,6 +15,7 @@ export function transformJob(job: Ios.Job): IosJobInput {
|
||||
triggeredBy: transformBuildTrigger(job.triggeredBy),
|
||||
projectArchive: transformProjectArchive(job.projectArchive),
|
||||
projectRootDirectory: nullthrows(job.projectRootDirectory),
|
||||
releaseChannel: job.releaseChannel,
|
||||
updates: job.updates,
|
||||
secrets: job.secrets ? transformIosSecrets(job.secrets) : undefined,
|
||||
builderEnvironment: job.builderEnvironment,
|
||||
@@ -31,9 +31,6 @@ export function transformJob(job: Ios.Job): IosJobInput {
|
||||
experimental: job.experimental,
|
||||
mode: transformBuildMode(job.mode),
|
||||
customBuildConfig: job.customBuildConfig,
|
||||
loggerLevel: job.loggerLevel
|
||||
? loggerLevelToGraphQLWorkerLoggerLevel[job.loggerLevel]
|
||||
: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -48,15 +48,6 @@ export async function prepareJobAsync(
|
||||
? getCustomBuildConfigPathForJob(buildProfile.config)
|
||||
: undefined;
|
||||
|
||||
let buildMode;
|
||||
if (ctx.repack) {
|
||||
buildMode = BuildMode.REPACK;
|
||||
} else if (buildProfile.config) {
|
||||
buildMode = BuildMode.CUSTOM;
|
||||
} else {
|
||||
buildMode = BuildMode.BUILD;
|
||||
}
|
||||
|
||||
const job: Ios.Job = {
|
||||
type: ctx.workflow,
|
||||
platform: Platform.IOS,
|
||||
@@ -71,6 +62,7 @@ export async function prepareJobAsync(
|
||||
bundler: buildProfile.bundler,
|
||||
cocoapods: buildProfile.cocoapods,
|
||||
fastlane: buildProfile.fastlane,
|
||||
expoCli: buildProfile.expoCli,
|
||||
env: buildProfile.env,
|
||||
},
|
||||
cache: {
|
||||
@@ -81,6 +73,7 @@ export async function prepareJobAsync(
|
||||
secrets: {
|
||||
buildCredentials,
|
||||
},
|
||||
releaseChannel: buildProfile.releaseChannel,
|
||||
updates: { channel: buildProfile.channel },
|
||||
developmentClient: buildProfile.developmentClient,
|
||||
simulator: buildProfile.simulator,
|
||||
@@ -97,19 +90,13 @@ export async function prepareJobAsync(
|
||||
experimental: {
|
||||
prebuildCommand: buildProfile.prebuildCommand,
|
||||
},
|
||||
mode: buildMode,
|
||||
mode: buildProfile.config ? BuildMode.CUSTOM : BuildMode.BUILD,
|
||||
triggeredBy: BuildTrigger.EAS_CLI,
|
||||
...(maybeCustomBuildConfigPath && {
|
||||
customBuildConfig: {
|
||||
path: maybeCustomBuildConfigPath,
|
||||
},
|
||||
}),
|
||||
...(ctx.repack && {
|
||||
customBuildConfig: {
|
||||
path: '__eas/repack.yml',
|
||||
},
|
||||
}),
|
||||
loggerLevel: ctx.loggerLevel,
|
||||
};
|
||||
return sanitizeBuildJob(job) as Ios.Job;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ExpoConfig } from '@expo/config';
|
||||
import { Env, Platform, Workflow } from '@expo/eas-build-job';
|
||||
import { Platform, Workflow } from '@expo/eas-build-job';
|
||||
import { IosVersionAutoIncrement } from '@expo/eas-json';
|
||||
|
||||
import { BumpStrategy, bumpVersionAsync, bumpVersionInAppJsonAsync } from './version';
|
||||
@@ -15,21 +15,19 @@ export async function syncProjectConfigurationAsync({
|
||||
targets,
|
||||
localAutoIncrement,
|
||||
vcsClient,
|
||||
env,
|
||||
}: {
|
||||
projectDir: string;
|
||||
exp: ExpoConfig;
|
||||
targets: Target[];
|
||||
localAutoIncrement?: IosVersionAutoIncrement;
|
||||
vcsClient: Client;
|
||||
env: Env | undefined;
|
||||
}): Promise<void> {
|
||||
const workflow = await resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient);
|
||||
const versionBumpStrategy = resolveVersionBumpStrategy(localAutoIncrement ?? false);
|
||||
|
||||
if (workflow === Workflow.GENERIC) {
|
||||
if (isExpoUpdatesInstalled(projectDir)) {
|
||||
await syncUpdatesConfigurationAsync({ vcsClient, projectDir, exp, workflow, env });
|
||||
await syncUpdatesConfigurationAsync(vcsClient, projectDir, exp);
|
||||
}
|
||||
await bumpVersionAsync({ projectDir, exp, bumpStrategy: versionBumpStrategy, targets });
|
||||
} else {
|
||||
|
||||
@@ -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.118';
|
||||
const PLUGIN_PACKAGE_VERSION = '1.0.95';
|
||||
|
||||
export enum LocalBuildMode {
|
||||
/**
|
||||
|
||||
@@ -9,16 +9,26 @@ import { maybeResolveVersionsAsync as maybeResolveIosVersionsAsync } from './ios
|
||||
import { LocalBuildMode } from './local';
|
||||
import { BuildDistributionType } from './types';
|
||||
import Log from '../log';
|
||||
import { getUsername, isExpoUpdatesInstalled } from '../project/projectUtils';
|
||||
import {
|
||||
getUsername,
|
||||
isClassicUpdatesSupportedAsync,
|
||||
isExpoUpdatesInstalled,
|
||||
} from '../project/projectUtils';
|
||||
import { resolveRuntimeVersionAsync } from '../project/resolveRuntimeVersionAsync';
|
||||
import { readChannelSafelyAsync as readAndroidChannelSafelyAsync } from '../update/android/UpdatesModule';
|
||||
import { readChannelSafelyAsync as readIosChannelSafelyAsync } from '../update/ios/UpdatesModule';
|
||||
import {
|
||||
readChannelSafelyAsync as readAndroidChannelSafelyAsync,
|
||||
readReleaseChannelSafelyAsync as readAndroidReleaseChannelSafelyAsync,
|
||||
} from '../update/android/UpdatesModule';
|
||||
import {
|
||||
readChannelSafelyAsync as readIosChannelSafelyAsync,
|
||||
readReleaseChannelSafelyAsync as readIosReleaseChannelSafelyAsync,
|
||||
} from '../update/ios/UpdatesModule';
|
||||
import { easCliVersion } from '../utils/easCli';
|
||||
|
||||
export async function collectMetadataAsync<T extends Platform>(
|
||||
ctx: BuildContext<T>
|
||||
): Promise<Metadata> {
|
||||
const channelObject = await resolveChannelAsync(ctx);
|
||||
const channelOrReleaseChannel = await resolveChannelOrReleaseChannelAsync(ctx);
|
||||
const distribution = ctx.buildProfile.distribution ?? BuildDistributionType.STORE;
|
||||
const metadata: Metadata = {
|
||||
trackingContext: ctx.analyticsEventProperties,
|
||||
@@ -27,17 +37,9 @@ export async function collectMetadataAsync<T extends Platform>(
|
||||
workflow: ctx.workflow,
|
||||
credentialsSource: ctx.buildProfile.credentialsSource,
|
||||
sdkVersion: ctx.exp.sdkVersion,
|
||||
runtimeVersion:
|
||||
(await resolveRuntimeVersionAsync({
|
||||
exp: ctx.exp,
|
||||
platform: ctx.platform,
|
||||
workflow: ctx.workflow,
|
||||
projectDir: ctx.projectDir,
|
||||
env: ctx.buildProfile.env,
|
||||
cwd: ctx.projectDir,
|
||||
})) ?? undefined,
|
||||
runtimeVersion: (await resolveRuntimeVersionAsync(ctx)) ?? undefined,
|
||||
reactNativeVersion: await getReactNativeVersionAsync(ctx.projectDir),
|
||||
...channelObject,
|
||||
...channelOrReleaseChannel,
|
||||
distribution,
|
||||
appName: ctx.exp.name,
|
||||
appIdentifier: resolveAppIdentifier(ctx),
|
||||
@@ -115,9 +117,9 @@ function resolveAppIdentifier<T extends Platform>(ctx: BuildContext<T>): string
|
||||
}
|
||||
}
|
||||
|
||||
async function resolveChannelAsync<T extends Platform>(
|
||||
async function resolveChannelOrReleaseChannelAsync<T extends Platform>(
|
||||
ctx: BuildContext<T>
|
||||
): Promise<{ channel: string } | null> {
|
||||
): Promise<{ channel: string } | { releaseChannel: string } | null> {
|
||||
if (!isExpoUpdatesInstalled(ctx.projectDir)) {
|
||||
return null;
|
||||
}
|
||||
@@ -129,7 +131,31 @@ async function resolveChannelAsync<T extends Platform>(
|
||||
return { channel };
|
||||
}
|
||||
|
||||
return null;
|
||||
if (!(await isClassicUpdatesSupportedAsync(ctx.projectDir))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (ctx.buildProfile.releaseChannel) {
|
||||
return { releaseChannel: ctx.buildProfile.releaseChannel };
|
||||
}
|
||||
|
||||
const releaseChannel = await getNativeReleaseChannelAsync(ctx);
|
||||
return { releaseChannel };
|
||||
}
|
||||
|
||||
async function getNativeReleaseChannelAsync<T extends Platform>(
|
||||
ctx: BuildContext<T>
|
||||
): Promise<string> {
|
||||
switch (ctx.platform) {
|
||||
case Platform.ANDROID: {
|
||||
return (await readAndroidReleaseChannelSafelyAsync(ctx.projectDir)) ?? 'default';
|
||||
}
|
||||
case Platform.IOS: {
|
||||
return (await readIosReleaseChannelSafelyAsync(ctx.projectDir)) ?? 'default';
|
||||
}
|
||||
default:
|
||||
return 'default';
|
||||
}
|
||||
}
|
||||
|
||||
async function getNativeChannelAsync<T extends Platform>(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ExpoConfig } from '@expo/config-types';
|
||||
import { Env, Platform, Workflow } from '@expo/eas-build-job';
|
||||
import { Platform, Workflow } from '@expo/eas-build-job';
|
||||
import {
|
||||
AppVersionSource,
|
||||
BuildProfile,
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
ResourceClass,
|
||||
SubmitProfile,
|
||||
} from '@expo/eas-json';
|
||||
import { LoggerLevel } from '@expo/logger';
|
||||
import assert from 'assert';
|
||||
import chalk from 'chalk';
|
||||
import nullthrows from 'nullthrows';
|
||||
@@ -71,6 +70,7 @@ import {
|
||||
} from '../submit/submit';
|
||||
import { printSubmissionDetailsUrls } from '../submit/utils/urls';
|
||||
import { ensureEASUpdateIsConfiguredAsync } from '../update/configure';
|
||||
import { validateBuildProfileConfigMatchesProjectConfigAsync } from '../update/utils';
|
||||
import { Actor } from '../user/User';
|
||||
import { downloadAndMaybeExtractAppAsync } from '../utils/download';
|
||||
import { truthy } from '../utils/expodash/filter';
|
||||
@@ -93,9 +93,6 @@ export interface BuildFlags {
|
||||
localBuildOptions: LocalBuildOptions;
|
||||
resourceClass?: ResourceClass;
|
||||
message?: string;
|
||||
buildLoggerLevel?: LoggerLevel;
|
||||
freezeCredentials: boolean;
|
||||
repack: boolean;
|
||||
}
|
||||
|
||||
export async function runBuildAndSubmitAsync(
|
||||
@@ -106,9 +103,7 @@ export async function runBuildAndSubmitAsync(
|
||||
flags: BuildFlags,
|
||||
actor: Actor,
|
||||
getDynamicPrivateProjectConfigAsync: DynamicConfigContextFn
|
||||
): Promise<{
|
||||
buildIds: string[];
|
||||
}> {
|
||||
): Promise<void> {
|
||||
await vcsClient.ensureRepoExistsAsync();
|
||||
await ensureRepoIsCleanAsync(vcsClient, flags.nonInteractive);
|
||||
|
||||
@@ -143,6 +138,28 @@ export async function runBuildAndSubmitAsync(
|
||||
`The "image" field in the build profile "${buildProfile.profileName}" is set to "${buildProfile.profile.image}". This tag is deprecated and will be removed in the future. Use other images or tags listed here: https://docs.expo.dev/build-reference/infrastructure/`
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
buildProfile.profile.image &&
|
||||
[
|
||||
'macos-monterey-12.4-xcode-13.4',
|
||||
'macos-monterey-12.3-xcode-13.3',
|
||||
'macos-monterey-12.1-xcode-13.2',
|
||||
'macos-ventura-13.4-xcode-14.3.1',
|
||||
'macos-ventura-13.3-xcode-14.3',
|
||||
'macos-monterey-12.6-xcode-14.2',
|
||||
'macos-monterey-12.6-xcode-14.1',
|
||||
'macos-monterey-12.6-xcode-14.0',
|
||||
].includes(buildProfile.profile.image)
|
||||
) {
|
||||
Log.warn(
|
||||
`The "image" field in the build profile "${buildProfile.profileName}" is set to "${
|
||||
buildProfile.profile.image
|
||||
}". This image is using Xcode in version lower then 15. Apple's new requirement states that starting on April 29th, 2024, apps uploaded to App Store Connect must be built with Xcode 15 for iOS 17, iPadOS 17, tvOS 17, or watchOS 10. Start using Xcode 15 image today by setting "macos-sonoma-14.4-xcode-15.3" or "latest" as your image value. This image will be removed from EAS Build on May 29th, 2024. ${learnMore(
|
||||
'https://expo.dev/changelog/2024/03-29-eas-build-upcoming-ios-images-updates'
|
||||
)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
await ensureExpoDevClientInstalledForDevClientBuildsAsync({
|
||||
@@ -194,9 +211,7 @@ export async function runBuildAndSubmitAsync(
|
||||
}
|
||||
|
||||
if (flags.localBuildOptions.localBuildMode === LocalBuildMode.LOCAL_BUILD_PLUGIN) {
|
||||
return {
|
||||
buildIds: startedBuilds.map(({ build }) => build.id),
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
if (flags.localBuildOptions.localBuildMode === LocalBuildMode.INTERNAL) {
|
||||
@@ -236,7 +251,6 @@ export async function runBuildAndSubmitAsync(
|
||||
buildProfile: startedBuild.buildProfile.profile,
|
||||
submitProfile,
|
||||
nonInteractive: flags.nonInteractive,
|
||||
selectedSubmitProfileName: flags.submitProfile,
|
||||
});
|
||||
startedBuild.build = await BuildQuery.withSubmissionsByIdAsync(
|
||||
graphqlClient,
|
||||
@@ -253,18 +267,14 @@ export async function runBuildAndSubmitAsync(
|
||||
}
|
||||
|
||||
if (flags.localBuildOptions.localBuildMode) {
|
||||
return {
|
||||
buildIds: startedBuilds.map(({ build }) => build.id),
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
if (!flags.wait) {
|
||||
if (flags.json) {
|
||||
printJsonOnlyOutput(startedBuilds.map(buildInfo => buildInfo.build));
|
||||
}
|
||||
return {
|
||||
buildIds: startedBuilds.map(({ build }) => build.id),
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
const { accountName } = Object.values(buildCtxByPlatform)[0];
|
||||
@@ -305,9 +315,6 @@ export async function runBuildAndSubmitAsync(
|
||||
}
|
||||
exitWithNonZeroCodeIfSomeSubmissionsDidntFinish(completedSubmissions);
|
||||
}
|
||||
return {
|
||||
buildIds: startedBuilds.map(({ build }) => build.id),
|
||||
};
|
||||
}
|
||||
|
||||
async function prepareAndStartBuildAsync({
|
||||
@@ -353,9 +360,6 @@ async function prepareAndStartBuildAsync({
|
||||
vcsClient,
|
||||
getDynamicPrivateProjectConfigAsync,
|
||||
customBuildConfigMetadata,
|
||||
buildLoggerLevel: flags.buildLoggerLevel,
|
||||
freezeCredentials: flags.freezeCredentials,
|
||||
repack: flags.repack,
|
||||
});
|
||||
|
||||
if (moreBuilds) {
|
||||
@@ -368,6 +372,12 @@ async function prepareAndStartBuildAsync({
|
||||
);
|
||||
}
|
||||
|
||||
await validateBuildProfileConfigMatchesProjectConfigAsync(
|
||||
buildCtx.exp,
|
||||
buildProfile,
|
||||
buildCtx.projectId,
|
||||
flags.nonInteractive
|
||||
);
|
||||
if (buildProfile.profile.channel) {
|
||||
await validateExpoUpdatesInstalledAsProjectDependencyAsync({
|
||||
exp: buildCtx.exp,
|
||||
@@ -377,7 +387,6 @@ async function prepareAndStartBuildAsync({
|
||||
sdkVersion: buildCtx.exp.sdkVersion,
|
||||
nonInteractive: flags.nonInteractive,
|
||||
buildProfile,
|
||||
env: buildProfile.profile.env,
|
||||
});
|
||||
if (isUsingEASUpdate(buildCtx.exp, buildCtx.projectId)) {
|
||||
const doesChannelExist = await doesChannelExistAsync(graphqlClient, {
|
||||
@@ -432,7 +441,6 @@ async function prepareAndStartSubmissionAsync({
|
||||
projectDir,
|
||||
buildProfile,
|
||||
submitProfile,
|
||||
selectedSubmitProfileName,
|
||||
nonInteractive,
|
||||
}: {
|
||||
build: BuildFragment;
|
||||
@@ -441,7 +449,6 @@ async function prepareAndStartSubmissionAsync({
|
||||
projectDir: string;
|
||||
buildProfile: BuildProfile;
|
||||
submitProfile: SubmitProfile;
|
||||
selectedSubmitProfileName?: string;
|
||||
nonInteractive: boolean;
|
||||
}): Promise<SubmissionFragment> {
|
||||
const platform = toPlatform(build.platform);
|
||||
@@ -461,7 +468,6 @@ async function prepareAndStartSubmissionAsync({
|
||||
exp: buildCtx.exp,
|
||||
vcsClient: buildCtx.vcsClient,
|
||||
isVerboseFastlaneEnabled: false,
|
||||
specifiedProfile: selectedSubmitProfileName,
|
||||
});
|
||||
|
||||
if (moreBuilds) {
|
||||
@@ -525,7 +531,6 @@ async function validateExpoUpdatesInstalledAsProjectDependencyAsync({
|
||||
buildProfile,
|
||||
nonInteractive,
|
||||
sdkVersion,
|
||||
env,
|
||||
}: {
|
||||
exp: ExpoConfig;
|
||||
projectId: string;
|
||||
@@ -534,7 +539,6 @@ async function validateExpoUpdatesInstalledAsProjectDependencyAsync({
|
||||
buildProfile: ProfileData<'build'>;
|
||||
nonInteractive: boolean;
|
||||
sdkVersion?: string;
|
||||
env: Env | undefined;
|
||||
}): Promise<void> {
|
||||
if (isExpoUpdatesInstalledOrAvailable(projectDir, sdkVersion)) {
|
||||
return;
|
||||
@@ -562,7 +566,6 @@ async function validateExpoUpdatesInstalledAsProjectDependencyAsync({
|
||||
projectDir,
|
||||
platform: RequestedPlatform.All,
|
||||
vcsClient,
|
||||
env,
|
||||
});
|
||||
Log.withTick('Installed expo-updates and configured EAS Update.');
|
||||
throw new Error('Command must be re-run to pick up new updates configuration.');
|
||||
|
||||
@@ -39,10 +39,6 @@ export function formatGraphQLBuild(build: BuildFragment): string {
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Profile',
|
||||
value: build.buildProfile,
|
||||
},
|
||||
{
|
||||
label: 'Message',
|
||||
value: build.message,
|
||||
@@ -55,6 +51,10 @@ export function formatGraphQLBuild(build: BuildFragment): string {
|
||||
label: 'Enterprise Provisioning',
|
||||
value: build.iosEnterpriseProvisioning?.toLowerCase(),
|
||||
},
|
||||
{
|
||||
label: 'Release Channel',
|
||||
value: build.releaseChannel,
|
||||
},
|
||||
{
|
||||
label: 'Channel',
|
||||
value: build.channel,
|
||||
|
||||
@@ -100,21 +100,44 @@ export type LocalFile = {
|
||||
};
|
||||
|
||||
export async function makeProjectMetadataFileAsync(archivePath: string): Promise<LocalFile> {
|
||||
const spinner = ora('Creating project metadata file');
|
||||
const timerLabel = 'makeProjectMetadataFileAsync';
|
||||
const timer = setTimeout(
|
||||
() => {
|
||||
spinner.start();
|
||||
},
|
||||
Log.isDebug ? 1 : 1000
|
||||
);
|
||||
startTimer(timerLabel);
|
||||
|
||||
const metadataLocation = path.join(getTmpDirectory(), `${uuidv4()}-eas-build-metadata.json`);
|
||||
const archiveContent: string[] = [];
|
||||
|
||||
await tar.list({
|
||||
file: archivePath,
|
||||
onentry: (entry: tar.ReadEntry) => {
|
||||
if (entry.type === 'File' && !entry.path.includes('.git/')) {
|
||||
archiveContent.push(entry.path);
|
||||
}
|
||||
},
|
||||
});
|
||||
try {
|
||||
await tar.list({
|
||||
file: archivePath,
|
||||
onentry: (entry: tar.ReadEntry) => {
|
||||
if (entry.type === 'File' && !entry.path.includes('.git/')) {
|
||||
archiveContent.push(entry.path);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
await fs.writeJSON(metadataLocation, {
|
||||
archiveContent,
|
||||
});
|
||||
await fs.writeJSON(metadataLocation, {
|
||||
archiveContent,
|
||||
});
|
||||
} catch (e) {
|
||||
clearTimeout(timer);
|
||||
if (spinner.isSpinning) {
|
||||
spinner.fail();
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
clearTimeout(timer);
|
||||
|
||||
const duration = endTimer(timerLabel);
|
||||
const prettyTime = formatMilliseconds(duration);
|
||||
spinner.succeed(`Created project metadata file ${chalk.dim(prettyTime)}`);
|
||||
|
||||
return { path: metadataLocation, size: await fs.stat(metadataLocation).then(stat => stat.size) };
|
||||
}
|
||||
|
||||
@@ -50,31 +50,3 @@ export function getUpdateGroupUrl(
|
||||
getExpoWebsiteBaseUrl()
|
||||
).toString();
|
||||
}
|
||||
|
||||
export function getUpdatePreviewUrl({
|
||||
message,
|
||||
updateRuntimeVersion,
|
||||
createdAt,
|
||||
slug,
|
||||
projectId,
|
||||
group,
|
||||
}: {
|
||||
message?: string;
|
||||
updateRuntimeVersion: string;
|
||||
createdAt: string;
|
||||
slug: string;
|
||||
projectId: string;
|
||||
group: string;
|
||||
}): string {
|
||||
const previewUrl = new URL(`/preview/update`, getExpoWebsiteBaseUrl());
|
||||
if (message) {
|
||||
//previewUrl.searchParams.append('message', message);
|
||||
}
|
||||
|
||||
previewUrl.searchParams.append('updateRuntimeVersion', updateRuntimeVersion);
|
||||
//previewUrl.searchParams.append('createdAt', createdAt);
|
||||
previewUrl.searchParams.append('slug', slug);
|
||||
previewUrl.searchParams.append('projectId', projectId);
|
||||
previewUrl.searchParams.append('group', group);
|
||||
return previewUrl.toString();
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Command } from '@oclif/core';
|
||||
import { CombinedError } from '@urql/core';
|
||||
import chalk from 'chalk';
|
||||
import { GraphQLError } from 'graphql/error';
|
||||
import nullthrows from 'nullthrows';
|
||||
|
||||
@@ -201,7 +200,7 @@ export default abstract class EasCommand extends Command {
|
||||
if (err instanceof EasCommandError) {
|
||||
Log.error(err.message);
|
||||
} else if (err instanceof CombinedError && err?.graphQLErrors) {
|
||||
const cleanGQLErrorsMessage = err?.graphQLErrors
|
||||
const cleanMessage = err?.graphQLErrors
|
||||
.map((graphQLError: GraphQLError) => {
|
||||
const messageLine = graphQLError.message.replace('[GraphQL] ', '');
|
||||
const requestIdLine = graphQLError.extensions?.requestId
|
||||
@@ -211,21 +210,12 @@ export default abstract class EasCommand extends Command {
|
||||
const defaultMsg = `${messageLine}${requestIdLine}`;
|
||||
|
||||
if (graphQLError.extensions?.errorCode === 'UNAUTHORIZED_ERROR') {
|
||||
return `${chalk.bold(
|
||||
`You don't have the required permissions to perform this operation.`
|
||||
)}\n\nThis can sometimes happen if you are logged in as incorrect user.\nRun ${chalk.bold(
|
||||
'eas whoami'
|
||||
)} to check the username you are logged in as.\nRun ${chalk.bold(
|
||||
'eas login'
|
||||
)} to change the account.\n\nOriginal error message: ${defaultMsg}`;
|
||||
return `You don't have the required permissions to perform this operation.\n\n${defaultMsg}`;
|
||||
}
|
||||
|
||||
return defaultMsg;
|
||||
})
|
||||
.join('\n');
|
||||
const cleanMessage = err.networkError
|
||||
? `${cleanGQLErrorsMessage}\n${err.networkError.message}`
|
||||
: cleanGQLErrorsMessage;
|
||||
Log.error(cleanMessage);
|
||||
baseMessage = BASE_GRAPHQL_ERROR_MESSAGE;
|
||||
} else {
|
||||
|
||||
-7
@@ -55,7 +55,6 @@ describe(getProjectIdAsync, () => {
|
||||
],
|
||||
isExpoAdmin: false,
|
||||
featureGates: {},
|
||||
preferences: {},
|
||||
},
|
||||
authenticationInfo: { accessToken: 'fake', sessionSecret: null },
|
||||
});
|
||||
@@ -80,7 +79,6 @@ describe(getProjectIdAsync, () => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: '1234',
|
||||
fullName: '@notnotbrent/test',
|
||||
name: 'test',
|
||||
slug: 'test',
|
||||
ownerAccount: { name: 'notnotbrent' } as any,
|
||||
});
|
||||
@@ -101,7 +99,6 @@ describe(getProjectIdAsync, () => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: '1234',
|
||||
fullName: '@notnotbrent/test',
|
||||
name: 'test',
|
||||
slug: 'test',
|
||||
ownerAccount: { name: 'notnotbrent' } as any,
|
||||
});
|
||||
@@ -126,7 +123,6 @@ describe(getProjectIdAsync, () => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: '1234',
|
||||
fullName: '@totallybrent/test',
|
||||
name: 'test',
|
||||
slug: 'test',
|
||||
ownerAccount: { name: 'totallybrent' } as any,
|
||||
});
|
||||
@@ -175,7 +171,6 @@ describe(getProjectIdAsync, () => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: '1234',
|
||||
fullName: '@totallybrent/test',
|
||||
name: 'test',
|
||||
slug: 'test',
|
||||
ownerAccount: { name: 'totallybrent' } as any,
|
||||
});
|
||||
@@ -200,7 +195,6 @@ describe(getProjectIdAsync, () => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: '1234',
|
||||
fullName: '@notnotbrent/test',
|
||||
name: 'test',
|
||||
slug: 'test',
|
||||
ownerAccount: { name: 'notnotbrent' } as any,
|
||||
});
|
||||
@@ -270,7 +264,6 @@ describe(getProjectIdAsync, () => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: '1234',
|
||||
fullName: '@notnotbrent/test',
|
||||
name: 'test',
|
||||
slug: 'test',
|
||||
ownerAccount: { name: 'notnotbrent' } as any,
|
||||
});
|
||||
|
||||
+1
-5
@@ -15,11 +15,7 @@ async function applyCliConfigAsync(projectDir: string): Promise<void> {
|
||||
const config = await EasJsonUtils.getCliConfigAsync(easJsonAccessor);
|
||||
if (config?.version && !semver.satisfies(easCliVersion, config.version)) {
|
||||
throw new Error(
|
||||
`You are on eas-cli@${easCliVersion} which does not satisfy the CLI version constraint defined in eas.json (${
|
||||
config.version
|
||||
}).\n\nThis error probably means that you need update your eas-cli to a newer version.\nRun ${chalk.bold(
|
||||
'npm install -g eas-cli'
|
||||
)} to update the eas-cli to the latest version.`
|
||||
`You are on eas-cli@${easCliVersion} which does not satisfy the CLI version constraint in eas.json (${config.version})`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ExpoConfig } from '@expo/config-types';
|
||||
import { Env } from '@expo/eas-build-job';
|
||||
import chalk from 'chalk';
|
||||
|
||||
import { ExpoGraphqlClient, createGraphqlClient } from './createGraphqlClient';
|
||||
import { createGraphqlClient } from './createGraphqlClient';
|
||||
import { findProjectRootAsync } from './findProjectDirAndVerifyProjectSetupAsync';
|
||||
import { AppQuery } from '../../../graphql/queries/AppQuery';
|
||||
import Log, { learnMore } from '../../../log';
|
||||
@@ -87,23 +87,6 @@ export async function getProjectIdAsync(
|
||||
});
|
||||
const graphqlClient = createGraphqlClient(authenticationInfo);
|
||||
|
||||
const projectId = await validateOrSetProjectIdAsync({ exp, graphqlClient, actor, options });
|
||||
return projectId;
|
||||
}
|
||||
|
||||
export async function validateOrSetProjectIdAsync({
|
||||
exp,
|
||||
graphqlClient,
|
||||
actor,
|
||||
options,
|
||||
cwd,
|
||||
}: {
|
||||
exp: ExpoConfig;
|
||||
graphqlClient: ExpoGraphqlClient;
|
||||
actor: Actor;
|
||||
options: { env?: Env; nonInteractive: boolean };
|
||||
cwd?: string;
|
||||
}): Promise<string> {
|
||||
const localProjectId = exp.extra?.eas?.projectId;
|
||||
if (localProjectId) {
|
||||
if (typeof localProjectId !== 'string') {
|
||||
@@ -163,9 +146,7 @@ export async function validateOrSetProjectIdAsync({
|
||||
return localProjectId;
|
||||
}
|
||||
|
||||
const projectDir = await findProjectRootAsync({
|
||||
cwd,
|
||||
});
|
||||
const projectDir = await findProjectRootAsync();
|
||||
if (!projectDir) {
|
||||
throw new Error('This command must be run inside a project directory.');
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ export default class AccountLogin extends EasCommand {
|
||||
description: 'Login with SSO',
|
||||
char: 's',
|
||||
default: false,
|
||||
hidden: true,
|
||||
}),
|
||||
};
|
||||
|
||||
|
||||
@@ -74,20 +74,14 @@ export default class BuildConfigure extends EasCommand {
|
||||
if ([RequestedPlatform.Android, RequestedPlatform.All].includes(platform)) {
|
||||
const workflow = await resolveWorkflowAsync(projectDir, Platform.ANDROID, vcsClient);
|
||||
if (workflow === Workflow.GENERIC) {
|
||||
await syncAndroidUpdatesConfigurationAsync({ projectDir, exp, workflow, env: undefined });
|
||||
await syncAndroidUpdatesConfigurationAsync(projectDir, exp);
|
||||
}
|
||||
}
|
||||
|
||||
if ([RequestedPlatform.Ios, RequestedPlatform.All].includes(platform)) {
|
||||
const workflow = await resolveWorkflowAsync(projectDir, Platform.IOS, vcsClient);
|
||||
if (workflow === Workflow.GENERIC) {
|
||||
await syncIosUpdatesConfigurationAsync({
|
||||
vcsClient,
|
||||
projectDir,
|
||||
exp,
|
||||
workflow,
|
||||
env: undefined,
|
||||
});
|
||||
await syncIosUpdatesConfigurationAsync(vcsClient, projectDir, exp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Platform } from '@expo/eas-build-job';
|
||||
import { EasJsonAccessor, EasJsonUtils, ResourceClass } from '@expo/eas-json';
|
||||
import { LoggerLevel } from '@expo/logger';
|
||||
import { Errors, Flags } from '@oclif/core';
|
||||
import chalk from 'chalk';
|
||||
import figures from 'figures';
|
||||
@@ -34,9 +33,6 @@ interface RawBuildFlags {
|
||||
'auto-submit-with-profile'?: string;
|
||||
'resource-class'?: ResourceClass;
|
||||
message?: string;
|
||||
'build-logger-level'?: LoggerLevel;
|
||||
'freeze-credentials': boolean;
|
||||
repack: boolean;
|
||||
}
|
||||
|
||||
export default class Build extends EasCommand {
|
||||
@@ -102,19 +98,6 @@ export default class Build extends EasCommand {
|
||||
char: 'm',
|
||||
description: 'A short message describing the build',
|
||||
}),
|
||||
'build-logger-level': Flags.enum({
|
||||
description: 'The level of logs to output during the build process. Defaults to "info".',
|
||||
options: Object.values(LoggerLevel),
|
||||
}),
|
||||
'freeze-credentials': Flags.boolean({
|
||||
default: false,
|
||||
description: 'Prevent the build from updating credentials in non-interactive mode',
|
||||
}),
|
||||
repack: Flags.boolean({
|
||||
default: false,
|
||||
hidden: true,
|
||||
description: 'Use the golden dev client build repack flow as it works for onboarding',
|
||||
}),
|
||||
...EasNonInteractiveAndJsonFlags,
|
||||
};
|
||||
|
||||
@@ -227,9 +210,6 @@ export default class Build extends EasCommand {
|
||||
submitProfile: flags['auto-submit-with-profile'] ?? profile,
|
||||
resourceClass: flags['resource-class'],
|
||||
message,
|
||||
buildLoggerLevel: flags['build-logger-level'],
|
||||
freezeCredentials: flags['freeze-credentials'],
|
||||
repack: flags.repack,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +105,6 @@ export default class BuildInspect extends EasCommand {
|
||||
projectDir,
|
||||
{
|
||||
nonInteractive: false,
|
||||
freezeCredentials: false,
|
||||
wait: true,
|
||||
clearCache: false,
|
||||
json: false,
|
||||
@@ -120,7 +119,6 @@ export default class BuildInspect extends EasCommand {
|
||||
workingdir: tmpWorkingdir,
|
||||
artifactsDir: path.join(tmpWorkingdir, 'artifacts'),
|
||||
},
|
||||
repack: false,
|
||||
},
|
||||
actor,
|
||||
getDynamicPrivateProjectConfigAsync
|
||||
|
||||
@@ -77,7 +77,6 @@ export default class BuildInternal extends EasCommand {
|
||||
requestedPlatform: flags.platform as RequestedPlatform,
|
||||
profile: flags.profile,
|
||||
nonInteractive: true,
|
||||
freezeCredentials: false,
|
||||
wait: false,
|
||||
clearCache: false,
|
||||
json: true,
|
||||
@@ -86,7 +85,6 @@ export default class BuildInternal extends EasCommand {
|
||||
localBuildMode: LocalBuildMode.INTERNAL,
|
||||
},
|
||||
submitProfile: flags['auto-submit-with-profile'] ?? flags.profile,
|
||||
repack: false,
|
||||
},
|
||||
actor,
|
||||
getDynamicPrivateProjectConfigAsync
|
||||
|
||||
@@ -21,47 +21,34 @@ export default class BuildList extends EasCommand {
|
||||
|
||||
static override flags = {
|
||||
platform: Flags.enum({
|
||||
options: Object.values(RequestedPlatform),
|
||||
char: 'p',
|
||||
options: [RequestedPlatform.All, RequestedPlatform.Android, RequestedPlatform.Ios],
|
||||
}),
|
||||
status: Flags.enum({
|
||||
options: Object.values(BuildStatus),
|
||||
description: 'Filter only builds with the specified status',
|
||||
options: [
|
||||
BuildStatus.NEW,
|
||||
BuildStatus.IN_QUEUE,
|
||||
BuildStatus.IN_PROGRESS,
|
||||
BuildStatus.PENDING_CANCEL,
|
||||
BuildStatus.ERRORED,
|
||||
BuildStatus.FINISHED,
|
||||
BuildStatus.CANCELED,
|
||||
],
|
||||
}),
|
||||
distribution: Flags.enum({
|
||||
options: Object.values(BuildDistributionType),
|
||||
description: 'Filter only builds with the specified distribution type',
|
||||
options: [
|
||||
BuildDistributionType.STORE,
|
||||
BuildDistributionType.INTERNAL,
|
||||
BuildDistributionType.SIMULATOR,
|
||||
],
|
||||
}),
|
||||
channel: Flags.string(),
|
||||
'app-version': Flags.string({
|
||||
aliases: ['appVersion'],
|
||||
description: 'Filter only builds created with the specified main app version',
|
||||
}),
|
||||
'app-build-version': Flags.string({
|
||||
aliases: ['appBuildVersion'],
|
||||
description: 'Filter only builds created with the specified app build version',
|
||||
}),
|
||||
'sdk-version': Flags.string({
|
||||
aliases: ['sdkVersion'],
|
||||
description: 'Filter only builds created with the specified Expo SDK version',
|
||||
}),
|
||||
'runtime-version': Flags.string({
|
||||
aliases: ['runtimeVersion'],
|
||||
description: 'Filter only builds created with the specified runtime version',
|
||||
}),
|
||||
'app-identifier': Flags.string({
|
||||
aliases: ['appIdentifier'],
|
||||
description: 'Filter only builds created with the specified app identifier',
|
||||
}),
|
||||
'build-profile': Flags.string({
|
||||
char: 'e',
|
||||
aliases: ['profile', 'buildProfile'],
|
||||
description: 'Filter only builds created with the specified build profile',
|
||||
}),
|
||||
'git-commit-hash': Flags.string({
|
||||
aliases: ['gitCommitHash'],
|
||||
description: 'Filter only builds created with the specified git commit hash',
|
||||
}),
|
||||
appVersion: Flags.string(),
|
||||
appBuildVersion: Flags.string(),
|
||||
sdkVersion: Flags.string(),
|
||||
runtimeVersion: Flags.string(),
|
||||
appIdentifier: Flags.string(),
|
||||
buildProfile: Flags.string(),
|
||||
gitCommitHash: Flags.string(),
|
||||
...EasPaginatedQueryFlags,
|
||||
limit: getLimitFlagWithCustomValues({ defaultTo: 10, limit: BUILDS_LIMIT }),
|
||||
...EasNonInteractiveAndJsonFlags,
|
||||
@@ -122,13 +109,13 @@ export default class BuildList extends EasCommand {
|
||||
status: graphqlBuildStatus,
|
||||
distribution: graphqlBuildDistribution,
|
||||
channel: flags.channel,
|
||||
appVersion: flags['app-version'],
|
||||
appBuildVersion: flags['app-build-version'],
|
||||
sdkVersion: flags['sdk-version'],
|
||||
runtimeVersion: flags['runtime-version'],
|
||||
appIdentifier: flags['app-identifier'],
|
||||
buildProfile: flags['build-profile'],
|
||||
gitCommitHash: flags['git-commit-hash'],
|
||||
appVersion: flags.appVersion,
|
||||
appBuildVersion: flags.appBuildVersion,
|
||||
sdkVersion: flags.sdkVersion,
|
||||
runtimeVersion: flags.runtimeVersion,
|
||||
appIdentifier: flags.appIdentifier,
|
||||
buildProfile: flags.buildProfile,
|
||||
gitCommitHash: flags.gitCommitHash,
|
||||
simulator: flags.simulator,
|
||||
},
|
||||
paginatedQueryOptions,
|
||||
|
||||
@@ -42,8 +42,7 @@ interface BuildResignFlags {
|
||||
offset?: number;
|
||||
limit?: number;
|
||||
platform?: Platform;
|
||||
targetProfile?: string;
|
||||
sourceProfile?: string;
|
||||
profile?: string;
|
||||
maybeBuildId?: string;
|
||||
wait: boolean;
|
||||
}
|
||||
@@ -53,8 +52,7 @@ interface RawBuildResignFlags {
|
||||
offset: number | undefined;
|
||||
limit: number | undefined;
|
||||
platform: 'android' | 'ios' | undefined;
|
||||
'target-profile': string | undefined;
|
||||
'source-profile': string | undefined;
|
||||
profile: string | undefined;
|
||||
wait: boolean;
|
||||
id: string | undefined;
|
||||
}
|
||||
@@ -67,16 +65,10 @@ export default class BuildResign extends EasCommand {
|
||||
char: 'p',
|
||||
options: ['android', 'ios'],
|
||||
}),
|
||||
'target-profile': Flags.string({
|
||||
profile: Flags.string({
|
||||
char: 'e',
|
||||
description:
|
||||
'Name of the target build profile from eas.json. Credentials and environment variables from this profile will be used when re-signing. Defaults to "production" if defined in eas.json.',
|
||||
helpValue: 'PROFILE_NAME',
|
||||
aliases: ['profile'],
|
||||
}),
|
||||
'source-profile': Flags.string({
|
||||
description:
|
||||
'Name of the source build profile from eas.json. Used to filter builds eligible for re-signing.',
|
||||
'Name of the build profile from eas.json. Defaults to "production" if defined in eas.json.',
|
||||
helpValue: 'PROFILE_NAME',
|
||||
}),
|
||||
wait: Flags.boolean({
|
||||
@@ -138,20 +130,12 @@ export default class BuildResign extends EasCommand {
|
||||
const buildProfile = await EasJsonUtils.getBuildProfileAsync(
|
||||
easJsonAccessor,
|
||||
platform,
|
||||
flags.targetProfile ?? 'production'
|
||||
flags.profile ?? 'production'
|
||||
);
|
||||
const { exp, projectId } = await getDynamicPrivateProjectConfigAsync({ env: buildProfile.env });
|
||||
const account = await getOwnerAccountForProjectIdAsync(graphqlClient, projectId);
|
||||
const build = await this.ensureBuildSelectedAsync(
|
||||
{
|
||||
graphqlClient,
|
||||
projectId,
|
||||
platform,
|
||||
nonInteractive,
|
||||
limit,
|
||||
offset,
|
||||
buildProfile: flags.sourceProfile,
|
||||
},
|
||||
{ graphqlClient, projectId, platform, nonInteractive, limit, offset },
|
||||
maybeBuild
|
||||
);
|
||||
const credentialsCtx = new CredentialsContext({
|
||||
@@ -244,8 +228,7 @@ export default class BuildResign extends EasCommand {
|
||||
offset: flags.offset,
|
||||
limit: flags.limit,
|
||||
platform: flags.platform as Platform | undefined,
|
||||
sourceProfile: flags['source-profile'],
|
||||
targetProfile: flags['target-profile'],
|
||||
profile: flags.profile,
|
||||
maybeBuildId: flags.id,
|
||||
wait: flags.wait,
|
||||
};
|
||||
@@ -259,7 +242,6 @@ export default class BuildResign extends EasCommand {
|
||||
nonInteractive,
|
||||
limit,
|
||||
offset,
|
||||
buildProfile,
|
||||
}: {
|
||||
graphqlClient: ExpoGraphqlClient;
|
||||
projectId: string;
|
||||
@@ -267,7 +249,6 @@ export default class BuildResign extends EasCommand {
|
||||
nonInteractive: boolean;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
buildProfile?: string;
|
||||
},
|
||||
maybeBuild?: BuildFragment
|
||||
): Promise<BuildFragment> {
|
||||
@@ -287,7 +268,6 @@ export default class BuildResign extends EasCommand {
|
||||
distribution: DistributionType.Internal,
|
||||
platform: toAppPlatform(platform),
|
||||
status: BuildStatus.Finished,
|
||||
buildProfile,
|
||||
},
|
||||
});
|
||||
if (!build) {
|
||||
|
||||
@@ -88,7 +88,6 @@ export default class BuildVersionGetView extends EasCommand {
|
||||
buildProfile: profile,
|
||||
platform,
|
||||
vcsClient,
|
||||
nonInteractive: flags['non-interactive'],
|
||||
});
|
||||
const remoteVersions = await AppVersionQuery.latestVersionAsync(
|
||||
graphqlClient,
|
||||
|
||||
@@ -77,7 +77,6 @@ export default class BuildVersionSetView extends EasCommand {
|
||||
buildProfile: profile,
|
||||
platform,
|
||||
vcsClient,
|
||||
nonInteractive: false,
|
||||
});
|
||||
const remoteVersions = await AppVersionQuery.latestVersionAsync(
|
||||
graphqlClient,
|
||||
|
||||
@@ -102,7 +102,6 @@ export default class BuildVersionSyncView extends EasCommand {
|
||||
buildProfile: profileInfo.profile,
|
||||
platform: profileInfo.platform,
|
||||
vcsClient,
|
||||
nonInteractive: false,
|
||||
});
|
||||
const remoteVersions = await AppVersionQuery.latestVersionAsync(
|
||||
graphqlClient,
|
||||
|
||||
@@ -117,7 +117,7 @@ export default class ChannelRollout extends EasCommand {
|
||||
required: false,
|
||||
}),
|
||||
'private-key-path': Flags.string({
|
||||
description: `File containing the PEM-encoded private key corresponding to the certificate in expo-updates' configuration. Defaults to a file named "private-key.pem" in the certificate's directory. Only relevant if you are using code signing: https://docs.expo.dev/eas-update/code-signing/`,
|
||||
description: `File containing the PEM-encoded private key corresponding to the certificate in expo-updates' configuration. Defaults to a file named "private-key.pem" in the certificate's directory.`,
|
||||
required: false,
|
||||
}),
|
||||
...EasNonInteractiveAndJsonFlags,
|
||||
@@ -125,7 +125,6 @@ export default class ChannelRollout extends EasCommand {
|
||||
|
||||
static override contextDefinition = {
|
||||
...this.ContextOptions.ProjectConfig,
|
||||
...this.ContextOptions.Vcs,
|
||||
...this.ContextOptions.LoggedIn,
|
||||
};
|
||||
|
||||
@@ -134,7 +133,6 @@ export default class ChannelRollout extends EasCommand {
|
||||
const argsAndFlags = this.sanitizeArgsAndFlags({ ...flags, ...args });
|
||||
const {
|
||||
privateProjectConfig: { exp, projectId, projectDir },
|
||||
vcsClient,
|
||||
loggedIn: { graphqlClient },
|
||||
} = await this.getContextAsync(ChannelRollout, {
|
||||
nonInteractive: argsAndFlags.nonInteractive,
|
||||
@@ -148,7 +146,6 @@ export default class ChannelRollout extends EasCommand {
|
||||
nonInteractive: argsAndFlags.nonInteractive,
|
||||
graphqlClient,
|
||||
app,
|
||||
vcsClient,
|
||||
};
|
||||
if (argsAndFlags.nonInteractive) {
|
||||
await new NonInteractiveRollout(argsAndFlags).runAsync(ctx);
|
||||
|
||||
@@ -58,8 +58,7 @@ export default class InitializeBuildCredentials extends EasCommand {
|
||||
privateProjectConfig ?? null,
|
||||
getDynamicPrivateProjectConfigAsync,
|
||||
platform,
|
||||
buildProfile,
|
||||
process.cwd()
|
||||
buildProfile
|
||||
).runAsync();
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
import { Platform } from '@expo/eas-build-job';
|
||||
import chalk from 'chalk';
|
||||
import envinfo from 'envinfo';
|
||||
|
||||
import EasCommand from '../commandUtils/EasCommand';
|
||||
import Log from '../log';
|
||||
import { ora } from '../ora';
|
||||
import { resolveWorkflowAsync } from '../project/workflow';
|
||||
import { easCliVersion } from '../utils/easCli';
|
||||
import { Client } from '../vcs/vcs';
|
||||
@@ -22,7 +20,6 @@ export default class Diagnostics extends EasCommand {
|
||||
nonInteractive: true,
|
||||
});
|
||||
|
||||
const spinner = ora().start(`Gathering diagnostic information...`);
|
||||
const info = await envinfo.run(
|
||||
{
|
||||
System: ['OS', 'Shell'],
|
||||
@@ -43,10 +40,9 @@ export default class Diagnostics extends EasCommand {
|
||||
npmGlobalPackages: ['eas-cli', 'expo-cli'],
|
||||
},
|
||||
{
|
||||
title: chalk.bold(`EAS CLI ${easCliVersion} environment info`),
|
||||
title: `EAS CLI ${easCliVersion} environment info`,
|
||||
}
|
||||
);
|
||||
spinner.succeed('All needed information gathered!');
|
||||
|
||||
Log.log(info.trimEnd());
|
||||
await this.printWorkflowAsync(projectDir, vcsClient);
|
||||
@@ -60,7 +56,7 @@ export default class Diagnostics extends EasCommand {
|
||||
if (androidWorkflow === iosWorkflow) {
|
||||
Log.log(` Project workflow: ${androidWorkflow}`);
|
||||
} else {
|
||||
Log.log(` Project workflow:`);
|
||||
Log.log(` Project Workflow:`);
|
||||
Log.log(` Android: ${androidWorkflow}`);
|
||||
Log.log(` iOS: ${iosWorkflow}`);
|
||||
}
|
||||
|
||||
@@ -110,7 +110,6 @@ describe(ProjectInit.name, () => {
|
||||
it('is no-op if already configured for id', async () => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: '1234',
|
||||
name: 'testing-123',
|
||||
slug: 'testing-123',
|
||||
fullName: '@jester/testing-123',
|
||||
ownerAccount: jester.accounts[0],
|
||||
@@ -122,7 +121,6 @@ describe(ProjectInit.name, () => {
|
||||
it('prompts to overwrite when different', async () => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: '1234',
|
||||
name: 'testing-123',
|
||||
slug: 'testing-123',
|
||||
fullName: '@jester/testing-123',
|
||||
ownerAccount: jester.accounts[0],
|
||||
@@ -137,7 +135,6 @@ describe(ProjectInit.name, () => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: '1234',
|
||||
slug: 'testing-123',
|
||||
name: 'testing-123',
|
||||
fullName: '@jester/testing-123',
|
||||
ownerAccount: jester.accounts[0],
|
||||
});
|
||||
@@ -155,7 +152,6 @@ describe(ProjectInit.name, () => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: '1234',
|
||||
slug: 'testing-123',
|
||||
name: 'testing-123',
|
||||
fullName: '@jester/testing-123',
|
||||
ownerAccount: jester.accounts[0],
|
||||
});
|
||||
@@ -190,7 +186,6 @@ describe(ProjectInit.name, () => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: '1234',
|
||||
slug: 'testing-123',
|
||||
name: 'testing-123',
|
||||
fullName: '@jester/testing-123',
|
||||
ownerAccount: jester.accounts[0],
|
||||
});
|
||||
@@ -203,7 +198,6 @@ describe(ProjectInit.name, () => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: '1234',
|
||||
slug: 'testing-124',
|
||||
name: 'testing-123',
|
||||
fullName: '@jester2/testing-124',
|
||||
ownerAccount: jester2.accounts[0],
|
||||
});
|
||||
@@ -229,7 +223,6 @@ describe(ProjectInit.name, () => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: '1234',
|
||||
slug: 'testing-124',
|
||||
name: 'testing-123',
|
||||
fullName: '@jester2/testing-124',
|
||||
ownerAccount: jester2.accounts[0],
|
||||
});
|
||||
@@ -254,7 +247,6 @@ describe(ProjectInit.name, () => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: '1234',
|
||||
slug: 'testing-124',
|
||||
name: 'testing-123',
|
||||
fullName: '@jester2/testing-124',
|
||||
ownerAccount: jester2.accounts[0],
|
||||
});
|
||||
@@ -281,7 +273,6 @@ describe(ProjectInit.name, () => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: '1234',
|
||||
slug: 'testing-123',
|
||||
name: 'testing-123',
|
||||
fullName: '@jester/testing-123',
|
||||
ownerAccount: jester.accounts[0],
|
||||
});
|
||||
@@ -297,7 +288,6 @@ describe(ProjectInit.name, () => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: '1234',
|
||||
slug: 'testing-123',
|
||||
name: 'testing-123',
|
||||
fullName: '@jester/testing-123',
|
||||
ownerAccount: jester.accounts[0],
|
||||
});
|
||||
@@ -312,7 +302,6 @@ describe(ProjectInit.name, () => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: '1234',
|
||||
slug: 'testing-124',
|
||||
name: 'testing-123',
|
||||
fullName: '@jester2/testing-124',
|
||||
ownerAccount: jester2.accounts[0],
|
||||
});
|
||||
@@ -340,7 +329,6 @@ describe(ProjectInit.name, () => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: '1234',
|
||||
slug: 'testing-124',
|
||||
name: 'testing-123',
|
||||
fullName: '@jester2/testing-124',
|
||||
ownerAccount: jester2.accounts[0],
|
||||
});
|
||||
@@ -367,7 +355,6 @@ describe(ProjectInit.name, () => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: '1234',
|
||||
slug: 'testing-124',
|
||||
name: 'testing-123',
|
||||
fullName: '@jester2/testing-124',
|
||||
ownerAccount: jester2.accounts[0],
|
||||
});
|
||||
@@ -397,7 +384,6 @@ describe(ProjectInit.name, () => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: '1234',
|
||||
slug: 'testing-123',
|
||||
name: 'testing-123',
|
||||
fullName: '@jester/testing-123',
|
||||
ownerAccount: jester.accounts[0],
|
||||
});
|
||||
@@ -412,7 +398,6 @@ describe(ProjectInit.name, () => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: '1234',
|
||||
slug: 'testing-124',
|
||||
name: 'testing-123',
|
||||
fullName: '@jester2/testing-124',
|
||||
ownerAccount: jester2.accounts[0],
|
||||
});
|
||||
@@ -452,7 +437,6 @@ describe(ProjectInit.name, () => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: '1234',
|
||||
slug: 'testing-123',
|
||||
name: 'testing-123',
|
||||
fullName: '@jester/testing-123',
|
||||
ownerAccount: jester.accounts[0],
|
||||
});
|
||||
@@ -480,7 +464,6 @@ describe(ProjectInit.name, () => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: '0129',
|
||||
slug: 'testing-123',
|
||||
name: 'testing-123',
|
||||
fullName: '@jester/testing-123',
|
||||
ownerAccount: jester.accounts[0],
|
||||
});
|
||||
|
||||
@@ -1,494 +0,0 @@
|
||||
import { ExpoConfig } from '@expo/config-types';
|
||||
import { Platform } from '@expo/eas-build-job';
|
||||
import { EasJson } from '@expo/eas-json';
|
||||
import chalk from 'chalk';
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
|
||||
import { getEASUpdateURL, getExpoWebsiteBaseUrl } from '../../api';
|
||||
import { runBuildAndSubmitAsync } from '../../build/runBuildAndSubmit';
|
||||
import { reviewAndCommitChangesAsync } from '../../build/utils/repository';
|
||||
import EasCommand from '../../commandUtils/EasCommand';
|
||||
import { DynamicConfigContextFn } from '../../commandUtils/context/DynamicProjectConfigContextField';
|
||||
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
import { validateOrSetProjectIdAsync } from '../../commandUtils/context/contextUtils/getProjectIdAsync';
|
||||
import { CredentialsContextProjectInfo } from '../../credentials/context';
|
||||
import { SetUpBuildCredentialsCommandAction } from '../../credentials/manager/SetUpBuildCredentialsCommandAction';
|
||||
import {
|
||||
AppFragment,
|
||||
AppPlatform,
|
||||
OnboardingDeviceType,
|
||||
OnboardingEnvironment,
|
||||
} from '../../graphql/generated';
|
||||
import { UserPreferencesMutation } from '../../graphql/mutations/UserPreferencesMutation';
|
||||
import { AppQuery } from '../../graphql/queries/AppQuery';
|
||||
import Log, { learnMore, link } from '../../log';
|
||||
import {
|
||||
canAccessRepositoryUsingSshAsync,
|
||||
runGitCloneAsync,
|
||||
runGitPushAsync,
|
||||
} from '../../onboarding/git';
|
||||
import { installDependenciesAsync } from '../../onboarding/installDependencies';
|
||||
import { runCommandAsync } from '../../onboarding/runCommand';
|
||||
import { RequestedPlatform } from '../../platform';
|
||||
import { ExpoConfigOptions, getPrivateExpoConfig } from '../../project/expoConfig';
|
||||
import { promptAsync } from '../../prompts';
|
||||
import { Actor } from '../../user/User';
|
||||
import { easCliVersion } from '../../utils/easCli';
|
||||
import GitClient from '../../vcs/clients/git';
|
||||
|
||||
export default class Onboarding extends EasCommand {
|
||||
static override aliases = ['init:onboarding', 'onboarding'];
|
||||
|
||||
static override description =
|
||||
'continue onboarding process started on the https://expo.new website.';
|
||||
|
||||
static override flags = {};
|
||||
|
||||
static override args = [{ name: 'TARGET_PROJECT_DIRECTORY' }];
|
||||
|
||||
static override contextDefinition = {
|
||||
...this.ContextOptions.LoggedIn,
|
||||
...this.ContextOptions.Analytics,
|
||||
};
|
||||
|
||||
async runAsync(): Promise<void> {
|
||||
const {
|
||||
args: { TARGET_PROJECT_DIRECTORY: targetProjectDirInput },
|
||||
} = await this.parse(Onboarding);
|
||||
|
||||
const {
|
||||
loggedIn: { actor, graphqlClient },
|
||||
analytics,
|
||||
} = await this.getContextAsync(Onboarding, {
|
||||
nonInteractive: false,
|
||||
});
|
||||
|
||||
if (actor.__typename === 'Robot') {
|
||||
throw new Error(
|
||||
'This command is not available for robot users. Make sure you are not using a robot token and try again.'
|
||||
);
|
||||
}
|
||||
|
||||
if (!actor.preferences.onboarding) {
|
||||
throw new Error(
|
||||
'This command can only be run as part of the onboarding process started on the Expo website. Visit https://expo.new to start a new project.'
|
||||
);
|
||||
}
|
||||
|
||||
if (!actor.preferences.onboarding.platform) {
|
||||
throw new Error(
|
||||
'This command can only be run as part of the onboarding process started on the Expo website. It seems like you started an onboarding process, but we are missing some information needed to be filled in before running the eas init:onboarding command (selected platform). Continue the onboarding process on the Expo website.'
|
||||
);
|
||||
}
|
||||
if (!actor.preferences.onboarding.environment) {
|
||||
throw new Error(
|
||||
'This command can only be run as part of the onboarding process started on the Expo website. It seems like you started an onboarding process, but we are missing some information needed to be filled in before running the eas init:onboarding command (selected environment). Continue the onboarding process on the Expo website.'
|
||||
);
|
||||
}
|
||||
if (!actor.preferences.onboarding.deviceType) {
|
||||
throw new Error(
|
||||
'This command can only be run as part of the onboarding process started on the Expo website. It seems like you started an onboarding process, but we are missing some information needed to be filled in before running the eas init:onboarding command (selected device type). Continue the onboarding process on the Expo website.'
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
new Date(actor.preferences.onboarding.lastUsed) < new Date(Date.now() - 1000 * 60 * 60 * 24)
|
||||
) {
|
||||
Log.warn(
|
||||
'It seems like you started an onboarding process, but it has been a while since you last used it. If you want to start a new onboarding process, visit https://expo.new.'
|
||||
);
|
||||
Log.log();
|
||||
}
|
||||
|
||||
const platform =
|
||||
actor.preferences.onboarding.platform === AppPlatform.Android
|
||||
? Platform.ANDROID
|
||||
: Platform.IOS;
|
||||
|
||||
const app = await AppQuery.byIdAsync(graphqlClient, actor.preferences.onboarding.appId);
|
||||
|
||||
const githubUsername = app.githubRepository
|
||||
? app.githubRepository.metadata.githubRepoOwnerName
|
||||
: 'expo';
|
||||
const githubRepositoryName = app.githubRepository
|
||||
? app.githubRepository.metadata.githubRepoName
|
||||
: 'expo-template-default';
|
||||
|
||||
Log.log(`👋 Welcome to Expo, ${actor.username}!`);
|
||||
Log.log();
|
||||
Log.log('✨ We will continue your onboarding process in EAS CLI');
|
||||
Log.log();
|
||||
Log.log(
|
||||
`🚚 Let's start by cloning ${
|
||||
app.githubRepository
|
||||
? `your project (${githubUsername}/${githubRepositoryName})`
|
||||
: `default Expo template project (${githubUsername}/${githubRepositoryName})`
|
||||
} from GitHub and installing dependencies.`
|
||||
);
|
||||
Log.log();
|
||||
let initialTargetProjectDirectory: string;
|
||||
if (targetProjectDirInput) {
|
||||
initialTargetProjectDirectory = targetProjectDirInput;
|
||||
Log.log(`📂 Cloning the project to ${initialTargetProjectDirectory}`);
|
||||
} else {
|
||||
const { selectedTargetProjectDirectory } = await promptAsync({
|
||||
type: 'text',
|
||||
name: 'selectedTargetProjectDirectory',
|
||||
message: app.githubRepository
|
||||
? '📂 Where would you like to clone the project to?'
|
||||
: '📂 Where would you like to create your new project directory?',
|
||||
initial: app.githubRepository
|
||||
? path.join(process.cwd(), githubRepositoryName)
|
||||
: path.join(process.cwd(), `${actor.username}-first-project`),
|
||||
});
|
||||
initialTargetProjectDirectory = selectedTargetProjectDirectory;
|
||||
}
|
||||
Log.log();
|
||||
|
||||
const cloneMethod = (await canAccessRepositoryUsingSshAsync({
|
||||
githubUsername,
|
||||
githubRepositoryName,
|
||||
}))
|
||||
? 'ssh'
|
||||
: 'https';
|
||||
Log.log(chalk.dim(`We detected that ${cloneMethod} is your preffered git clone method`));
|
||||
Log.log();
|
||||
|
||||
const { targetProjectDir: finalTargetProjectDirectory } = await runGitCloneAsync({
|
||||
githubUsername,
|
||||
githubRepositoryName,
|
||||
targetProjectDir: initialTargetProjectDirectory,
|
||||
cloneMethod,
|
||||
});
|
||||
|
||||
const vcsClient = new GitClient(finalTargetProjectDirectory);
|
||||
if (!app.githubRepository) {
|
||||
await fs.remove(path.join(finalTargetProjectDirectory, '.git'));
|
||||
await runCommandAsync({
|
||||
cwd: finalTargetProjectDirectory,
|
||||
command: 'git',
|
||||
args: ['init'],
|
||||
});
|
||||
Log.log();
|
||||
await configureProjectFromBareDefaultExpoTemplateAsync({
|
||||
app,
|
||||
vcsClient,
|
||||
targetDir: finalTargetProjectDirectory,
|
||||
});
|
||||
}
|
||||
|
||||
await installDependenciesAsync({
|
||||
projectDir: finalTargetProjectDirectory,
|
||||
});
|
||||
const exp = await getPrivateExpoConfigWithProjectIdAsync({
|
||||
projectDir: finalTargetProjectDirectory,
|
||||
graphqlClient,
|
||||
actor,
|
||||
});
|
||||
const getDynamicProjectConfigFn = getDynamicPrivateProjectConfigGetter({
|
||||
projectDir: finalTargetProjectDirectory,
|
||||
graphqlClient,
|
||||
actor,
|
||||
});
|
||||
|
||||
if (!app.githubRepository) {
|
||||
await runCommandAsync({
|
||||
cwd: finalTargetProjectDirectory,
|
||||
command: 'npx',
|
||||
args: ['expo', 'install', 'expo-updates'],
|
||||
});
|
||||
Log.log();
|
||||
await runCommandAsync({
|
||||
cwd: finalTargetProjectDirectory,
|
||||
command: 'npx',
|
||||
args: ['expo', 'install', 'expo-insights'],
|
||||
});
|
||||
Log.log();
|
||||
await runCommandAsync({
|
||||
cwd: finalTargetProjectDirectory,
|
||||
command: 'npx',
|
||||
args: ['expo', 'install', 'expo-dev-client'],
|
||||
});
|
||||
Log.log();
|
||||
}
|
||||
await vcsClient.trackFileAsync('package-lock.json');
|
||||
|
||||
const shouldSetupCredentials =
|
||||
((platform === Platform.IOS &&
|
||||
actor.preferences.onboarding.deviceType === OnboardingDeviceType.Device) ||
|
||||
platform === Platform.ANDROID) &&
|
||||
actor.preferences.onboarding.environment === OnboardingEnvironment.DevBuild;
|
||||
if (shouldSetupCredentials) {
|
||||
Log.log('🔑 Now we need to set up build credentials for your project:');
|
||||
await new SetUpBuildCredentialsCommandAction(
|
||||
actor,
|
||||
graphqlClient,
|
||||
vcsClient,
|
||||
analytics,
|
||||
exp,
|
||||
getDynamicProjectConfigFn,
|
||||
platform,
|
||||
actor.preferences.onboarding.deviceType === OnboardingDeviceType.Simulator
|
||||
? 'development-simulator'
|
||||
: 'development',
|
||||
finalTargetProjectDirectory
|
||||
).runAsync();
|
||||
}
|
||||
|
||||
if (app.githubRepository && (await vcsClient.hasUncommittedChangesAsync())) {
|
||||
Log.log(
|
||||
'📦 We will now commit the changes made by the configuration process and push them to GitHub:'
|
||||
);
|
||||
Log.log();
|
||||
Log.log('🔍 Checking for changes in the repository...');
|
||||
await vcsClient.showChangedFilesAsync();
|
||||
await reviewAndCommitChangesAsync(
|
||||
vcsClient,
|
||||
`[eas-onboarding] Install dependencies${
|
||||
shouldSetupCredentials ? ' and set up build credentials' : ''
|
||||
}`,
|
||||
{ nonInteractive: false }
|
||||
);
|
||||
Log.log('📤 Pushing changes to GitHub...');
|
||||
await runGitPushAsync({
|
||||
targetProjectDir: finalTargetProjectDirectory,
|
||||
});
|
||||
} else if (!app.githubRepository) {
|
||||
await runCommandAsync({
|
||||
cwd: finalTargetProjectDirectory,
|
||||
command: 'git',
|
||||
args: ['add', '.'],
|
||||
});
|
||||
Log.log();
|
||||
await runCommandAsync({
|
||||
cwd: finalTargetProjectDirectory,
|
||||
command: 'git',
|
||||
args: ['commit', '-m', 'Initial commit'],
|
||||
});
|
||||
Log.log();
|
||||
}
|
||||
|
||||
Log.log();
|
||||
Log.log('🎉 We finished configuring your project.');
|
||||
Log.log();
|
||||
if (
|
||||
app.githubRepository ||
|
||||
actor.preferences.onboarding.environment === OnboardingEnvironment.ExpoGo
|
||||
) {
|
||||
Log.log('🚀 You can now go back to the website to continue:');
|
||||
const url = new URL(
|
||||
`/onboarding/develop/set-up-project-on-your-machine?project=${app.slug}&accountId=${app.ownerAccount.id}`,
|
||||
getExpoWebsiteBaseUrl()
|
||||
).toString();
|
||||
Log.log(`👉 ${link(url)}`);
|
||||
} else {
|
||||
Log.log('🚀 Now we are going to trigger your first build');
|
||||
Log.log();
|
||||
const { buildIds } = await runBuildAndSubmitAsync(
|
||||
graphqlClient,
|
||||
analytics,
|
||||
vcsClient,
|
||||
finalTargetProjectDirectory,
|
||||
{
|
||||
nonInteractive: true,
|
||||
requestedPlatform:
|
||||
platform === Platform.ANDROID ? RequestedPlatform.Android : RequestedPlatform.Ios,
|
||||
profile:
|
||||
actor.preferences.onboarding.deviceType === OnboardingDeviceType.Simulator
|
||||
? 'development-simulator'
|
||||
: 'development',
|
||||
wait: false,
|
||||
clearCache: false,
|
||||
json: false,
|
||||
autoSubmit: false,
|
||||
localBuildOptions: {},
|
||||
freezeCredentials: false,
|
||||
repack: true,
|
||||
},
|
||||
actor,
|
||||
getDynamicProjectConfigFn
|
||||
);
|
||||
const buildId = buildIds[0];
|
||||
Log.log();
|
||||
Log.log('🚀 You can now go back to the website to continue:');
|
||||
const url = new URL(
|
||||
`/onboarding/develop/set-up-project-on-your-machine?project=${app.slug}&accountId=${app.ownerAccount.id}&buildId=${buildId}`,
|
||||
getExpoWebsiteBaseUrl()
|
||||
).toString();
|
||||
Log.log(`👉 ${link(url)}`);
|
||||
}
|
||||
|
||||
const { __typename, ...previousPreferences } = actor.preferences.onboarding;
|
||||
await UserPreferencesMutation.markCliDoneInOnboardingUserPreferencesAsync(graphqlClient, {
|
||||
...previousPreferences,
|
||||
appId: app.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// we can't get this automated by using command context because when we run a command the project directory doesn't exist yet
|
||||
async function getPrivateExpoConfigWithProjectIdAsync({
|
||||
projectDir,
|
||||
graphqlClient,
|
||||
actor,
|
||||
options,
|
||||
}: {
|
||||
projectDir: string;
|
||||
graphqlClient: ExpoGraphqlClient;
|
||||
actor: Actor;
|
||||
options?: ExpoConfigOptions;
|
||||
}): Promise<CredentialsContextProjectInfo> {
|
||||
const expBefore = getPrivateExpoConfig(projectDir, options);
|
||||
const projectId = await validateOrSetProjectIdAsync({
|
||||
exp: expBefore,
|
||||
graphqlClient,
|
||||
actor,
|
||||
options: {
|
||||
nonInteractive: false,
|
||||
},
|
||||
cwd: projectDir,
|
||||
});
|
||||
const exp = getPrivateExpoConfig(projectDir, options);
|
||||
return {
|
||||
exp,
|
||||
projectId,
|
||||
};
|
||||
}
|
||||
|
||||
// we can't get this automated by using command context because when we run a command the project directory doesn't exist yet
|
||||
function getDynamicPrivateProjectConfigGetter({
|
||||
projectDir,
|
||||
graphqlClient,
|
||||
actor,
|
||||
}: {
|
||||
projectDir: string;
|
||||
graphqlClient: ExpoGraphqlClient;
|
||||
actor: Actor;
|
||||
}): DynamicConfigContextFn {
|
||||
return async (options?: ExpoConfigOptions) => {
|
||||
return {
|
||||
...(await getPrivateExpoConfigWithProjectIdAsync({
|
||||
projectDir,
|
||||
graphqlClient,
|
||||
actor,
|
||||
options,
|
||||
})),
|
||||
projectDir,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
async function configureProjectFromBareDefaultExpoTemplateAsync({
|
||||
app,
|
||||
vcsClient,
|
||||
targetDir,
|
||||
}: {
|
||||
app: AppFragment;
|
||||
vcsClient: GitClient;
|
||||
targetDir: string;
|
||||
}): Promise<void> {
|
||||
// Android package name requires each component to start with a lowercase letter.
|
||||
const isUsernameValidSegment = /^[^a-z]/.test(app.ownerAccount.name);
|
||||
const userPrefix = isUsernameValidSegment ? 'user' : '';
|
||||
const isSlugValidSegment = /^[^a-z]/.test(app.slug);
|
||||
const slugPrefix = isSlugValidSegment ? 'app' : '';
|
||||
|
||||
const bundleIdentifier = `com.${userPrefix}${stripInvalidCharactersForBundleIdentifier(
|
||||
app.ownerAccount.name
|
||||
)}.${slugPrefix}${stripInvalidCharactersForBundleIdentifier(app.slug)}`;
|
||||
const updateUrl = getEASUpdateURL(app.id);
|
||||
|
||||
const easBuildGitHubConfig = {
|
||||
android: {
|
||||
image: 'latest',
|
||||
},
|
||||
ios: {
|
||||
image: 'latest',
|
||||
},
|
||||
};
|
||||
|
||||
const easJson: EasJson = {
|
||||
cli: {
|
||||
version: `>= ${easCliVersion}`,
|
||||
},
|
||||
build: {
|
||||
development: {
|
||||
developmentClient: true,
|
||||
distribution: 'internal',
|
||||
...easBuildGitHubConfig,
|
||||
},
|
||||
'development-simulator': {
|
||||
extends: 'development',
|
||||
ios: {
|
||||
simulator: true,
|
||||
},
|
||||
},
|
||||
preview: {
|
||||
distribution: 'internal',
|
||||
channel: 'main',
|
||||
...easBuildGitHubConfig,
|
||||
},
|
||||
production: {
|
||||
channel: 'production',
|
||||
...easBuildGitHubConfig,
|
||||
},
|
||||
},
|
||||
submit: {
|
||||
production: {},
|
||||
},
|
||||
};
|
||||
|
||||
const easJsonPath = path.join(targetDir, 'eas.json');
|
||||
await fs.writeFile(easJsonPath, `${JSON.stringify(easJson, null, 2)}\n`);
|
||||
await vcsClient.trackFileAsync(easJsonPath);
|
||||
Log.log(
|
||||
`✅ Generated ${chalk.bold('eas.json')}. ${learnMore(
|
||||
'https://docs.expo.dev/build-reference/eas-json/'
|
||||
)}`
|
||||
);
|
||||
Log.log();
|
||||
|
||||
const baseExpoConfig = JSON.parse(await fs.readFile(path.join(targetDir, 'app.json'), 'utf8'))
|
||||
.expo as ExpoConfig;
|
||||
|
||||
const expoConfig: ExpoConfig = {
|
||||
...baseExpoConfig,
|
||||
name: app.name ?? app.slug,
|
||||
slug: app.slug,
|
||||
extra: {
|
||||
eas: {
|
||||
projectId: app.id,
|
||||
},
|
||||
},
|
||||
owner: app.ownerAccount.name,
|
||||
updates: {
|
||||
url: updateUrl,
|
||||
},
|
||||
runtimeVersion: {
|
||||
policy: 'appVersion',
|
||||
},
|
||||
ios: {
|
||||
...baseExpoConfig.ios,
|
||||
bundleIdentifier,
|
||||
},
|
||||
android: {
|
||||
...baseExpoConfig.android,
|
||||
package: bundleIdentifier,
|
||||
},
|
||||
};
|
||||
|
||||
const appJsonPath = path.join(targetDir, 'app.json');
|
||||
await fs.writeFile(appJsonPath, `${JSON.stringify({ expo: expoConfig }, null, 2)}\n`);
|
||||
await vcsClient.trackFileAsync(appJsonPath);
|
||||
Log.log(
|
||||
`✅ Generated ${chalk.bold('app.json')}. ${learnMore(
|
||||
'https://docs.expo.dev/versions/latest/config/app/'
|
||||
)}`
|
||||
);
|
||||
Log.log();
|
||||
}
|
||||
|
||||
function stripInvalidCharactersForBundleIdentifier(string: string): string {
|
||||
return string.replaceAll(/[^A-Za-z0-9]/g, '');
|
||||
}
|
||||
@@ -274,7 +274,6 @@ function mockTestProject({
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: '1234',
|
||||
slug: 'testing-123',
|
||||
name: 'testing-123',
|
||||
fullName: '@jester/testing-123',
|
||||
ownerAccount: jester.accounts[0],
|
||||
});
|
||||
|
||||
@@ -367,7 +367,6 @@ function mockTestProject({
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: '1234',
|
||||
slug: 'testing-123',
|
||||
name: 'testing-123',
|
||||
fullName: '@jester/testing-123',
|
||||
ownerAccount: jester.accounts[0],
|
||||
});
|
||||
|
||||
@@ -259,7 +259,6 @@ function mockTestProject({
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: '1234',
|
||||
slug: 'testing-123',
|
||||
name: 'testing-123',
|
||||
fullName: '@jester/testing-123',
|
||||
ownerAccount: jester.accounts[0],
|
||||
});
|
||||
|
||||
@@ -52,7 +52,6 @@ export default class UpdateConfigure extends EasCommand {
|
||||
projectDir,
|
||||
platform,
|
||||
vcsClient,
|
||||
env: undefined,
|
||||
});
|
||||
|
||||
await ensureEASUpdateIsConfiguredInEasJsonAsync(projectDir);
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
import { Platform as PublishPlatform } from '@expo/config';
|
||||
import { Workflow } from '@expo/eas-build-job';
|
||||
import { Errors, Flags } from '@oclif/core';
|
||||
import chalk from 'chalk';
|
||||
import indentString from 'indent-string';
|
||||
import nullthrows from 'nullthrows';
|
||||
import qrcodeTerminal from 'qrcode-terminal';
|
||||
|
||||
import { ensureBranchExistsAsync } from '../../branch/queries';
|
||||
import { ensureRepoIsCleanAsync } from '../../build/utils/repository';
|
||||
import { getUpdateGroupUrl, getUpdatePreviewUrl } from '../../build/utils/url';
|
||||
import { getUpdateGroupUrl } from '../../build/utils/url';
|
||||
import { ensureChannelExistsAsync } from '../../channel/queries';
|
||||
import EasCommand from '../../commandUtils/EasCommand';
|
||||
import { EasNonInteractiveAndJsonFlags } from '../../commandUtils/flags';
|
||||
import { getPaginatedQueryOptions } from '../../commandUtils/pagination';
|
||||
@@ -42,7 +40,6 @@ import {
|
||||
resolveInputDirectoryAsync,
|
||||
uploadAssetsAsync,
|
||||
} from '../../project/publish';
|
||||
import { resolveWorkflowPerPlatformAsync } from '../../project/workflow';
|
||||
import { ensureEASUpdateIsConfiguredAsync } from '../../update/configure';
|
||||
import { getUpdateJsonInfosForUpdates } from '../../update/utils';
|
||||
import {
|
||||
@@ -143,7 +140,7 @@ export default class UpdatePublish extends EasCommand {
|
||||
default: false,
|
||||
}),
|
||||
'private-key-path': Flags.string({
|
||||
description: `File containing the PEM-encoded private key corresponding to the certificate in expo-updates' configuration. Defaults to a file named "private-key.pem" in the certificate's directory. Only relevant if you are using code signing: https://docs.expo.dev/eas-update/code-signing/`,
|
||||
description: `File containing the PEM-encoded private key corresponding to the certificate in expo-updates' configuration. Defaults to a file named "private-key.pem" in the certificate's directory.`,
|
||||
required: false,
|
||||
}),
|
||||
...EasNonInteractiveAndJsonFlags,
|
||||
@@ -202,7 +199,6 @@ export default class UpdatePublish extends EasCommand {
|
||||
projectDir,
|
||||
projectId,
|
||||
vcsClient,
|
||||
env: undefined,
|
||||
});
|
||||
|
||||
const { exp } = await getDynamicPublicProjectConfigAsync();
|
||||
@@ -363,24 +359,29 @@ export default class UpdatePublish extends EasCommand {
|
||||
throw e;
|
||||
}
|
||||
|
||||
const workflows = await resolveWorkflowPerPlatformAsync(projectDir, vcsClient);
|
||||
const runtimeVersions = await getRuntimeVersionObjectAsync({
|
||||
exp,
|
||||
platforms: realizedPlatforms,
|
||||
projectDir,
|
||||
workflows: {
|
||||
...workflows,
|
||||
web: Workflow.UNKNOWN,
|
||||
},
|
||||
env: undefined,
|
||||
vcsClient,
|
||||
});
|
||||
const runtimeToPlatformMapping =
|
||||
getRuntimeToPlatformMappingFromRuntimeVersions(runtimeVersions);
|
||||
|
||||
const { branchId } = await ensureBranchExistsAsync(graphqlClient, {
|
||||
const { branchId, createdBranch } = await ensureBranchExistsAsync(graphqlClient, {
|
||||
appId: projectId,
|
||||
branchName,
|
||||
});
|
||||
if (createdBranch) {
|
||||
await ensureChannelExistsAsync(graphqlClient, {
|
||||
appId: projectId,
|
||||
branchId,
|
||||
channelName: branchName,
|
||||
});
|
||||
Log.withTick(
|
||||
`Channel: ${chalk.bold(branchName)} pointed at branch: ${chalk.bold(branchName)}`
|
||||
);
|
||||
}
|
||||
|
||||
const gitCommitHash = await vcsClient.getCommitHashAsync();
|
||||
const isGitWorkingTreeDirty = await vcsClient.hasUncommittedChangesAsync();
|
||||
@@ -496,15 +497,6 @@ export default class UpdatePublish extends EasCommand {
|
||||
const accountName = (await getOwnerAccountForProjectIdAsync(graphqlClient, projectId)).name;
|
||||
const updateGroupUrl = getUpdateGroupUrl(accountName, projectName, updateGroupId);
|
||||
const updateGroupLink = link(updateGroupUrl, { dim: false });
|
||||
const updateCreatedAt = (newAndroidUpdate ?? newIosUpdate)?.createdAt;
|
||||
const updateQrCodeUrl = getUpdatePreviewUrl({
|
||||
message: updateMessage,
|
||||
updateRuntimeVersion: runtime.runtimeVersion,
|
||||
createdAt: updateCreatedAt.toString(),
|
||||
slug: projectName, // todo check this
|
||||
projectId,
|
||||
group: updateGroupId,
|
||||
});
|
||||
|
||||
Log.log(
|
||||
formatFields([
|
||||
@@ -525,12 +517,9 @@ export default class UpdatePublish extends EasCommand {
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{ label: 'EAS Dashboard', value: updateGroupLink },
|
||||
{ label: 'Website link', value: updateGroupLink },
|
||||
])
|
||||
);
|
||||
qrcodeTerminal.generate(updateQrCodeUrl, { small: true }, code =>
|
||||
Log.log(`${indentString(code, 2)}\n`)
|
||||
);
|
||||
Log.addNewLineIfNone();
|
||||
if (
|
||||
isUploadedAssetCountAboveWarningThreshold(uploadedAssetCount, assetLimitPerUpdateGroup)
|
||||
|
||||
@@ -69,7 +69,7 @@ export default class UpdateRepublish extends EasCommand {
|
||||
required: false,
|
||||
}),
|
||||
'private-key-path': Flags.string({
|
||||
description: `File containing the PEM-encoded private key corresponding to the certificate in expo-updates' configuration. Defaults to a file named "private-key.pem" in the certificate's directory. Only relevant if you are using code signing: https://docs.expo.dev/eas-update/code-signing/`,
|
||||
description: `File containing the PEM-encoded private key corresponding to the certificate in expo-updates' configuration. Defaults to a file named "private-key.pem" in the certificate's directory.`,
|
||||
required: false,
|
||||
}),
|
||||
...EasNonInteractiveAndJsonFlags,
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Platform as PublishPlatform } from '@expo/config';
|
||||
import { Workflow } from '@expo/eas-build-job';
|
||||
import { Errors, Flags } from '@oclif/core';
|
||||
import chalk from 'chalk';
|
||||
import nullthrows from 'nullthrows';
|
||||
|
||||
import { ensureBranchExistsAsync } from '../../branch/queries';
|
||||
import { getUpdateGroupUrl } from '../../build/utils/url';
|
||||
import { ensureChannelExistsAsync } from '../../channel/queries';
|
||||
import EasCommand from '../../commandUtils/EasCommand';
|
||||
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
import { EasNonInteractiveAndJsonFlags } from '../../commandUtils/flags';
|
||||
@@ -32,7 +33,6 @@ import {
|
||||
getRuntimeVersionObjectAsync,
|
||||
getUpdateMessageForCommandAsync,
|
||||
} from '../../project/publish';
|
||||
import { resolveWorkflowPerPlatformAsync } from '../../project/workflow';
|
||||
import { ensureEASUpdateIsConfiguredAsync } from '../../update/configure';
|
||||
import { getUpdateJsonInfosForUpdates } from '../../update/utils';
|
||||
import {
|
||||
@@ -101,7 +101,7 @@ export default class UpdateRollBackToEmbedded extends EasCommand {
|
||||
default: false,
|
||||
}),
|
||||
'private-key-path': Flags.string({
|
||||
description: `File containing the PEM-encoded private key corresponding to the certificate in expo-updates' configuration. Defaults to a file named "private-key.pem" in the certificate's directory. Only relevant if you are using code signing: https://docs.expo.dev/eas-update/code-signing/`,
|
||||
description: `File containing the PEM-encoded private key corresponding to the certificate in expo-updates' configuration. Defaults to a file named "private-key.pem" in the certificate's directory.`,
|
||||
required: false,
|
||||
}),
|
||||
...EasNonInteractiveAndJsonFlags,
|
||||
@@ -154,7 +154,6 @@ export default class UpdateRollBackToEmbedded extends EasCommand {
|
||||
projectDir,
|
||||
projectId,
|
||||
vcsClient,
|
||||
env: undefined,
|
||||
});
|
||||
|
||||
// check that the expo-updates package version supports roll back to embedded
|
||||
@@ -185,24 +184,28 @@ export default class UpdateRollBackToEmbedded extends EasCommand {
|
||||
const realizedPlatforms: PublishPlatform[] =
|
||||
platformFlag === 'all' ? defaultPublishPlatforms : [platformFlag];
|
||||
|
||||
const { branchId } = await ensureBranchExistsAsync(graphqlClient, {
|
||||
const { branchId, createdBranch } = await ensureBranchExistsAsync(graphqlClient, {
|
||||
appId: projectId,
|
||||
branchName,
|
||||
});
|
||||
if (createdBranch) {
|
||||
await ensureChannelExistsAsync(graphqlClient, {
|
||||
appId: projectId,
|
||||
branchId,
|
||||
channelName: branchName,
|
||||
});
|
||||
}
|
||||
|
||||
Log.withTick(`Channel: ${chalk.bold(branchName)} pointed at branch: ${chalk.bold(branchName)}`);
|
||||
|
||||
const gitCommitHash = await vcsClient.getCommitHashAsync();
|
||||
const isGitWorkingTreeDirty = await vcsClient.hasUncommittedChangesAsync();
|
||||
|
||||
const workflows = await resolveWorkflowPerPlatformAsync(projectDir, vcsClient);
|
||||
const runtimeVersions = await getRuntimeVersionObjectAsync({
|
||||
exp,
|
||||
platforms: realizedPlatforms,
|
||||
projectDir,
|
||||
workflows: {
|
||||
...workflows,
|
||||
web: Workflow.UNKNOWN,
|
||||
},
|
||||
env: undefined,
|
||||
vcsClient,
|
||||
});
|
||||
|
||||
let newUpdates: UpdatePublishMutation['updateBranch']['publishUpdateGroups'];
|
||||
@@ -276,7 +279,7 @@ export default class UpdateRollBackToEmbedded extends EasCommand {
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{ label: 'EAS Dashboard', value: updateGroupLink },
|
||||
{ label: 'Website link', value: updateGroupLink },
|
||||
])
|
||||
);
|
||||
Log.addNewLineIfNone();
|
||||
|
||||
@@ -10,7 +10,7 @@ export default class UpdateRollback extends EasCommand {
|
||||
|
||||
static override flags = {
|
||||
'private-key-path': Flags.string({
|
||||
description: `File containing the PEM-encoded private key corresponding to the certificate in expo-updates' configuration. Defaults to a file named "private-key.pem" in the certificate's directory. Only relevant if you are using code signing: https://docs.expo.dev/eas-update/code-signing/`,
|
||||
description: `File containing the PEM-encoded private key corresponding to the certificate in expo-updates' configuration. Defaults to a file named "private-key.pem" in the certificate's directory.`,
|
||||
required: false,
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -55,7 +55,6 @@ export const testPKCS12EmptyPasswordKeystore: Keystore = {
|
||||
export const testAppFragment: AppFragment = {
|
||||
id: 'test-app-id',
|
||||
fullName: '@testuser/testapp',
|
||||
name: 'testapp',
|
||||
slug: 'testapp',
|
||||
ownerAccount: {
|
||||
id: 'test-account-id',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import AppStoreApi from '../ios/appstore/AppStoreApi';
|
||||
import { AuthCtx, AuthenticationMode } from '../ios/appstore/authenticateTypes';
|
||||
import { AuthCtx } from '../ios/appstore/authenticateTypes';
|
||||
|
||||
export const testAuthCtx: AuthCtx = {
|
||||
appleId: 'test-apple-id',
|
||||
@@ -9,7 +9,6 @@ export const testAuthCtx: AuthCtx = {
|
||||
|
||||
export function getAppstoreMock(): AppStoreApi {
|
||||
return {
|
||||
defaultAuthenticationMode: AuthenticationMode.USER,
|
||||
ensureAuthenticatedAsync: jest.fn(),
|
||||
ensureBundleIdExistsAsync: jest.fn(),
|
||||
listDistributionCertificatesAsync: jest.fn(),
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import assert from 'node:assert';
|
||||
|
||||
import { AppFragment, Role } from '../../graphql/generated';
|
||||
import { Actor } from '../../user/User';
|
||||
|
||||
@@ -26,7 +24,6 @@ export const jester: Actor = {
|
||||
],
|
||||
isExpoAdmin: false,
|
||||
featureGates: {},
|
||||
preferences: {},
|
||||
};
|
||||
|
||||
export const jester2 = {
|
||||
@@ -44,7 +41,6 @@ export const jester2 = {
|
||||
featureGates: {},
|
||||
};
|
||||
|
||||
assert(jester.__typename === 'User');
|
||||
export const testUsername = jester.username;
|
||||
export const testSlug = 'testApp';
|
||||
export const testProjectId = '7ef93448-3bc7-4b57-be32-99326dcf24f0';
|
||||
@@ -80,7 +76,6 @@ export const testAppJsonWithDifferentOwner = {
|
||||
export const testAppQueryByIdResponse: AppFragment = {
|
||||
id: testProjectId,
|
||||
slug: testSlug,
|
||||
name: 'testing 123',
|
||||
fullName: testExperienceName,
|
||||
ownerAccount: jester.accounts[0],
|
||||
};
|
||||
@@ -55,7 +55,6 @@ export const testAppleAppIdentifierFragment: AppleAppIdentifierFragment = {
|
||||
export const testAppFragment: AppFragment = {
|
||||
id: 'test-app-id',
|
||||
fullName: '@testuser/testapp',
|
||||
name: 'testapp',
|
||||
slug: 'testapp',
|
||||
ownerAccount: {
|
||||
id: 'test-account-id',
|
||||
|
||||
+7
-60
@@ -4,76 +4,27 @@ import gql from 'graphql-tag';
|
||||
import { ExpoGraphqlClient } from '../../../../../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
import { withErrorHandlingAsync } from '../../../../../graphql/client';
|
||||
import {
|
||||
GoogleServiceAccountKeyByAccountQuery,
|
||||
GoogleServiceAccountKeyFragment,
|
||||
GoogleServiceAccountKeysPaginatedByAccountQuery,
|
||||
} from '../../../../../graphql/generated';
|
||||
import { GoogleServiceAccountKeyFragmentNode } from '../../../../../graphql/types/credentials/GoogleServiceAccountKey';
|
||||
import { Connection, QueryParams, fetchEntireDatasetAsync } from '../../../../../utils/relay';
|
||||
|
||||
export const GoogleServiceAccountKeyQuery = {
|
||||
async getAllForAccountAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
accountName: string
|
||||
): Promise<GoogleServiceAccountKeyFragment[]> {
|
||||
const paginatedGetterAsync = async (
|
||||
relayArgs: QueryParams
|
||||
): Promise<Connection<GoogleServiceAccountKeyFragment>> => {
|
||||
return await GoogleServiceAccountKeyQuery.getAllForAccountPaginatedAsync(
|
||||
graphqlClient,
|
||||
accountName,
|
||||
relayArgs
|
||||
);
|
||||
};
|
||||
return await fetchEntireDatasetAsync({
|
||||
paginatedGetterAsync,
|
||||
progressBarLabel: 'fetching Google Service Account Keys...',
|
||||
});
|
||||
},
|
||||
async getAllForAccountPaginatedAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
accountName: string,
|
||||
{
|
||||
after,
|
||||
first,
|
||||
before,
|
||||
last,
|
||||
}: { after?: string; first?: number; before?: string; last?: number }
|
||||
): Promise<
|
||||
GoogleServiceAccountKeysPaginatedByAccountQuery['account']['byName']['googleServiceAccountKeysPaginated']
|
||||
> {
|
||||
const data = await withErrorHandlingAsync(
|
||||
graphqlClient
|
||||
.query<GoogleServiceAccountKeysPaginatedByAccountQuery>(
|
||||
.query<GoogleServiceAccountKeyByAccountQuery>(
|
||||
gql`
|
||||
query GoogleServiceAccountKeysPaginatedByAccountQuery(
|
||||
$accountName: String!
|
||||
$after: String
|
||||
$first: Int
|
||||
$before: String
|
||||
$last: Int
|
||||
) {
|
||||
query GoogleServiceAccountKeyByAccountQuery($accountName: String!) {
|
||||
account {
|
||||
byName(accountName: $accountName) {
|
||||
id
|
||||
googleServiceAccountKeysPaginated(
|
||||
after: $after
|
||||
first: $first
|
||||
before: $before
|
||||
last: $last
|
||||
) {
|
||||
edges {
|
||||
cursor
|
||||
node {
|
||||
id
|
||||
...GoogleServiceAccountKeyFragment
|
||||
}
|
||||
}
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
hasPreviousPage
|
||||
startCursor
|
||||
endCursor
|
||||
}
|
||||
googleServiceAccountKeys {
|
||||
id
|
||||
...GoogleServiceAccountKeyFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,10 +33,6 @@ export const GoogleServiceAccountKeyQuery = {
|
||||
`,
|
||||
{
|
||||
accountName,
|
||||
after,
|
||||
first,
|
||||
before,
|
||||
last,
|
||||
},
|
||||
{
|
||||
additionalTypenames: ['GoogleServiceAccountKey'],
|
||||
@@ -93,6 +40,6 @@ export const GoogleServiceAccountKeyQuery = {
|
||||
)
|
||||
.toPromise()
|
||||
);
|
||||
return data.account.byName.googleServiceAccountKeysPaginated;
|
||||
return data.account.byName.googleServiceAccountKeys;
|
||||
},
|
||||
};
|
||||
@@ -25,7 +25,6 @@ export class CredentialsContext {
|
||||
public readonly appStore = new AppStoreApi();
|
||||
public readonly ios = IosGraphqlClient;
|
||||
public readonly nonInteractive: boolean;
|
||||
public readonly freezeCredentials: boolean = false;
|
||||
public readonly projectDir: string;
|
||||
public readonly user: Actor;
|
||||
public readonly graphqlClient: ExpoGraphqlClient;
|
||||
@@ -48,7 +47,6 @@ export class CredentialsContext {
|
||||
graphqlClient: ExpoGraphqlClient;
|
||||
analytics: Analytics;
|
||||
vcsClient: Client;
|
||||
freezeCredentials?: boolean;
|
||||
env?: Env;
|
||||
}
|
||||
) {
|
||||
@@ -60,7 +58,6 @@ export class CredentialsContext {
|
||||
this.vcsClient = options.vcsClient;
|
||||
this.nonInteractive = options.nonInteractive ?? false;
|
||||
this.projectInfo = options.projectInfo;
|
||||
this.freezeCredentials = options.freezeCredentials ?? false;
|
||||
}
|
||||
|
||||
get hasProjectContext(): boolean {
|
||||
|
||||
@@ -1,31 +1,9 @@
|
||||
import { learnMore } from '../log';
|
||||
|
||||
export class MissingCredentialsNonInteractiveError extends Error {
|
||||
constructor(message?: string) {
|
||||
super(message ?? 'Credentials are not set up. Run this command again in interactive mode.');
|
||||
}
|
||||
}
|
||||
|
||||
export class InsufficientAuthenticationNonInteractiveError extends Error {
|
||||
constructor(message?: string) {
|
||||
super(
|
||||
message ??
|
||||
`Authentication with an ASC API key is required in non-interactive mode. ${learnMore(
|
||||
'https://docs.expo.dev/build/building-on-ci/#optional-provide-an-asc-api-token-for-your-apple-team'
|
||||
)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class ForbidCredentialModificationError extends Error {
|
||||
constructor(message?: string) {
|
||||
super(
|
||||
message ??
|
||||
'Credentials cannot be modified. Run this command again without the --freeze-credentials flag.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class MissingCredentialsError extends Error {
|
||||
constructor(message?: string) {
|
||||
super(message ?? 'Credentials are not set up.');
|
||||
|
||||
@@ -14,7 +14,6 @@ import { isAdHocProfile, isEnterpriseUniversalProfile } from './utils/provisioni
|
||||
import { CommonIosAppCredentialsFragment } from '../../graphql/generated';
|
||||
import Log from '../../log';
|
||||
import { findApplicationTarget } from '../../project/ios/target';
|
||||
import { isExpoNotificationsInstalled } from '../../project/projectUtils';
|
||||
import { selectAsync } from '../../prompts';
|
||||
import { CredentialsContext } from '../context';
|
||||
import * as credentialsJsonReader from '../credentialsJson/read';
|
||||
@@ -106,11 +105,6 @@ export default class IosCredentialsProvider {
|
||||
|
||||
if (ctx.easJsonCliConfig?.promptToConfigurePushNotifications === false) {
|
||||
return null;
|
||||
} else if (
|
||||
ctx.easJsonCliConfig?.promptToConfigurePushNotifications === undefined &&
|
||||
!(await isExpoNotificationsInstalled(ctx.projectDir))
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const setupOption = await selectAsync(
|
||||
|
||||
@@ -5,18 +5,15 @@ import {
|
||||
AppleDistributionCertificateFragment,
|
||||
AppleProvisioningProfileFragment,
|
||||
} from '../../../graphql/generated';
|
||||
import Log, { learnMore } from '../../../log';
|
||||
import Log from '../../../log';
|
||||
import { ora } from '../../../ora';
|
||||
import { getApplePlatformFromTarget } from '../../../project/ios/target';
|
||||
import { CredentialsContext } from '../../context';
|
||||
import {
|
||||
ForbidCredentialModificationError,
|
||||
InsufficientAuthenticationNonInteractiveError,
|
||||
} from '../../errors';
|
||||
import { MissingCredentialsNonInteractiveError } from '../../errors';
|
||||
import { AppleProvisioningProfileMutationResult } from '../api/graphql/mutations/AppleProvisioningProfileMutation';
|
||||
import { AppLookupParams } from '../api/graphql/types/AppLookupParams';
|
||||
import { ProvisioningProfileStoreInfo } from '../appstore/Credentials.types';
|
||||
import { AuthCtx, AuthenticationMode } from '../appstore/authenticateTypes';
|
||||
import { AuthCtx } from '../appstore/authenticateTypes';
|
||||
import { Target } from '../types';
|
||||
|
||||
export class ConfigureProvisioningProfile {
|
||||
@@ -30,18 +27,9 @@ export class ConfigureProvisioningProfile {
|
||||
public async runAsync(
|
||||
ctx: CredentialsContext
|
||||
): Promise<AppleProvisioningProfileMutationResult | null> {
|
||||
if (ctx.freezeCredentials) {
|
||||
throw new ForbidCredentialModificationError(
|
||||
'Remove the --freeze-credentials flag to configure a Provisioning Profile.'
|
||||
);
|
||||
} else if (
|
||||
ctx.nonInteractive &&
|
||||
ctx.appStore.defaultAuthenticationMode !== AuthenticationMode.API_KEY
|
||||
) {
|
||||
throw new InsufficientAuthenticationNonInteractiveError(
|
||||
`In order to configure your Provisioning Profile, authentication with an ASC API key is required in non-interactive mode. ${learnMore(
|
||||
'https://docs.expo.dev/build/building-on-ci/#optional-provide-an-asc-api-token-for-your-apple-team'
|
||||
)}`
|
||||
if (ctx.nonInteractive) {
|
||||
throw new MissingCredentialsNonInteractiveError(
|
||||
'Configuring Provisioning Profiles is only supported in interactive mode.'
|
||||
);
|
||||
}
|
||||
const { developerPortalIdentifier, provisioningProfile } = this.originalProvisioningProfile;
|
||||
@@ -58,7 +46,7 @@ export class ConfigureProvisioningProfile {
|
||||
return null;
|
||||
}
|
||||
|
||||
const applePlatform = getApplePlatformFromTarget(this.target);
|
||||
const applePlatform = await getApplePlatformFromTarget(this.target);
|
||||
const profilesFromApple = await ctx.appStore.listProvisioningProfilesAsync(
|
||||
this.app.bundleIdentifier,
|
||||
applePlatform
|
||||
|
||||
@@ -4,17 +4,14 @@ import nullthrows from 'nullthrows';
|
||||
import { resolveAppleTeamIfAuthenticatedAsync } from './AppleTeamUtils';
|
||||
import { generateProvisioningProfileAsync } from './ProvisioningProfileUtils';
|
||||
import { AppleDistributionCertificateFragment } from '../../../graphql/generated';
|
||||
import Log, { learnMore } from '../../../log';
|
||||
import Log from '../../../log';
|
||||
import { CredentialsContext } from '../../context';
|
||||
import {
|
||||
ForbidCredentialModificationError,
|
||||
InsufficientAuthenticationNonInteractiveError,
|
||||
} from '../../errors';
|
||||
import { MissingCredentialsNonInteractiveError } from '../../errors';
|
||||
import { askForUserProvidedAsync } from '../../utils/promptForCredentials';
|
||||
import { AppleProvisioningProfileMutationResult } from '../api/graphql/mutations/AppleProvisioningProfileMutation';
|
||||
import { AppLookupParams } from '../api/graphql/types/AppLookupParams';
|
||||
import { ProvisioningProfile } from '../appstore/Credentials.types';
|
||||
import { AuthCtx, AuthenticationMode } from '../appstore/authenticateTypes';
|
||||
import { AuthCtx } from '../appstore/authenticateTypes';
|
||||
import { provisioningProfileSchema } from '../credentials';
|
||||
import { Target } from '../types';
|
||||
|
||||
@@ -26,18 +23,9 @@ export class CreateProvisioningProfile {
|
||||
) {}
|
||||
|
||||
async runAsync(ctx: CredentialsContext): Promise<AppleProvisioningProfileMutationResult> {
|
||||
if (ctx.freezeCredentials) {
|
||||
throw new ForbidCredentialModificationError(
|
||||
'Run this command again without the --freeze-credentials flag in order to generate a new Provisioning Profile.'
|
||||
);
|
||||
} else if (
|
||||
ctx.nonInteractive &&
|
||||
ctx.appStore.defaultAuthenticationMode !== AuthenticationMode.API_KEY
|
||||
) {
|
||||
throw new InsufficientAuthenticationNonInteractiveError(
|
||||
`In order to generate a new Provisioning Profile, authentication with an ASC API key is required in non-interactive mode. ${learnMore(
|
||||
'https://docs.expo.dev/build/building-on-ci/#optional-provide-an-asc-api-token-for-your-apple-team'
|
||||
)}`
|
||||
if (ctx.nonInteractive) {
|
||||
throw new MissingCredentialsNonInteractiveError(
|
||||
'Creating Provisioning Profiles is only supported in interactive mode.'
|
||||
);
|
||||
}
|
||||
const appleAuthCtx = await ctx.appStore.ensureAuthenticatedAsync();
|
||||
@@ -61,31 +49,16 @@ export class CreateProvisioningProfile {
|
||||
return provisioningProfileMutationResult;
|
||||
}
|
||||
|
||||
private async maybeGetUserProvidedAsync(
|
||||
ctx: CredentialsContext
|
||||
): Promise<ProvisioningProfile | null> {
|
||||
if (ctx.nonInteractive) {
|
||||
return null;
|
||||
}
|
||||
private async provideOrGenerateAsync(
|
||||
ctx: CredentialsContext,
|
||||
appleAuthCtx: AuthCtx
|
||||
): Promise<ProvisioningProfile> {
|
||||
const userProvided = await askForUserProvidedAsync(provisioningProfileSchema);
|
||||
if (userProvided) {
|
||||
// userProvided profiles don't come with ProvisioningProfileId's (only accessible from Apple Portal API)
|
||||
Log.warn('Provisioning profile: Unable to validate specified profile.');
|
||||
return userProvided;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private async provideOrGenerateAsync(
|
||||
ctx: CredentialsContext,
|
||||
appleAuthCtx: AuthCtx
|
||||
): Promise<ProvisioningProfile> {
|
||||
const maybeUserProvided = await this.maybeGetUserProvidedAsync(ctx);
|
||||
if (maybeUserProvided) {
|
||||
// userProvided profiles don't come with ProvisioningProfileId's (only accessible from Apple Portal API)
|
||||
Log.warn('Provisioning profile: Unable to validate specified profile.');
|
||||
return maybeUserProvided;
|
||||
}
|
||||
assert(
|
||||
this.distributionCertificate.certificateP12,
|
||||
'Distribution Certificate must have p12 certificate'
|
||||
|
||||
@@ -48,13 +48,8 @@ export function formatDistributionCertificate(
|
||||
buildCredentials => buildCredentials.iosAppCredentials.app
|
||||
);
|
||||
if (apps.length) {
|
||||
// iosAppBuildCredentialsList is capped at 20 on www
|
||||
const appFullNames = apps
|
||||
.map(app => app.fullName)
|
||||
.slice(0, 19)
|
||||
.join(',');
|
||||
const andMaybeMore = apps.length > 19 ? ' (and more)' : '';
|
||||
line += chalk.gray(`\n 📲 Used by: ${appFullNames}${andMaybeMore}`);
|
||||
const appFullNames = apps.map(app => app.fullName).join(',');
|
||||
line += chalk.gray(`\n 📲 Used by: ${appFullNames}`);
|
||||
}
|
||||
|
||||
if (validSerialNumbers?.includes(serialNumber)) {
|
||||
@@ -259,10 +254,6 @@ function formatDistributionCertificateFromApple(
|
||||
const { name, status, id, expires, created, ownerName, serialNumber } = appleInfo;
|
||||
const expiresDate = new Date(expires * 1000).toDateString();
|
||||
const createdDate = new Date(created * 1000).toDateString();
|
||||
return [
|
||||
`🍏 ${chalk.bold(name)} (${status})`,
|
||||
`${chalk.bold('ID:')} ${id} ${chalk.bold('Serial Number:')} ${serialNumber}`,
|
||||
`${chalk.bold('Apple Team:')} ${appleInfo.ownerId} (${ownerName})`,
|
||||
`${chalk.bold('Expires:')} ${expiresDate} ${chalk.bold('Created:')} ${createdDate}`,
|
||||
].join('\n\t');
|
||||
return `${name} (${status}) - Cert ID: ${id}, Serial number: ${serialNumber}, Team ID: ${appleInfo.ownerId}, Team name: ${ownerName}
|
||||
expires: ${expiresDate}, created: ${createdDate}`;
|
||||
}
|
||||
@@ -185,13 +185,8 @@ export function formatPushKey(
|
||||
|
||||
const apps = pushKey.iosAppCredentialsList.map(appCredentials => appCredentials.app);
|
||||
if (apps.length) {
|
||||
// iosAppCredentialsList is capped at 20 on www
|
||||
const appFullNames = apps
|
||||
.map(app => app.fullName)
|
||||
.slice(0, 19)
|
||||
.join(',');
|
||||
const andMaybeMore = apps.length > 19 ? ' (and more)' : '';
|
||||
line += chalk.gray(`\n 📲 Used by: ${appFullNames}${andMaybeMore}`);
|
||||
const appFullNames = apps.map(app => app.fullName).join(',');
|
||||
line += chalk.gray(`\n 📲 Used by: ${appFullNames}`);
|
||||
}
|
||||
|
||||
if (validPushKeyIdentifiers?.includes(keyIdentifier)) {
|
||||
|
||||
@@ -34,20 +34,14 @@ export class RemoveDistributionCertificate {
|
||||
buildCredentials => buildCredentials.iosAppCredentials.app
|
||||
);
|
||||
if (apps.length !== 0) {
|
||||
// iosAppBuildCredentialsList is capped at 20 on www
|
||||
const appFullNames = apps
|
||||
.map(app => app.fullName)
|
||||
.slice(0, 19)
|
||||
.join(',');
|
||||
const andMaybeMore = apps.length > 19 ? ' (and more)' : '';
|
||||
|
||||
const appFullNames = apps.map(app => app.fullName).join(',');
|
||||
if (ctx.nonInteractive) {
|
||||
throw new Error(
|
||||
`Certificate is currently used by ${appFullNames}${andMaybeMore} and cannot be deleted in non-interactive mode.`
|
||||
`Certificate is currently used by ${appFullNames} and cannot be deleted in non-interactive mode.`
|
||||
);
|
||||
}
|
||||
const confirm = await confirmAsync({
|
||||
message: `You are removing certificate used by ${appFullNames}${andMaybeMore}. Do you want to continue?`,
|
||||
message: `You are removing certificate used by ${appFullNames}. Do you want to continue?`,
|
||||
});
|
||||
if (!confirm) {
|
||||
Log.log('Aborting');
|
||||
|
||||
@@ -27,14 +27,9 @@ export class RemovePushKey {
|
||||
|
||||
const apps = this.pushKey.iosAppCredentialsList.map(appCredentials => appCredentials.app);
|
||||
if (apps.length !== 0) {
|
||||
// iosAppCredentialsList is capped at 20 on www
|
||||
const appFullNames = apps
|
||||
.map(app => app.fullName)
|
||||
.slice(0, 19)
|
||||
.join(',');
|
||||
const andMaybeMore = apps.length > 19 ? ' (and more)' : '';
|
||||
const appFullNames = apps.map(app => app.fullName).join(',');
|
||||
const confirm = await confirmAsync({
|
||||
message: `Removing this push key will disable push notifications for ${appFullNames}${andMaybeMore}. Do you want to continue?`,
|
||||
message: `Removing this push key will disable push notifications for ${appFullNames}. Do you want to continue?`,
|
||||
});
|
||||
if (!confirm) {
|
||||
Log.log('Aborting');
|
||||
|
||||
@@ -352,6 +352,7 @@ export class SetUpAdhocProvisioningProfile {
|
||||
|
||||
while (true) {
|
||||
if (method === RegistrationMethod.WEBSITE) {
|
||||
Log.newLine();
|
||||
Log.log(chalk.bold("Press any key if you've already finished device registration."));
|
||||
await pressAnyKeyToContinueAsync();
|
||||
}
|
||||
|
||||
@@ -15,17 +15,12 @@ import {
|
||||
IosAppBuildCredentialsFragment,
|
||||
IosDistributionType,
|
||||
} from '../../../graphql/generated';
|
||||
import { learnMore } from '../../../log';
|
||||
import { getApplePlatformFromTarget } from '../../../project/ios/target';
|
||||
import { confirmAsync } from '../../../prompts';
|
||||
import { CredentialsContext } from '../../context';
|
||||
import {
|
||||
ForbidCredentialModificationError,
|
||||
InsufficientAuthenticationNonInteractiveError,
|
||||
} from '../../errors';
|
||||
import { MissingCredentialsNonInteractiveError } from '../../errors';
|
||||
import { AppLookupParams } from '../api/graphql/types/AppLookupParams';
|
||||
import { ProvisioningProfileStoreInfo } from '../appstore/Credentials.types';
|
||||
import { AuthenticationMode } from '../appstore/authenticateTypes';
|
||||
import { Target } from '../types';
|
||||
import { validateProvisioningProfileAsync } from '../validators/validateProvisioningProfile';
|
||||
|
||||
@@ -107,18 +102,9 @@ export class SetUpProvisioningProfile {
|
||||
if (areBuildCredentialsSetup) {
|
||||
return nullthrows(await getBuildCredentialsAsync(ctx, this.app, this.distributionType));
|
||||
}
|
||||
if (ctx.freezeCredentials) {
|
||||
throw new ForbidCredentialModificationError(
|
||||
'Provisioning profile is not configured correctly. Remove the --freeze-credentials flag to configure it.'
|
||||
);
|
||||
} else if (
|
||||
ctx.nonInteractive &&
|
||||
ctx.appStore.defaultAuthenticationMode !== AuthenticationMode.API_KEY
|
||||
) {
|
||||
throw new InsufficientAuthenticationNonInteractiveError(
|
||||
`In order to configure your Provisioning Profile, authentication with an ASC API key is required in non-interactive mode. ${learnMore(
|
||||
'https://docs.expo.dev/build/building-on-ci/#optional-provide-an-asc-api-token-for-your-apple-team'
|
||||
)}`
|
||||
if (ctx.nonInteractive) {
|
||||
throw new MissingCredentialsNonInteractiveError(
|
||||
'Provisioning profile is not configured correctly. Run this command again in interactive mode.'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -141,18 +127,11 @@ export class SetUpProvisioningProfile {
|
||||
return await this.assignNewAndDeleteOldProfileAsync(ctx, distCert, currentProfile);
|
||||
}
|
||||
|
||||
const isNonInteractiveOrUserDidConfirmAsync = async (): Promise<boolean> => {
|
||||
if (ctx.nonInteractive) {
|
||||
return true;
|
||||
}
|
||||
return await confirmAsync({
|
||||
message: `${formatProvisioningProfileFromApple(
|
||||
currentProfileFromServer
|
||||
)} \n Would you like to reuse the original profile?`,
|
||||
});
|
||||
};
|
||||
|
||||
const confirm = await isNonInteractiveOrUserDidConfirmAsync();
|
||||
const confirm = await confirmAsync({
|
||||
message: `${formatProvisioningProfileFromApple(
|
||||
currentProfileFromServer
|
||||
)} \n Would you like to reuse the original profile?`,
|
||||
});
|
||||
if (!confirm) {
|
||||
return await this.assignNewAndDeleteOldProfileAsync(ctx, distCert, currentProfile);
|
||||
}
|
||||
|
||||
+5
-35
@@ -11,11 +11,7 @@ import {
|
||||
testTarget,
|
||||
testTargets,
|
||||
} from '../../../__tests__/fixtures-ios';
|
||||
import {
|
||||
ForbidCredentialModificationError,
|
||||
InsufficientAuthenticationNonInteractiveError,
|
||||
} from '../../../errors';
|
||||
import { AuthenticationMode } from '../../appstore/authenticateTypes';
|
||||
import { MissingCredentialsNonInteractiveError } from '../../../errors';
|
||||
import { getAppLookupParamsFromContextAsync } from '../BuildCredentialsUtils';
|
||||
import { ConfigureProvisioningProfile } from '../ConfigureProvisioningProfile';
|
||||
|
||||
@@ -28,18 +24,15 @@ describe('ConfigureProvisioningProfile', () => {
|
||||
beforeEach(() => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue(testAppQueryByIdResponse);
|
||||
});
|
||||
const testCases = ['NON_INTERACTIVE', 'INTERACTIVE'];
|
||||
test.each(testCases)('configures a Provisioning Profile in %s Mode', async mode => {
|
||||
it('configures a Provisioning Profile in Interactive Mode', async () => {
|
||||
const mockProvisioningProfileFromApple = {
|
||||
provisioningProfileId: testProvisioningProfileFragment.developerPortalIdentifier,
|
||||
provisioningProfile: testProvisioningProfileFragment.provisioningProfile,
|
||||
};
|
||||
const ctx = createCtxMock({
|
||||
nonInteractive: mode === 'NON_INTERACTIVE',
|
||||
nonInteractive: false,
|
||||
appStore: {
|
||||
...getAppstoreMock(),
|
||||
defaultAuthenticationMode:
|
||||
mode === 'NON_INTERACTIVE' ? AuthenticationMode.API_KEY : AuthenticationMode.USER,
|
||||
ensureAuthenticatedAsync: jest.fn(() => testAuthCtx),
|
||||
authCtx: testAuthCtx,
|
||||
createProvisioningProfileAsync: jest.fn(() => testProvisioningProfile),
|
||||
@@ -64,30 +57,7 @@ describe('ConfigureProvisioningProfile', () => {
|
||||
// expect provisioning profile not to be updated on apple portal
|
||||
expect(jest.mocked(ctx.appStore.useExistingProvisioningProfileAsync).mock.calls.length).toBe(1);
|
||||
});
|
||||
it('errors with --freeze-credentials flag', async () => {
|
||||
const ctx = createCtxMock({
|
||||
freezeCredentials: true,
|
||||
});
|
||||
const appLookupParams = await getAppLookupParamsFromContextAsync(
|
||||
ctx,
|
||||
findApplicationTarget(testTargets)
|
||||
);
|
||||
const provProfConfigurator = new ConfigureProvisioningProfile(
|
||||
appLookupParams,
|
||||
testTarget,
|
||||
testDistCertFragmentNoDependencies,
|
||||
testProvisioningProfileFragment
|
||||
);
|
||||
await expect(provProfConfigurator.runAsync(ctx)).rejects.toThrowError(
|
||||
ForbidCredentialModificationError
|
||||
);
|
||||
|
||||
// expect provisioning profile not to be updated on expo servers
|
||||
expect(jest.mocked(ctx.ios.updateProvisioningProfileAsync).mock.calls.length).toBe(0);
|
||||
// expect provisioning profile not to be updated on apple portal
|
||||
expect(jest.mocked(ctx.appStore.useExistingProvisioningProfileAsync).mock.calls.length).toBe(0);
|
||||
});
|
||||
it('errors with wrong authentication type in nonInteractive mode', async () => {
|
||||
it('errors in Non Interactive Mode', async () => {
|
||||
const ctx = createCtxMock({
|
||||
nonInteractive: true,
|
||||
});
|
||||
@@ -102,7 +72,7 @@ describe('ConfigureProvisioningProfile', () => {
|
||||
testProvisioningProfileFragment
|
||||
);
|
||||
await expect(provProfConfigurator.runAsync(ctx)).rejects.toThrowError(
|
||||
InsufficientAuthenticationNonInteractiveError
|
||||
MissingCredentialsNonInteractiveError
|
||||
);
|
||||
|
||||
// expect provisioning profile not to be updated on expo servers
|
||||
|
||||
+5
-35
@@ -10,11 +10,7 @@ import {
|
||||
testTarget,
|
||||
testTargets,
|
||||
} from '../../../__tests__/fixtures-ios';
|
||||
import {
|
||||
ForbidCredentialModificationError,
|
||||
InsufficientAuthenticationNonInteractiveError,
|
||||
} from '../../../errors';
|
||||
import { AuthenticationMode } from '../../appstore/authenticateTypes';
|
||||
import { MissingCredentialsNonInteractiveError } from '../../../errors';
|
||||
import { getAppLookupParamsFromContextAsync } from '../BuildCredentialsUtils';
|
||||
import { CreateProvisioningProfile } from '../CreateProvisioningProfile';
|
||||
|
||||
@@ -26,15 +22,11 @@ describe('CreateProvisioningProfile', () => {
|
||||
beforeEach(() => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue(testAppQueryByIdResponse);
|
||||
});
|
||||
|
||||
const testCases = ['NON_INTERACTIVE', 'INTERACTIVE'];
|
||||
test.each(testCases)('creates a Provisioning Profile in in %s Mode', async mode => {
|
||||
it('creates a Provisioning Profile in Interactive Mode', async () => {
|
||||
const ctx = createCtxMock({
|
||||
nonInteractive: mode === 'NON_INTERACTIVE',
|
||||
nonInteractive: false,
|
||||
appStore: {
|
||||
...getAppstoreMock(),
|
||||
defaultAuthenticationMode:
|
||||
mode === 'NON_INTERACTIVE' ? AuthenticationMode.API_KEY : AuthenticationMode.USER,
|
||||
ensureAuthenticatedAsync: jest.fn(() => testAuthCtx),
|
||||
authCtx: testAuthCtx,
|
||||
createProvisioningProfileAsync: jest.fn(() => testProvisioningProfile),
|
||||
@@ -56,29 +48,7 @@ describe('CreateProvisioningProfile', () => {
|
||||
// expect provisioning profile to be created on apple portal
|
||||
expect(jest.mocked(ctx.appStore.createProvisioningProfileAsync).mock.calls.length).toBe(1);
|
||||
});
|
||||
it('errors with --freeze-credentials flag', async () => {
|
||||
const ctx = createCtxMock({
|
||||
freezeCredentials: true,
|
||||
});
|
||||
const appLookupParams = await getAppLookupParamsFromContextAsync(
|
||||
ctx,
|
||||
findApplicationTarget(testTargets)
|
||||
);
|
||||
const createProvProfAction = new CreateProvisioningProfile(
|
||||
appLookupParams,
|
||||
testTarget,
|
||||
testDistCertFragmentNoDependencies
|
||||
);
|
||||
await expect(createProvProfAction.runAsync(ctx)).rejects.toThrowError(
|
||||
ForbidCredentialModificationError
|
||||
);
|
||||
|
||||
// expect provisioning profile not to be created on expo servers
|
||||
expect(jest.mocked(ctx.ios.createProvisioningProfileAsync).mock.calls.length).toBe(0);
|
||||
// expect provisioning profile not to be created on apple portal
|
||||
expect(jest.mocked(ctx.appStore.createProvisioningProfileAsync).mock.calls.length).toBe(0);
|
||||
});
|
||||
it('errors with wrong authentication type in nonInteractive mode', async () => {
|
||||
it('errors in Non Interactive Mode', async () => {
|
||||
const ctx = createCtxMock({
|
||||
nonInteractive: true,
|
||||
});
|
||||
@@ -92,7 +62,7 @@ describe('CreateProvisioningProfile', () => {
|
||||
testDistCertFragmentNoDependencies
|
||||
);
|
||||
await expect(createProvProfAction.runAsync(ctx)).rejects.toThrowError(
|
||||
InsufficientAuthenticationNonInteractiveError
|
||||
MissingCredentialsNonInteractiveError
|
||||
);
|
||||
|
||||
// expect provisioning profile not to be created on expo servers
|
||||
|
||||
+130
-186
@@ -15,11 +15,7 @@ import {
|
||||
testTarget,
|
||||
testTargets,
|
||||
} from '../../../__tests__/fixtures-ios';
|
||||
import {
|
||||
ForbidCredentialModificationError,
|
||||
InsufficientAuthenticationNonInteractiveError,
|
||||
} from '../../../errors';
|
||||
import { AuthenticationMode } from '../../appstore/authenticateTypes';
|
||||
import { MissingCredentialsNonInteractiveError } from '../../../errors';
|
||||
import { validateProvisioningProfileAsync } from '../../validators/validateProvisioningProfile';
|
||||
import { getAppLookupParamsFromContextAsync } from '../BuildCredentialsUtils';
|
||||
import { SetUpProvisioningProfile } from '../SetUpProvisioningProfile';
|
||||
@@ -36,185 +32,32 @@ describe('SetUpProvisioningProfile', () => {
|
||||
beforeEach(() => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue(testAppQueryByIdResponse);
|
||||
});
|
||||
|
||||
const testCases = ['NON_INTERACTIVE', 'INTERACTIVE'];
|
||||
test.each(testCases)(
|
||||
'repairs existing Provisioning Profile with bad build credentials in %s Mode',
|
||||
async mode => {
|
||||
jest.mocked(validateProvisioningProfileAsync).mockImplementation(async () => false);
|
||||
const ctx = createCtxMock({
|
||||
nonInteractive: mode === 'NON_INTERACTIVE',
|
||||
appStore: {
|
||||
...getAppstoreMock(),
|
||||
defaultAuthenticationMode:
|
||||
mode === 'NON_INTERACTIVE' ? AuthenticationMode.API_KEY : AuthenticationMode.USER,
|
||||
ensureAuthenticatedAsync: jest.fn(() => testAuthCtx),
|
||||
authCtx: testAuthCtx,
|
||||
listProvisioningProfilesAsync: jest.fn(() => [
|
||||
{
|
||||
provisioningProfileId: nullthrows(
|
||||
testCommonIosAppCredentialsFragment.iosAppBuildCredentialsList[0]
|
||||
.provisioningProfile
|
||||
).developerPortalIdentifier,
|
||||
},
|
||||
]),
|
||||
},
|
||||
ios: {
|
||||
...getNewIosApiMock(),
|
||||
getIosAppCredentialsWithBuildCredentialsAsync: jest.fn(
|
||||
() => testCommonIosAppCredentialsFragment
|
||||
),
|
||||
createOrGetExistingAppleAppIdentifierAsync: jest.fn(() => testAppleAppIdentifierFragment),
|
||||
createOrUpdateIosAppBuildCredentialsAsync: jest.fn(
|
||||
() => testIosAppBuildCredentialsFragment
|
||||
),
|
||||
},
|
||||
});
|
||||
const appLookupParams = await getAppLookupParamsFromContextAsync(
|
||||
ctx,
|
||||
findApplicationTarget(testTargets)
|
||||
);
|
||||
const setupProvisioningProfileAction = new SetUpProvisioningProfile(
|
||||
appLookupParams,
|
||||
testTarget,
|
||||
IosDistributionType.AppStore
|
||||
);
|
||||
await setupProvisioningProfileAction.runAsync(ctx);
|
||||
|
||||
// expect build credentials to be created or updated on expo servers
|
||||
expect(jest.mocked(ctx.ios.createOrUpdateIosAppBuildCredentialsAsync).mock.calls.length).toBe(
|
||||
1
|
||||
);
|
||||
// expect provisioning profile not to be deleted on expo servers
|
||||
expect(jest.mocked(ctx.ios.deleteProvisioningProfilesAsync).mock.calls.length).toBe(0);
|
||||
}
|
||||
);
|
||||
|
||||
test.each(testCases)(
|
||||
'sets up a new Provisioning Profile with bad build credentials in %s Mode',
|
||||
async mode => {
|
||||
jest.mocked(validateProvisioningProfileAsync).mockImplementation(async () => false);
|
||||
const ctx = createCtxMock({
|
||||
nonInteractive: mode === 'NON_INTERACTIVE',
|
||||
appStore: {
|
||||
...getAppstoreMock(),
|
||||
defaultAuthenticationMode:
|
||||
mode === 'NON_INTERACTIVE' ? AuthenticationMode.API_KEY : AuthenticationMode.USER,
|
||||
ensureAuthenticatedAsync: jest.fn(() => testAuthCtx),
|
||||
authCtx: testAuthCtx,
|
||||
listProvisioningProfilesAsync: jest.fn(() => []),
|
||||
},
|
||||
ios: {
|
||||
...getNewIosApiMock(),
|
||||
getIosAppCredentialsWithBuildCredentialsAsync: jest.fn(
|
||||
() => testCommonIosAppCredentialsFragment
|
||||
),
|
||||
createOrGetExistingAppleAppIdentifierAsync: jest.fn(() => testAppleAppIdentifierFragment),
|
||||
},
|
||||
});
|
||||
const appLookupParams = await getAppLookupParamsFromContextAsync(
|
||||
ctx,
|
||||
findApplicationTarget(testTargets)
|
||||
);
|
||||
const setupProvisioningProfileAction = new SetUpProvisioningProfile(
|
||||
appLookupParams,
|
||||
testTarget,
|
||||
IosDistributionType.AppStore
|
||||
);
|
||||
await setupProvisioningProfileAction.runAsync(ctx);
|
||||
|
||||
// expect build credentials to be created or updated on expo servers
|
||||
expect(jest.mocked(ctx.ios.createOrUpdateIosAppBuildCredentialsAsync).mock.calls.length).toBe(
|
||||
1
|
||||
);
|
||||
// expect provisioning profile to be deleted on expo servers
|
||||
expect(jest.mocked(ctx.ios.deleteProvisioningProfilesAsync).mock.calls.length).toBe(1);
|
||||
}
|
||||
);
|
||||
|
||||
test.each(testCases)(
|
||||
'skips setting up a Provisioning Profile with prior build credentials configured properly in %s Mode',
|
||||
async mode => {
|
||||
jest.mocked(validateProvisioningProfileAsync).mockImplementation(async () => true);
|
||||
const ctx = createCtxMock({
|
||||
nonInteractive: mode === 'NON_INTERACTIVE',
|
||||
appStore: {
|
||||
...getAppstoreMock(),
|
||||
defaultAuthenticationMode:
|
||||
mode === 'NON_INTERACTIVE' ? AuthenticationMode.API_KEY : AuthenticationMode.USER,
|
||||
ensureAuthenticatedAsync: jest.fn(() => testAuthCtx),
|
||||
authCtx: testAuthCtx,
|
||||
},
|
||||
ios: {
|
||||
...getNewIosApiMock(),
|
||||
getIosAppCredentialsWithBuildCredentialsAsync: jest.fn(
|
||||
() => testCommonIosAppCredentialsFragment
|
||||
),
|
||||
createOrGetExistingAppleAppIdentifierAsync: jest.fn(() => testAppleAppIdentifierFragment),
|
||||
},
|
||||
});
|
||||
const appLookupParams = await getAppLookupParamsFromContextAsync(
|
||||
ctx,
|
||||
findApplicationTarget(testTargets)
|
||||
);
|
||||
const setupProvisioningProfileAction = new SetUpProvisioningProfile(
|
||||
appLookupParams,
|
||||
testTarget,
|
||||
IosDistributionType.AppStore
|
||||
);
|
||||
await setupProvisioningProfileAction.runAsync(ctx);
|
||||
|
||||
// expect build credentials not to be created or updated on expo servers
|
||||
expect(jest.mocked(ctx.ios.createOrUpdateIosAppBuildCredentialsAsync).mock.calls.length).toBe(
|
||||
0
|
||||
);
|
||||
// expect provisioning profile not to be deleted on expo servers
|
||||
expect(jest.mocked(ctx.ios.deleteProvisioningProfilesAsync).mock.calls.length).toBe(0);
|
||||
}
|
||||
);
|
||||
|
||||
test.each(testCases)(
|
||||
'sets up a Provisioning Profile with no prior build credentials configured in %s Mode',
|
||||
async mode => {
|
||||
jest.mocked(validateProvisioningProfileAsync).mockImplementation(async () => false);
|
||||
const ctx = createCtxMock({
|
||||
nonInteractive: mode === 'NON_INTERACTIVE',
|
||||
appStore: {
|
||||
...getAppstoreMock(),
|
||||
defaultAuthenticationMode:
|
||||
mode === 'NON_INTERACTIVE' ? AuthenticationMode.API_KEY : AuthenticationMode.USER,
|
||||
ensureAuthenticatedAsync: jest.fn(() => testAuthCtx),
|
||||
authCtx: testAuthCtx,
|
||||
},
|
||||
ios: {
|
||||
...getNewIosApiMock(),
|
||||
createOrGetExistingAppleAppIdentifierAsync: jest.fn(() => testAppleAppIdentifierFragment),
|
||||
},
|
||||
});
|
||||
const appLookupParams = await getAppLookupParamsFromContextAsync(
|
||||
ctx,
|
||||
findApplicationTarget(testTargets)
|
||||
);
|
||||
const setupProvisioningProfileAction = new SetUpProvisioningProfile(
|
||||
appLookupParams,
|
||||
testTarget,
|
||||
IosDistributionType.AppStore
|
||||
);
|
||||
await setupProvisioningProfileAction.runAsync(ctx);
|
||||
|
||||
// expect build credentials to be created or updated on expo servers
|
||||
expect(jest.mocked(ctx.ios.createOrUpdateIosAppBuildCredentialsAsync).mock.calls.length).toBe(
|
||||
1
|
||||
);
|
||||
// expect provisioning profile not to be deleted on expo servers
|
||||
expect(jest.mocked(ctx.ios.deleteProvisioningProfilesAsync).mock.calls.length).toBe(0);
|
||||
}
|
||||
);
|
||||
|
||||
it('errors with --freeze-credentials flag', async () => {
|
||||
it('repairs existing Provisioning Profile with bad build credentials in Interactive Mode', async () => {
|
||||
jest.mocked(validateProvisioningProfileAsync).mockImplementation(async () => false);
|
||||
const ctx = createCtxMock({
|
||||
freezeCredentials: true,
|
||||
nonInteractive: false,
|
||||
appStore: {
|
||||
...getAppstoreMock(),
|
||||
ensureAuthenticatedAsync: jest.fn(() => testAuthCtx),
|
||||
authCtx: testAuthCtx,
|
||||
listProvisioningProfilesAsync: jest.fn(() => [
|
||||
{
|
||||
provisioningProfileId: nullthrows(
|
||||
testCommonIosAppCredentialsFragment.iosAppBuildCredentialsList[0].provisioningProfile
|
||||
).developerPortalIdentifier,
|
||||
},
|
||||
]),
|
||||
},
|
||||
ios: {
|
||||
...getNewIosApiMock(),
|
||||
getIosAppCredentialsWithBuildCredentialsAsync: jest.fn(
|
||||
() => testCommonIosAppCredentialsFragment
|
||||
),
|
||||
createOrGetExistingAppleAppIdentifierAsync: jest.fn(() => testAppleAppIdentifierFragment),
|
||||
createOrUpdateIosAppBuildCredentialsAsync: jest.fn(
|
||||
() => testIosAppBuildCredentialsFragment
|
||||
),
|
||||
},
|
||||
});
|
||||
const appLookupParams = await getAppLookupParamsFromContextAsync(
|
||||
ctx,
|
||||
@@ -225,9 +68,79 @@ describe('SetUpProvisioningProfile', () => {
|
||||
testTarget,
|
||||
IosDistributionType.AppStore
|
||||
);
|
||||
await expect(setupProvisioningProfileAction.runAsync(ctx)).rejects.toThrowError(
|
||||
ForbidCredentialModificationError
|
||||
await setupProvisioningProfileAction.runAsync(ctx);
|
||||
|
||||
// expect build credentials to be created or updated on expo servers
|
||||
expect(jest.mocked(ctx.ios.createOrUpdateIosAppBuildCredentialsAsync).mock.calls.length).toBe(
|
||||
1
|
||||
);
|
||||
// expect provisioning profile not to be deleted on expo servers
|
||||
expect(jest.mocked(ctx.ios.deleteProvisioningProfilesAsync).mock.calls.length).toBe(0);
|
||||
});
|
||||
it('sets up a new Provisioning Profile with bad build credentials in Interactive Mode', async () => {
|
||||
jest.mocked(validateProvisioningProfileAsync).mockImplementation(async () => false);
|
||||
const ctx = createCtxMock({
|
||||
nonInteractive: false,
|
||||
appStore: {
|
||||
...getAppstoreMock(),
|
||||
ensureAuthenticatedAsync: jest.fn(() => testAuthCtx),
|
||||
authCtx: testAuthCtx,
|
||||
listProvisioningProfilesAsync: jest.fn(() => []),
|
||||
},
|
||||
ios: {
|
||||
...getNewIosApiMock(),
|
||||
getIosAppCredentialsWithBuildCredentialsAsync: jest.fn(
|
||||
() => testCommonIosAppCredentialsFragment
|
||||
),
|
||||
createOrGetExistingAppleAppIdentifierAsync: jest.fn(() => testAppleAppIdentifierFragment),
|
||||
},
|
||||
});
|
||||
const appLookupParams = await getAppLookupParamsFromContextAsync(
|
||||
ctx,
|
||||
findApplicationTarget(testTargets)
|
||||
);
|
||||
const setupProvisioningProfileAction = new SetUpProvisioningProfile(
|
||||
appLookupParams,
|
||||
testTarget,
|
||||
IosDistributionType.AppStore
|
||||
);
|
||||
await setupProvisioningProfileAction.runAsync(ctx);
|
||||
|
||||
// expect build credentials to be created or updated on expo servers
|
||||
expect(jest.mocked(ctx.ios.createOrUpdateIosAppBuildCredentialsAsync).mock.calls.length).toBe(
|
||||
1
|
||||
);
|
||||
// expect provisioning profile to be deleted on expo servers
|
||||
expect(jest.mocked(ctx.ios.deleteProvisioningProfilesAsync).mock.calls.length).toBe(1);
|
||||
});
|
||||
it('skips setting up a Provisioning Profile with prior build credentials configured properly in Interactive Mode', async () => {
|
||||
jest.mocked(validateProvisioningProfileAsync).mockImplementation(async () => true);
|
||||
const ctx = createCtxMock({
|
||||
nonInteractive: false,
|
||||
appStore: {
|
||||
...getAppstoreMock(),
|
||||
ensureAuthenticatedAsync: jest.fn(() => testAuthCtx),
|
||||
authCtx: testAuthCtx,
|
||||
//listProvisioningProfilesAsync: jest.fn(() => []),
|
||||
},
|
||||
ios: {
|
||||
...getNewIosApiMock(),
|
||||
getIosAppCredentialsWithBuildCredentialsAsync: jest.fn(
|
||||
() => testCommonIosAppCredentialsFragment
|
||||
),
|
||||
createOrGetExistingAppleAppIdentifierAsync: jest.fn(() => testAppleAppIdentifierFragment),
|
||||
},
|
||||
});
|
||||
const appLookupParams = await getAppLookupParamsFromContextAsync(
|
||||
ctx,
|
||||
findApplicationTarget(testTargets)
|
||||
);
|
||||
const setupProvisioningProfileAction = new SetUpProvisioningProfile(
|
||||
appLookupParams,
|
||||
testTarget,
|
||||
IosDistributionType.AppStore
|
||||
);
|
||||
await setupProvisioningProfileAction.runAsync(ctx);
|
||||
|
||||
// expect build credentials not to be created or updated on expo servers
|
||||
expect(jest.mocked(ctx.ios.createOrUpdateIosAppBuildCredentialsAsync).mock.calls.length).toBe(
|
||||
@@ -236,8 +149,39 @@ describe('SetUpProvisioningProfile', () => {
|
||||
// expect provisioning profile not to be deleted on expo servers
|
||||
expect(jest.mocked(ctx.ios.deleteProvisioningProfilesAsync).mock.calls.length).toBe(0);
|
||||
});
|
||||
it('sets up a Provisioning Profile with no prior build credentials configured in Interactive Mode', async () => {
|
||||
jest.mocked(validateProvisioningProfileAsync).mockImplementation(async () => false);
|
||||
const ctx = createCtxMock({
|
||||
nonInteractive: false,
|
||||
appStore: {
|
||||
...getAppstoreMock(),
|
||||
ensureAuthenticatedAsync: jest.fn(() => testAuthCtx),
|
||||
authCtx: testAuthCtx,
|
||||
},
|
||||
ios: {
|
||||
...getNewIosApiMock(),
|
||||
createOrGetExistingAppleAppIdentifierAsync: jest.fn(() => testAppleAppIdentifierFragment),
|
||||
},
|
||||
});
|
||||
const appLookupParams = await getAppLookupParamsFromContextAsync(
|
||||
ctx,
|
||||
findApplicationTarget(testTargets)
|
||||
);
|
||||
const setupProvisioningProfileAction = new SetUpProvisioningProfile(
|
||||
appLookupParams,
|
||||
testTarget,
|
||||
IosDistributionType.AppStore
|
||||
);
|
||||
await setupProvisioningProfileAction.runAsync(ctx);
|
||||
|
||||
it('errors with wrong authentication type in nonInteractive mode', async () => {
|
||||
// expect build credentials to be created or updated on expo servers
|
||||
expect(jest.mocked(ctx.ios.createOrUpdateIosAppBuildCredentialsAsync).mock.calls.length).toBe(
|
||||
1
|
||||
);
|
||||
// expect provisioning profile not to be deleted on expo servers
|
||||
expect(jest.mocked(ctx.ios.deleteProvisioningProfilesAsync).mock.calls.length).toBe(0);
|
||||
});
|
||||
it('errors in Non Interactive Mode', async () => {
|
||||
jest.mocked(validateProvisioningProfileAsync).mockImplementation(async () => false);
|
||||
const ctx = createCtxMock({
|
||||
nonInteractive: true,
|
||||
@@ -252,7 +196,7 @@ describe('SetUpProvisioningProfile', () => {
|
||||
IosDistributionType.AppStore
|
||||
);
|
||||
await expect(setupProvisioningProfileAction.runAsync(ctx)).rejects.toThrowError(
|
||||
InsufficientAuthenticationNonInteractiveError
|
||||
MissingCredentialsNonInteractiveError
|
||||
);
|
||||
|
||||
// expect build credentials not to be created or updated on expo servers
|
||||
|
||||
@@ -326,7 +326,7 @@ export async function getDevicesForAppleTeamAsync(
|
||||
): Promise<AppleDeviceFragment[]> {
|
||||
return await AppleDeviceQuery.getAllByAppleTeamIdentifierAsync(
|
||||
graphqlClient,
|
||||
account.name,
|
||||
account.id,
|
||||
appleTeamIdentifier,
|
||||
{
|
||||
useCache,
|
||||
|
||||
+7
-60
@@ -4,76 +4,27 @@ import gql from 'graphql-tag';
|
||||
import { ExpoGraphqlClient } from '../../../../../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
import { withErrorHandlingAsync } from '../../../../../graphql/client';
|
||||
import {
|
||||
AppStoreConnectApiKeyByAccountQuery,
|
||||
AppStoreConnectApiKeyFragment,
|
||||
AppStoreConnectApiKeysPaginatedByAccountQuery,
|
||||
} from '../../../../../graphql/generated';
|
||||
import { AppStoreConnectApiKeyFragmentNode } from '../../../../../graphql/types/credentials/AppStoreConnectApiKey';
|
||||
import { Connection, QueryParams, fetchEntireDatasetAsync } from '../../../../../utils/relay';
|
||||
|
||||
export const AppStoreConnectApiKeyQuery = {
|
||||
async getAllForAccountAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
accountName: string
|
||||
): Promise<AppStoreConnectApiKeyFragment[]> {
|
||||
const paginatedGetterAsync = async (
|
||||
relayArgs: QueryParams
|
||||
): Promise<Connection<AppStoreConnectApiKeyFragment>> => {
|
||||
return await AppStoreConnectApiKeyQuery.getAllForAccountPaginatedAsync(
|
||||
graphqlClient,
|
||||
accountName,
|
||||
relayArgs
|
||||
);
|
||||
};
|
||||
return await fetchEntireDatasetAsync({
|
||||
paginatedGetterAsync,
|
||||
progressBarLabel: 'fetching ASC Keys...',
|
||||
});
|
||||
},
|
||||
async getAllForAccountPaginatedAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
accountName: string,
|
||||
{
|
||||
after,
|
||||
first,
|
||||
before,
|
||||
last,
|
||||
}: { after?: string; first?: number; before?: string; last?: number }
|
||||
): Promise<
|
||||
AppStoreConnectApiKeysPaginatedByAccountQuery['account']['byName']['appStoreConnectApiKeysPaginated']
|
||||
> {
|
||||
const data = await withErrorHandlingAsync(
|
||||
graphqlClient
|
||||
.query<AppStoreConnectApiKeysPaginatedByAccountQuery>(
|
||||
.query<AppStoreConnectApiKeyByAccountQuery>(
|
||||
gql`
|
||||
query AppStoreConnectApiKeysPaginatedByAccountQuery(
|
||||
$accountName: String!
|
||||
$after: String
|
||||
$first: Int
|
||||
$before: String
|
||||
$last: Int
|
||||
) {
|
||||
query AppStoreConnectApiKeyByAccountQuery($accountName: String!) {
|
||||
account {
|
||||
byName(accountName: $accountName) {
|
||||
id
|
||||
appStoreConnectApiKeysPaginated(
|
||||
after: $after
|
||||
first: $first
|
||||
before: $before
|
||||
last: $last
|
||||
) {
|
||||
edges {
|
||||
cursor
|
||||
node {
|
||||
id
|
||||
...AppStoreConnectApiKeyFragment
|
||||
}
|
||||
}
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
hasPreviousPage
|
||||
startCursor
|
||||
endCursor
|
||||
}
|
||||
appStoreConnectApiKeys {
|
||||
id
|
||||
...AppStoreConnectApiKeyFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,10 +33,6 @@ export const AppStoreConnectApiKeyQuery = {
|
||||
`,
|
||||
{
|
||||
accountName,
|
||||
after,
|
||||
first,
|
||||
before,
|
||||
last,
|
||||
},
|
||||
{
|
||||
additionalTypenames: ['AppStoreConnectApiKey'],
|
||||
@@ -93,6 +40,6 @@ export const AppStoreConnectApiKeyQuery = {
|
||||
)
|
||||
.toPromise()
|
||||
);
|
||||
return data.account.byName.appStoreConnectApiKeysPaginated;
|
||||
return data.account.byName.appStoreConnectApiKeys;
|
||||
},
|
||||
};
|
||||
@@ -1,3 +1,4 @@
|
||||
import assert from 'assert';
|
||||
import { print } from 'graphql';
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
@@ -6,16 +7,15 @@ import { DeviceNotFoundError } from '../../../../../devices/utils/errors';
|
||||
import { withErrorHandlingAsync } from '../../../../../graphql/client';
|
||||
import {
|
||||
AppleDevice,
|
||||
AppleDeviceFilterInput,
|
||||
AppleDeviceFragment,
|
||||
AppleDevicesByAppleTeamQuery,
|
||||
AppleDevicesByIdentifierQuery,
|
||||
AppleDevicesByTeamIdentifierQuery,
|
||||
AppleDevicesByTeamIdentifierQueryVariables,
|
||||
AppleDevicesPaginatedByAccountQuery,
|
||||
AppleTeamFragment,
|
||||
} from '../../../../../graphql/generated';
|
||||
import { AppleDeviceFragmentNode } from '../../../../../graphql/types/credentials/AppleDevice';
|
||||
import { AppleTeamFragmentNode } from '../../../../../graphql/types/credentials/AppleTeam';
|
||||
import { Connection, QueryParams, fetchEntireDatasetAsync } from '../../../../../utils/relay';
|
||||
import { formatAppleTeam } from '../../../actions/AppleTeamFormatting';
|
||||
|
||||
export type AppleDeviceFragmentWithAppleTeam = AppleDeviceFragment & {
|
||||
@@ -38,25 +38,51 @@ export type AppleDevicesByIdentifierQueryResult = AppleDeviceQueryResult & {
|
||||
export const AppleDeviceQuery = {
|
||||
async getAllByAppleTeamIdentifierAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
accountName: string,
|
||||
accountId: string,
|
||||
appleTeamIdentifier: string,
|
||||
{ useCache = true }: { useCache?: boolean } = {}
|
||||
): Promise<AppleDeviceFragmentWithAppleTeam[]> {
|
||||
const paginatedGetterAsync = async (
|
||||
relayArgs: QueryParams
|
||||
): Promise<Connection<AppleDeviceFragmentWithAppleTeam>> => {
|
||||
return await AppleDeviceQuery.getAllForAccountPaginatedAsync(graphqlClient, accountName, {
|
||||
...relayArgs,
|
||||
filter: {
|
||||
appleTeamIdentifier,
|
||||
},
|
||||
useCache,
|
||||
});
|
||||
};
|
||||
return await fetchEntireDatasetAsync({
|
||||
paginatedGetterAsync,
|
||||
progressBarLabel: 'Fetching Apple devices...',
|
||||
});
|
||||
const data = await withErrorHandlingAsync(
|
||||
graphqlClient
|
||||
.query<AppleDevicesByAppleTeamQuery>(
|
||||
gql`
|
||||
query AppleDevicesByAppleTeamQuery($accountId: ID!, $appleTeamIdentifier: String!) {
|
||||
appleTeam {
|
||||
byAppleTeamIdentifier(accountId: $accountId, identifier: $appleTeamIdentifier) {
|
||||
id
|
||||
...AppleTeamFragment
|
||||
appleDevices {
|
||||
id
|
||||
...AppleDeviceFragment
|
||||
appleTeam {
|
||||
id
|
||||
...AppleTeamFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${print(AppleTeamFragmentNode)}
|
||||
${print(AppleDeviceFragmentNode)}
|
||||
`,
|
||||
{
|
||||
accountId,
|
||||
appleTeamIdentifier,
|
||||
},
|
||||
{
|
||||
additionalTypenames: ['AppleDevice'],
|
||||
requestPolicy: useCache ? 'cache-first' : 'network-only',
|
||||
}
|
||||
)
|
||||
.toPromise()
|
||||
);
|
||||
assert(
|
||||
data.appleTeam.byAppleTeamIdentifier,
|
||||
'byAppleTeamIdentifier should be defined in this context - enforced by GraphQL'
|
||||
);
|
||||
const { appleDevices } = data.appleTeam.byAppleTeamIdentifier;
|
||||
assert(appleDevices, 'Apple Devices should be defined in this context - enforced by GraphQL');
|
||||
return appleDevices;
|
||||
},
|
||||
|
||||
async getAllForAppleTeamAsync(
|
||||
@@ -87,7 +113,6 @@ export const AppleDeviceQuery = {
|
||||
deviceClass
|
||||
enabled
|
||||
model
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,21 +138,41 @@ export const AppleDeviceQuery = {
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
accountName: string,
|
||||
identifier: string
|
||||
): Promise<AppleDeviceFragmentWithAppleTeam> {
|
||||
const paginatedGetterAsync = async (
|
||||
relayArgs: QueryParams
|
||||
): Promise<Connection<AppleDeviceFragmentWithAppleTeam>> => {
|
||||
return await AppleDeviceQuery.getAllForAccountPaginatedAsync(graphqlClient, accountName, {
|
||||
...relayArgs,
|
||||
filter: {
|
||||
identifier,
|
||||
},
|
||||
});
|
||||
};
|
||||
const devices = await fetchEntireDatasetAsync({
|
||||
paginatedGetterAsync,
|
||||
});
|
||||
const device = devices[0];
|
||||
): Promise<AppleDevicesByIdentifierQueryResult> {
|
||||
const data = await withErrorHandlingAsync(
|
||||
graphqlClient
|
||||
.query<AppleDevicesByIdentifierQuery>(
|
||||
gql`
|
||||
query AppleDevicesByIdentifier($accountName: String!, $identifier: String!) {
|
||||
account {
|
||||
byName(accountName: $accountName) {
|
||||
id
|
||||
appleDevices(identifier: $identifier) {
|
||||
id
|
||||
model
|
||||
identifier
|
||||
name
|
||||
deviceClass
|
||||
enabled
|
||||
appleTeam {
|
||||
id
|
||||
appleTeamIdentifier
|
||||
appleTeamName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
{ accountName, identifier },
|
||||
{
|
||||
additionalTypenames: ['AppleDevice', 'AppleTeam'],
|
||||
}
|
||||
)
|
||||
.toPromise()
|
||||
);
|
||||
|
||||
const device = data.account.byName.appleDevices[0];
|
||||
if (!device) {
|
||||
throw new DeviceNotFoundError(
|
||||
`Device with id ${identifier} was not found on account ${accountName}.`
|
||||
@@ -135,86 +180,4 @@ export const AppleDeviceQuery = {
|
||||
}
|
||||
return device;
|
||||
},
|
||||
async getAllForAccountPaginatedAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
accountName: string,
|
||||
{
|
||||
after,
|
||||
first,
|
||||
before,
|
||||
last,
|
||||
filter,
|
||||
useCache = true,
|
||||
}: {
|
||||
after?: string;
|
||||
first?: number;
|
||||
before?: string;
|
||||
last?: number;
|
||||
filter?: AppleDeviceFilterInput;
|
||||
useCache?: boolean;
|
||||
}
|
||||
): Promise<AppleDevicesPaginatedByAccountQuery['account']['byName']['appleDevicesPaginated']> {
|
||||
const data = await withErrorHandlingAsync(
|
||||
graphqlClient
|
||||
.query<AppleDevicesPaginatedByAccountQuery>(
|
||||
gql`
|
||||
query AppleDevicesPaginatedByAccountQuery(
|
||||
$accountName: String!
|
||||
$after: String
|
||||
$first: Int
|
||||
$before: String
|
||||
$last: Int
|
||||
$filter: AppleDeviceFilterInput
|
||||
) {
|
||||
account {
|
||||
byName(accountName: $accountName) {
|
||||
id
|
||||
appleDevicesPaginated(
|
||||
after: $after
|
||||
first: $first
|
||||
before: $before
|
||||
last: $last
|
||||
filter: $filter
|
||||
) {
|
||||
edges {
|
||||
cursor
|
||||
node {
|
||||
id
|
||||
...AppleDeviceFragment
|
||||
appleTeam {
|
||||
id
|
||||
...AppleTeamFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
hasPreviousPage
|
||||
startCursor
|
||||
endCursor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
${print(AppleTeamFragmentNode)}
|
||||
${print(AppleDeviceFragmentNode)}
|
||||
`,
|
||||
{
|
||||
accountName,
|
||||
after,
|
||||
first,
|
||||
before,
|
||||
last,
|
||||
filter,
|
||||
},
|
||||
{
|
||||
additionalTypenames: ['AppleDevice'],
|
||||
requestPolicy: useCache ? 'cache-first' : 'network-only',
|
||||
}
|
||||
)
|
||||
.toPromise()
|
||||
);
|
||||
return data.account.byName.appleDevicesPaginated;
|
||||
},
|
||||
};
|
||||
+7
-60
@@ -5,14 +5,13 @@ import gql from 'graphql-tag';
|
||||
import { ExpoGraphqlClient } from '../../../../../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
import { withErrorHandlingAsync } from '../../../../../graphql/client';
|
||||
import {
|
||||
AppleDistributionCertificateByAccountQuery,
|
||||
AppleDistributionCertificateByAppQuery,
|
||||
AppleDistributionCertificateFragment,
|
||||
AppleDistributionCertificatesPaginatedByAccountQuery,
|
||||
IosDistributionType,
|
||||
} from '../../../../../graphql/generated';
|
||||
import { AppleDistributionCertificateFragmentNode } from '../../../../../graphql/types/credentials/AppleDistributionCertificate';
|
||||
import { AppleTeamFragmentNode } from '../../../../../graphql/types/credentials/AppleTeam';
|
||||
import { Connection, QueryParams, fetchEntireDatasetAsync } from '../../../../../utils/relay';
|
||||
|
||||
export const AppleDistributionCertificateQuery = {
|
||||
async getForAppAsync(
|
||||
@@ -82,65 +81,17 @@ export const AppleDistributionCertificateQuery = {
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
accountName: string
|
||||
): Promise<AppleDistributionCertificateFragment[]> {
|
||||
const paginatedGetterAsync = async (
|
||||
relayArgs: QueryParams
|
||||
): Promise<Connection<AppleDistributionCertificateFragment>> => {
|
||||
return await AppleDistributionCertificateQuery.getAllForAccountPaginatedAsync(
|
||||
graphqlClient,
|
||||
accountName,
|
||||
relayArgs
|
||||
);
|
||||
};
|
||||
return await fetchEntireDatasetAsync({
|
||||
paginatedGetterAsync,
|
||||
progressBarLabel: 'fetching Apple Distribution Certificates...',
|
||||
});
|
||||
},
|
||||
async getAllForAccountPaginatedAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
accountName: string,
|
||||
{
|
||||
after,
|
||||
first,
|
||||
before,
|
||||
last,
|
||||
}: { after?: string; first?: number; before?: string; last?: number }
|
||||
): Promise<
|
||||
AppleDistributionCertificatesPaginatedByAccountQuery['account']['byName']['appleDistributionCertificatesPaginated']
|
||||
> {
|
||||
const data = await withErrorHandlingAsync(
|
||||
graphqlClient
|
||||
.query<AppleDistributionCertificatesPaginatedByAccountQuery>(
|
||||
.query<AppleDistributionCertificateByAccountQuery>(
|
||||
gql`
|
||||
query AppleDistributionCertificatesPaginatedByAccountQuery(
|
||||
$accountName: String!
|
||||
$after: String
|
||||
$first: Int
|
||||
$before: String
|
||||
$last: Int
|
||||
) {
|
||||
query AppleDistributionCertificateByAccountQuery($accountName: String!) {
|
||||
account {
|
||||
byName(accountName: $accountName) {
|
||||
id
|
||||
appleDistributionCertificatesPaginated(
|
||||
after: $after
|
||||
first: $first
|
||||
before: $before
|
||||
last: $last
|
||||
) {
|
||||
edges {
|
||||
cursor
|
||||
node {
|
||||
id
|
||||
...AppleDistributionCertificateFragment
|
||||
}
|
||||
}
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
hasPreviousPage
|
||||
startCursor
|
||||
endCursor
|
||||
}
|
||||
appleDistributionCertificates {
|
||||
id
|
||||
...AppleDistributionCertificateFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -149,10 +100,6 @@ export const AppleDistributionCertificateQuery = {
|
||||
`,
|
||||
{
|
||||
accountName,
|
||||
after,
|
||||
first,
|
||||
before,
|
||||
last,
|
||||
},
|
||||
{
|
||||
additionalTypenames: ['AppleDistributionCertificate'],
|
||||
@@ -160,6 +107,6 @@ export const AppleDistributionCertificateQuery = {
|
||||
)
|
||||
.toPromise()
|
||||
);
|
||||
return data.account.byName.appleDistributionCertificatesPaginated;
|
||||
return data.account.byName.appleDistributionCertificates;
|
||||
},
|
||||
};
|
||||
@@ -3,75 +3,25 @@ import gql from 'graphql-tag';
|
||||
|
||||
import { ExpoGraphqlClient } from '../../../../../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
import { withErrorHandlingAsync } from '../../../../../graphql/client';
|
||||
import {
|
||||
ApplePushKeyFragment,
|
||||
ApplePushKeysPaginatedByAccountQuery,
|
||||
} from '../../../../../graphql/generated';
|
||||
import { ApplePushKeyByAccountQuery, ApplePushKeyFragment } from '../../../../../graphql/generated';
|
||||
import { ApplePushKeyFragmentNode } from '../../../../../graphql/types/credentials/ApplePushKey';
|
||||
import { Connection, QueryParams, fetchEntireDatasetAsync } from '../../../../../utils/relay';
|
||||
|
||||
export const ApplePushKeyQuery = {
|
||||
async getAllForAccountAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
accountName: string
|
||||
): Promise<ApplePushKeyFragment[]> {
|
||||
const paginatedGetterAsync = async (
|
||||
relayArgs: QueryParams
|
||||
): Promise<Connection<ApplePushKeyFragment>> => {
|
||||
return await ApplePushKeyQuery.getAllForAccountPaginatedAsync(
|
||||
graphqlClient,
|
||||
accountName,
|
||||
relayArgs
|
||||
);
|
||||
};
|
||||
return await fetchEntireDatasetAsync({
|
||||
paginatedGetterAsync,
|
||||
progressBarLabel: 'fetching Apple Push Keys...',
|
||||
});
|
||||
},
|
||||
async getAllForAccountPaginatedAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
accountName: string,
|
||||
{
|
||||
after,
|
||||
first,
|
||||
before,
|
||||
last,
|
||||
}: { after?: string; first?: number; before?: string; last?: number }
|
||||
): Promise<ApplePushKeysPaginatedByAccountQuery['account']['byName']['applePushKeysPaginated']> {
|
||||
const data = await withErrorHandlingAsync(
|
||||
graphqlClient
|
||||
.query<ApplePushKeysPaginatedByAccountQuery>(
|
||||
.query<ApplePushKeyByAccountQuery>(
|
||||
gql`
|
||||
query ApplePushKeysPaginatedByAccountQuery(
|
||||
$accountName: String!
|
||||
$after: String
|
||||
$first: Int
|
||||
$before: String
|
||||
$last: Int
|
||||
) {
|
||||
query ApplePushKeyByAccountQuery($accountName: String!) {
|
||||
account {
|
||||
byName(accountName: $accountName) {
|
||||
id
|
||||
applePushKeysPaginated(
|
||||
after: $after
|
||||
first: $first
|
||||
before: $before
|
||||
last: $last
|
||||
) {
|
||||
edges {
|
||||
cursor
|
||||
node {
|
||||
id
|
||||
...ApplePushKeyFragment
|
||||
}
|
||||
}
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
hasPreviousPage
|
||||
startCursor
|
||||
endCursor
|
||||
}
|
||||
applePushKeys {
|
||||
id
|
||||
...ApplePushKeyFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,10 +30,6 @@ export const ApplePushKeyQuery = {
|
||||
`,
|
||||
{
|
||||
accountName,
|
||||
after,
|
||||
first,
|
||||
before,
|
||||
last,
|
||||
},
|
||||
{
|
||||
additionalTypenames: ['ApplePushKey'],
|
||||
@@ -91,6 +37,6 @@ export const ApplePushKeyQuery = {
|
||||
)
|
||||
.toPromise()
|
||||
);
|
||||
return data.account.byName.applePushKeysPaginated;
|
||||
return data.account.byName.applePushKeys;
|
||||
},
|
||||
};
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
} from '@expo/apple-utils';
|
||||
import assert from 'assert';
|
||||
import chalk from 'chalk';
|
||||
import * as getenv from 'getenv';
|
||||
import { int } from 'getenv';
|
||||
|
||||
import {
|
||||
ApiKeyAuthCtx,
|
||||
@@ -191,7 +191,7 @@ async function authenticateAsUserAsync(options: Options = {}): Promise<AuthCtx>
|
||||
cookies: options.cookies,
|
||||
teamId: options.teamId ?? process.env.EXPO_APPLE_TEAM_ID,
|
||||
providerId: process.env.EXPO_APPLE_PROVIDER_ID
|
||||
? getenv.int('EXPO_APPLE_PROVIDER_ID')
|
||||
? int(process.env.EXPO_APPLE_PROVIDER_ID)
|
||||
: undefined,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -18,18 +18,13 @@ export class SetUpBuildCredentialsCommandAction {
|
||||
public readonly projectInfo: CredentialsContextProjectInfo | null,
|
||||
public readonly getDynamicPrivateProjectConfigAsync: DynamicConfigContextFn,
|
||||
private readonly platform: Platform,
|
||||
private readonly profileName: string,
|
||||
private readonly projectDir: string
|
||||
private readonly profileName: string
|
||||
) {}
|
||||
|
||||
async runAsync(): Promise<void> {
|
||||
if (this.platform === Platform.IOS) {
|
||||
return await new SetUpIosBuildCredentials(this, this.projectDir, this.profileName).runAsync();
|
||||
return await new SetUpIosBuildCredentials(this, process.cwd(), this.profileName).runAsync();
|
||||
}
|
||||
return await new SetUpAndroidBuildCredentials(
|
||||
this,
|
||||
this.projectDir,
|
||||
this.profileName
|
||||
).runAsync();
|
||||
return await new SetUpAndroidBuildCredentials(this, process.cwd(), this.profileName).runAsync();
|
||||
}
|
||||
}
|
||||
@@ -38,7 +38,7 @@ export class SetUpIosBuildCredentials extends ManageIos {
|
||||
}
|
||||
|
||||
const ctx = new CredentialsContext({
|
||||
projectDir: this.projectDir,
|
||||
projectDir: process.cwd(),
|
||||
projectInfo,
|
||||
user: this.callingAction.actor,
|
||||
graphqlClient: this.callingAction.graphqlClient,
|
||||
|
||||
@@ -44,7 +44,6 @@ describe(AccountResolver, () => {
|
||||
],
|
||||
isExpoAdmin: false,
|
||||
featureGates: {},
|
||||
preferences: {},
|
||||
};
|
||||
|
||||
describe('when inside project dir', () => {
|
||||
@@ -52,7 +51,6 @@ describe(AccountResolver, () => {
|
||||
jest.mocked(AppQuery.byIdAsync).mockResolvedValue({
|
||||
id: 'test-project-id',
|
||||
fullName: '@foo/wat',
|
||||
name: 'wat',
|
||||
slug: 'wat',
|
||||
ownerAccount: {
|
||||
id: 'account_id_888',
|
||||
|
||||
@@ -34,7 +34,7 @@ export default class DeviceCreateAction {
|
||||
await runDeveloperPortalMethodAsync(
|
||||
this.graphqlClient,
|
||||
this.appStoreApi,
|
||||
this.account,
|
||||
this.account.id,
|
||||
this.appleTeam
|
||||
);
|
||||
} else if (method === RegistrationMethod.INPUT) {
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
import AppStoreApi from '../../../credentials/ios/appstore/AppStoreApi';
|
||||
import { getRequestContext } from '../../../credentials/ios/appstore/authenticate';
|
||||
import { AuthCtx } from '../../../credentials/ios/appstore/authenticateTypes';
|
||||
import { AccountFragment, AppleDeviceClass, AppleTeam } from '../../../graphql/generated';
|
||||
import { AppleDeviceClass, AppleTeam } from '../../../graphql/generated';
|
||||
import Log from '../../../log';
|
||||
import { ora } from '../../../ora';
|
||||
import { promptAsync } from '../../../prompts';
|
||||
@@ -25,14 +25,14 @@ const DEVICE_CLASS_TO_GRAPHQL_TYPE: Partial<Record<DeviceClass, AppleDeviceClass
|
||||
export async function runDeveloperPortalMethodAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
appStoreApi: AppStoreApi,
|
||||
account: AccountFragment,
|
||||
accountId: string,
|
||||
appleTeam: Pick<AppleTeam, 'appleTeamIdentifier' | 'appleTeamName' | 'id'>
|
||||
): Promise<void> {
|
||||
const appleAuthCtx = await appStoreApi.ensureAuthenticatedAsync();
|
||||
const unregisteredPortalDevices = await findUnregisteredPortalDevicesAsync(
|
||||
graphqlClient,
|
||||
appleAuthCtx,
|
||||
account.name,
|
||||
accountId,
|
||||
appleTeam
|
||||
);
|
||||
if (unregisteredPortalDevices.length === 0) {
|
||||
@@ -40,7 +40,7 @@ export async function runDeveloperPortalMethodAsync(
|
||||
return;
|
||||
}
|
||||
const devicesToImport = await chooseDevicesToImportAsync(unregisteredPortalDevices);
|
||||
await importDevicesAsync(graphqlClient, account.id, appleTeam, devicesToImport);
|
||||
await importDevicesAsync(graphqlClient, accountId, appleTeam, devicesToImport);
|
||||
}
|
||||
|
||||
async function importDevicesAsync(
|
||||
@@ -88,12 +88,12 @@ async function importDeviceChunkAsync(
|
||||
async function findUnregisteredPortalDevicesAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
appleAuthCtx: AuthCtx,
|
||||
accountName: string,
|
||||
accountId: string,
|
||||
appleTeam: Pick<AppleTeam, 'appleTeamIdentifier' | 'appleTeamName' | 'id'>
|
||||
): Promise<Device[]> {
|
||||
const expoRegisteredDevices = await AppleDeviceQuery.getAllByAppleTeamIdentifierAsync(
|
||||
graphqlClient,
|
||||
accountName,
|
||||
accountId,
|
||||
appleTeam.appleTeamIdentifier,
|
||||
{ useCache: false }
|
||||
);
|
||||
|
||||
@@ -26,6 +26,7 @@ export async function runRegistrationUrlMethodAsync(
|
||||
Log.log(
|
||||
'Open the following link on your iOS devices (or scan the QR code) and follow the instructions to install the development profile:'
|
||||
);
|
||||
Log.newLine();
|
||||
Log.log(chalk.green(`${registrationURL}`));
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ const DEVICE_CLASS_DISPLAY_NAMES: Record<AppleDeviceClass, string> = {
|
||||
[AppleDeviceClass.Iphone]: 'iPhone',
|
||||
[AppleDeviceClass.Ipad]: 'iPad',
|
||||
[AppleDeviceClass.Mac]: 'Mac',
|
||||
[AppleDeviceClass.Unknown]: 'Unknown',
|
||||
};
|
||||
|
||||
function formatDeviceClass(device: Device | NewDevice): string {
|
||||
|
||||
@@ -6,6 +6,5 @@ export function createCtxMock(options: { nonInteractive?: boolean } = {}): EASUp
|
||||
graphqlClient: jest.fn() as any,
|
||||
nonInteractive: options.nonInteractive ?? false,
|
||||
app: { exp: testAppJson, projectId: 'test-project-id', projectDir: '/' },
|
||||
vcsClient: jest.fn() as any,
|
||||
};
|
||||
}
|
||||
@@ -1,13 +1,11 @@
|
||||
import { ExpoConfig } from '@expo/config-types';
|
||||
|
||||
import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
import { Client } from '../vcs/vcs';
|
||||
|
||||
export type EASUpdateContext = {
|
||||
graphqlClient: ExpoGraphqlClient;
|
||||
nonInteractive: boolean;
|
||||
app: { exp: ExpoConfig; projectId: string; projectDir: string };
|
||||
vcsClient: Client;
|
||||
};
|
||||
|
||||
export interface EASUpdateAction<T = any> {
|
||||
|
||||
+276
-782
File diff suppressed because it is too large.
Load diff
@@ -14,8 +14,6 @@ import {
|
||||
} from '../generated';
|
||||
import { UpdateFragmentNode } from '../types/Update';
|
||||
|
||||
const turtleJobRunId = process.env.EAS_BUILD_ID;
|
||||
|
||||
export const PublishMutation = {
|
||||
async getUploadURLsAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
@@ -59,12 +57,7 @@ export const PublishMutation = {
|
||||
}
|
||||
${print(UpdateFragmentNode)}
|
||||
`,
|
||||
{
|
||||
publishUpdateGroupsInput: publishUpdateGroupsInput.map(input => ({
|
||||
...input,
|
||||
turtleJobRunId,
|
||||
})),
|
||||
}
|
||||
{ publishUpdateGroupsInput }
|
||||
)
|
||||
.toPromise()
|
||||
);
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
import assert from 'assert';
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
import { withErrorHandlingAsync } from '../client';
|
||||
import {
|
||||
MarkCliDoneInOnboardingUserPreferencesMutation,
|
||||
MarkCliDoneInOnboardingUserPreferencesMutationVariables,
|
||||
UserPreferencesOnboardingInput,
|
||||
} from '../generated';
|
||||
|
||||
export const UserPreferencesMutation = {
|
||||
async markCliDoneInOnboardingUserPreferencesAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
userPreferencesData: Partial<UserPreferencesOnboardingInput> & { appId: string }
|
||||
): Promise<{
|
||||
isCLIDone: boolean;
|
||||
appId: string;
|
||||
}> {
|
||||
const data = await withErrorHandlingAsync(
|
||||
graphqlClient
|
||||
.mutation<
|
||||
MarkCliDoneInOnboardingUserPreferencesMutation,
|
||||
MarkCliDoneInOnboardingUserPreferencesMutationVariables
|
||||
>(
|
||||
gql`
|
||||
mutation MarkCliDoneInOnboardingUserPreferencesMutation(
|
||||
$preferences: UserPreferencesInput!
|
||||
) {
|
||||
me {
|
||||
setPreferences(preferences: $preferences) {
|
||||
onboarding {
|
||||
appId
|
||||
isCLIDone
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
{
|
||||
preferences: {
|
||||
onboarding: {
|
||||
...userPreferencesData,
|
||||
isCLIDone: true,
|
||||
lastUsed: new Date().toISOString(),
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
.toPromise()
|
||||
);
|
||||
const appId = data.me.setPreferences.onboarding?.appId;
|
||||
assert(appId, 'App ID must be defined');
|
||||
const isCLIDone = data.me.setPreferences.onboarding?.isCLIDone;
|
||||
assert(isCLIDone, 'isCLIDone must be defined and true');
|
||||
return {
|
||||
appId,
|
||||
isCLIDone,
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -22,16 +22,6 @@ export const UserQuery = {
|
||||
id
|
||||
...AccountFragment
|
||||
}
|
||||
preferences {
|
||||
onboarding {
|
||||
appId
|
||||
platform
|
||||
deviceType
|
||||
environment
|
||||
isCLIDone
|
||||
lastUsed
|
||||
}
|
||||
}
|
||||
}
|
||||
... on Robot {
|
||||
firstName
|
||||
|
||||
@@ -5,7 +5,6 @@ import { AccountFragmentNode } from './Account';
|
||||
export const AppFragmentNode = gql`
|
||||
fragment AppFragment on App {
|
||||
id
|
||||
name
|
||||
fullName
|
||||
slug
|
||||
ownerAccount {
|
||||
@@ -13,13 +12,6 @@ export const AppFragmentNode = gql`
|
||||
name
|
||||
...AccountFragment
|
||||
}
|
||||
githubRepository {
|
||||
id
|
||||
metadata {
|
||||
githubRepoOwnerName
|
||||
githubRepoName
|
||||
}
|
||||
}
|
||||
}
|
||||
${AccountFragmentNode}
|
||||
`;
|
||||
@@ -37,6 +37,7 @@ export const BuildFragmentNode = gql`
|
||||
}
|
||||
}
|
||||
channel
|
||||
releaseChannel
|
||||
distribution
|
||||
iosEnterpriseProvisioning
|
||||
buildProfile
|
||||
@@ -54,6 +55,7 @@ export const BuildFragmentNode = gql`
|
||||
updatedAt
|
||||
message
|
||||
completedAt
|
||||
resourceClass
|
||||
expirationDate
|
||||
isForIosSimulator
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ export const APPLE_DEVICE_CLASS_LABELS: Record<AppleDeviceClass, string> = {
|
||||
[AppleDeviceClass.Ipad]: 'iPad',
|
||||
[AppleDeviceClass.Iphone]: 'iPhone',
|
||||
[AppleDeviceClass.Mac]: 'Mac',
|
||||
[AppleDeviceClass.Unknown]: 'Unknown',
|
||||
};
|
||||
|
||||
export const AppleDeviceFragmentNode = gql`
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
import spawnAsync from '@expo/spawn-async';
|
||||
|
||||
import { runCommandAsync } from './runCommand';
|
||||
import Log from '../log';
|
||||
import { confirmAsync, promptAsync } from '../prompts';
|
||||
|
||||
export async function runGitCloneAsync({
|
||||
targetProjectDir,
|
||||
githubRepositoryName,
|
||||
githubUsername,
|
||||
cloneMethod,
|
||||
}: {
|
||||
githubUsername: string;
|
||||
githubRepositoryName: string;
|
||||
targetProjectDir: string;
|
||||
cloneMethod: 'ssh' | 'https';
|
||||
}): Promise<{
|
||||
targetProjectDir: string;
|
||||
}> {
|
||||
const url =
|
||||
cloneMethod === 'ssh'
|
||||
? `[email protected]:${githubUsername}/${githubRepositoryName}.git`
|
||||
: `https://github.com/${githubUsername}/${githubRepositoryName}.git`;
|
||||
try {
|
||||
await runCommandAsync({
|
||||
command: 'git',
|
||||
args: ['clone', url, targetProjectDir],
|
||||
shouldPrintStderrLineAsStdout: line => {
|
||||
return line.includes('Cloning into');
|
||||
},
|
||||
showSpinner: false,
|
||||
});
|
||||
return { targetProjectDir };
|
||||
} catch (error: any) {
|
||||
if (error.stderr.includes('already exists')) {
|
||||
Log.warn(`Directory ${targetProjectDir} already exists.`);
|
||||
const shouldContinue = await confirmAsync({
|
||||
message: 'Do you want to clone your project to some other destination?',
|
||||
});
|
||||
if (!shouldContinue) {
|
||||
throw new Error('Directory already exists. Aborting...');
|
||||
}
|
||||
const { newTargetProjectDir } = await promptAsync({
|
||||
type: 'text',
|
||||
name: 'newTargetProjectDir',
|
||||
message: 'New target directory path:',
|
||||
validate: (input: string) => input !== '',
|
||||
});
|
||||
return await runGitCloneAsync({
|
||||
githubRepositoryName,
|
||||
githubUsername,
|
||||
targetProjectDir: newTargetProjectDir,
|
||||
cloneMethod,
|
||||
});
|
||||
} else if (error.stderr.includes('Permission denied')) {
|
||||
Log.warn(
|
||||
`It seems like you do not have permission to clone the repository using ${cloneMethod}.`
|
||||
);
|
||||
const newMethod = cloneMethod === 'ssh' ? 'https' : 'ssh';
|
||||
const shouldContinue = await confirmAsync({
|
||||
message: `Do you want to clone the repository using ${newMethod} instead?`,
|
||||
});
|
||||
if (!shouldContinue) {
|
||||
throw new Error('Permission denied. Aborting...');
|
||||
}
|
||||
return await runGitCloneAsync({
|
||||
githubRepositoryName,
|
||||
githubUsername,
|
||||
targetProjectDir,
|
||||
cloneMethod: newMethod,
|
||||
});
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function runGitPushAsync({
|
||||
targetProjectDir,
|
||||
}: {
|
||||
targetProjectDir: string;
|
||||
}): Promise<void> {
|
||||
await runCommandAsync({
|
||||
command: 'git',
|
||||
args: ['push'],
|
||||
cwd: targetProjectDir,
|
||||
});
|
||||
}
|
||||
|
||||
export async function canAccessRepositoryUsingSshAsync({
|
||||
githubUsername,
|
||||
githubRepositoryName,
|
||||
}: {
|
||||
githubUsername: string;
|
||||
githubRepositoryName: string;
|
||||
}): Promise<boolean> {
|
||||
try {
|
||||
await spawnAsync('git', [
|
||||
'ls-remote',
|
||||
`[email protected]:${githubUsername}/${githubRepositoryName}.git`,
|
||||
]);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
import { runCommandAsync } from './runCommand';
|
||||
|
||||
export async function installDependenciesAsync({
|
||||
projectDir,
|
||||
}: {
|
||||
projectDir: string;
|
||||
}): Promise<void> {
|
||||
// TODO: add support for other package managers
|
||||
await runCommandAsync({
|
||||
command: 'npm',
|
||||
args: ['install'],
|
||||
cwd: projectDir,
|
||||
shouldShowStderrLine: line => {
|
||||
return (
|
||||
!line.includes('WARN') &&
|
||||
!line.includes('deprecated') &&
|
||||
!line.includes('no longer maintained') &&
|
||||
!line.includes('has been moved') &&
|
||||
!(line === 'npm')
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
import spawnAsync from '@expo/spawn-async';
|
||||
import chalk from 'chalk';
|
||||
|
||||
import Log from '../log';
|
||||
import { Ora, ora } from '../ora';
|
||||
|
||||
export async function runCommandAsync({
|
||||
cwd,
|
||||
args,
|
||||
command,
|
||||
shouldShowStderrLine,
|
||||
shouldPrintStderrLineAsStdout,
|
||||
showSpinner = true,
|
||||
}: {
|
||||
cwd?: string;
|
||||
args: string[];
|
||||
command: string;
|
||||
shouldShowStderrLine?: (line: string) => boolean;
|
||||
shouldPrintStderrLineAsStdout?: (line: string) => boolean;
|
||||
showSpinner?: boolean;
|
||||
}): Promise<void> {
|
||||
Log.log(`🏗️ Running ${chalk.bold(`${command} ${args.join(' ')}`)}...`);
|
||||
let spinner: Ora | undefined;
|
||||
if (showSpinner) {
|
||||
spinner = ora(`${chalk.bold(`${command} ${args.join(' ')}`)}`).start();
|
||||
}
|
||||
const spawnPromise = spawnAsync(command, args, {
|
||||
stdio: ['inherit', 'pipe', 'pipe'],
|
||||
cwd,
|
||||
});
|
||||
const {
|
||||
child: { stdout, stderr },
|
||||
} = spawnPromise;
|
||||
if (!stdout || !stderr) {
|
||||
throw new Error(`Failed to spawn ${command}`);
|
||||
}
|
||||
|
||||
stdout.on('data', data => {
|
||||
for (const line of data.toString().trim().split('\n')) {
|
||||
Log.log(`${chalk.gray(`[${command}]`)} ${line}`);
|
||||
}
|
||||
});
|
||||
stderr.on('data', data => {
|
||||
for (const line of data.toString().trim().split('\n')) {
|
||||
if (shouldShowStderrLine && !shouldShowStderrLine(line)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const log = `${chalk.gray(`[${command}]`)} ${line}`;
|
||||
if (shouldPrintStderrLineAsStdout && shouldPrintStderrLineAsStdout(line)) {
|
||||
Log.log(log);
|
||||
} else {
|
||||
Log.warn(`${chalk.gray(`[${command}]`)} ${line}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
await spawnPromise;
|
||||
} catch (error) {
|
||||
if (showSpinner) {
|
||||
spinner?.fail(`${chalk.bold(`${command} ${args.join(' ')}`)} failed`);
|
||||
} else {
|
||||
Log.error(`❌ ${chalk.bold(`${command} ${args.join(' ')}`)} failed`);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (showSpinner) {
|
||||
spinner?.succeed(`${chalk.bold(`${command} ${args.join(' ')}`)} succeeded`);
|
||||
} else {
|
||||
Log.log(`✅ ${chalk.bold(`${command} ${args.join(' ')}`)} succeeded`);
|
||||
}
|
||||
Log.log('');
|
||||
}
|
||||
Loaded 100 of 139 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user