Compare commits

..
Author SHA1 Message Date
Quinlan Jung 2be2536654 Temporary Commit at 6/25/2024, 10:08:24 AM 2024-06-25 10:08:24 -07:00
359 changed files with 2739 additions and 30158 deletions

No files matched your search

-1
View File
@@ -5,4 +5,3 @@
packages/eas-cli/src/graphql/generated.ts
node_modules
ts-declarations
+6
View File
@@ -30,6 +30,12 @@ module.exports = {
},
],
'no-underscore-dangle': ['error', { allow: ['__typename'] }],
'@typescript-eslint/explicit-function-return-type': [
'warn',
{
allowExpressions: true,
},
],
'async-protect/async-suffix': 'error',
'node/no-sync': 'error',
},
-26
View File
@@ -1,26 +0,0 @@
commentConfiguration:
preamble: 'Subscribed to pull request'
epilogue: 'Generated by [CodeMention](https://github.com/expo/expo/actions/workflows/codemention.yaml)'
rules:
- patterns: ['**/*']
mentions: ['szdziedzic', 'khamilowicz', 'sjchmiela']
- patterns: ['packages/eas-cli/src/build/**']
mentions: ['szdziedzic', 'khamilowicz', 'sjchmiela']
- patterns: ['packages/eas-cli/src/commands/build/**']
mentions: ['szdziedzic', 'khamilowicz', 'sjchmiela']
- patterns: ['packages/eas-cli/src/submit/**']
mentions: ['szdziedzic', 'khamilowicz', 'sjchmiela']
- patterns: ['packages/eas-cli/src/commands/submit.ts']
mentions: ['szdziedzic', 'khamilowicz', 'sjchmiela', 'radoslawkrzemien']
- patterns: ['packages/eas-cli/src/update/**']
mentions: ['EvanBacon', 'byCedric', 'wschurman']
- patterns: ['packages/eas-cli/src/commands/update/**']
mentions: ['EvanBacon', 'byCedric', 'wschurman']
- patterns: ['packages/eas-cli/schema/**']
mentions: ['bycedric']
- patterns: ['packages/eas-cli/src/metadata/**']
mentions: ['bycedric']
- patterns: ['packages/eas-cli/src/commands/metadata/**']
mentions: ['bycedric']
- patterns: ['packages/eas-json/**']
mentions: ['szdziedzic', 'khamilowicz', 'sjchmiela']
+48
View File
@@ -0,0 +1,48 @@
name: Changelog bot
on:
issue_comment:
types: [created]
jobs:
pr-commented:
runs-on: ubuntu-latest
if: ${{ github.event.issue.pull_request && github.event.issue.user.login == github.event.comment.user.login && startsWith(github.event.comment.body, '/changelog-entry ') }}
steps:
- uses: actions/checkout@v2
with:
token: ${{ secrets.EXPO_BOT_PAT }}
- uses: actions/setup-node@v2
with:
node-version: 20
- name: Checkout Pull Request
run: gh pr checkout ${{ github.event.issue.number }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Install dependencies
working-directory: ./scripts
run: yarn install --frozen-lockfile --check-files
- name: Add changelog entry
working-directory: ./scripts
run: |
PARAMS=${PR_COMMENT_BODY#/changelog-entry }
if [[ ! "$PARAMS" =~ " " ]]; then
echo "Invalid /changelog-entry command"
exit 1
fi
CATEGORY=$( cut -d ' ' -f 1 <<< "$PARAMS" | sed -e 's/^[[:space:]]*//' )
MESSAGE=$( cut -d ' ' -f 2- <<< "$PARAMS" | sed -e 's/^[[:space:]]*//' )
yarn changelog-entry "$CATEGORY" "$MESSAGE"
env:
GITHUB_PR_AUTHOR: ${{ github.event.issue.user.login }}
GITHUB_PR_NUMBER: ${{ github.event.issue.number }}
PR_COMMENT_BODY: ${{ github.event.comment.body }}
- name: Commit and push
run: |
# use the last commit author name and email
git config --global user.name "$(git --no-pager log --format=format:'%an' -n 1)"
git config --global user.email "$(git --no-pager log --format=format:'%ae' -n 1)"
git add CHANGELOG.md
git commit -m "update CHANGELOG.md"
git push
+2 -1
View File
@@ -36,5 +36,6 @@ jobs:
refresh-message-position: true
message: ${{ contains(github.event.pull_request.labels.*.name, 'no changelog') && '⏩ The changelog entry check has been skipped since the "no changelog" label is present.' || '✅ Thank you for adding the changelog entry!' }}
message-failure: |
❌ It looks like a changelog entry is missing for this PR. Add it manually to CHANGELOG.md.
❌ It looks like a changelog entry is missing for this PR. You have two options: you can add it manually, or you can use the changelog bot to do it for you.
🤖 To use the bot, simply comment on this PR with the command `/changelog-entry [breaking-change|new-feature|bug-fix|chore] [message]`.
⏩ If this PR doesn't require a changelog entry, such as if it's an internal change that doesn't affect the user experience, you can add the "no changelog" label to the PR.
-14
View File
@@ -1,14 +0,0 @@
name: codemention
on:
pull_request_target:
types: [opened, synchronize, ready_for_review]
jobs:
codemention:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: tobyhs/[email protected]
with:
githubToken: ${{ secrets.GITHUB_TOKEN }}
-277
View File
@@ -12,283 +12,6 @@ This is the log of notable changes to EAS CLI and related packages.
### 🧹 Chores
- Upgrade `@expo` packages to SDK 52 versions. ([#2706](https://github.com/expo/eas-cli/pull/2706) by [@szdziedzic](https://github.com/szdziedzic))
## [13.4.1](https://github.com/expo/eas-cli/releases/tag/v13.4.1) - 2024-11-22
### 🧹 Chores
- Improve logging in `eas env:pull`. ([#2720](https://github.com/expo/eas-cli/pull/2720) by [@szdziedzic](https://github.com/szdziedzic))
## [13.4.0](https://github.com/expo/eas-cli/releases/tag/v13.4.0) - 2024-11-22
### 🎉 New features
- Calculate fingerprint on each update. ([#2687](https://github.com/expo/eas-cli/pull/2687) by [@quinlanj](https://github.com/quinlanj))
- Calculate fingerprint on each update republish. ([#2708](https://github.com/expo/eas-cli/pull/2708) by [@quinlanj](https://github.com/quinlanj))
- Add `eas env` commands. ([#2711](https://github.com/expo/eas-cli/pull/2711) by [@szdziedzic](https://github.com/szdziedzic))
- Add `--environment` flag to `eas update` command. ([#2711](https://github.com/expo/eas-cli/pull/2711) by [@szdziedzic](https://github.com/szdziedzic))
- Load readable environment variables from EAS servers on every build. ([#2644](https://github.com/expo/eas-cli/pull/2644) by [@szdziedzic](https://github.com/szdziedzic))
- Add environment field to `eas.schema.json`. ([#2719](https://github.com/expo/eas-cli/pull/2719) by [@szdziedzic](https://github.com/szdziedzic))
### 🧹 Chores
- Deprecate `eas secret` commands. ([#2705](https://github.com/expo/eas-cli/pull/2705) by [@szdziedzic](https://github.com/szdziedzic))
## [13.3.0](https://github.com/expo/eas-cli/releases/tag/v13.3.0) - 2024-11-18
### 🎉 New features
- Added `eas workflow` commands. [#2650](https://github.com/expo/eas-cli/pull/2650), [#2669](https://github.com/expo/eas-cli/pull/2669), [#2678](https://github.com/expo/eas-cli/pull/2678) by [@jonsamp](https://github.com/jonsamp) and [@sjchmiela](https://github.com/sjchmiela) ([#2683](https://github.com/expo/eas-cli/pull/2683) by [@sjchmiela](https://github.com/sjchmiela))
## [13.2.3](https://github.com/expo/eas-cli/releases/tag/v13.2.3) - 2024-11-15
## [13.2.2](https://github.com/expo/eas-cli/releases/tag/v13.2.2) - 2024-11-15
## [13.2.1](https://github.com/expo/eas-cli/releases/tag/v13.2.1) - 2024-11-14
## [13.2.0](https://github.com/expo/eas-cli/releases/tag/v13.2.0) - 2024-11-13
### 🎉 New features
- Add EAS_SKIP_AUTO_FINGERPRINT to skip fingerprint computation on build ([#2675](https://github.com/expo/eas-cli/pull/2675) by [@quinlanj](https://github.com/quinlanj))
- Default build-logger-level to debug when EXPO_DEBUG is set. ([#2676](https://github.com/expo/eas-cli/pull/2676) by [@wschurman](https://github.com/wschurman))
## [13.1.1](https://github.com/expo/eas-cli/releases/tag/v13.1.1) - 2024-11-08
## [13.1.0](https://github.com/expo/eas-cli/releases/tag/v13.1.0) - 2024-11-07
### 🎉 New features
- Compute fingerprint for builds with SDK 52 and higher ([#2663](https://github.com/expo/eas-cli/pull/2663) by [@quinlanj](https://github.com/quinlanj))
## [13.0.1](https://github.com/expo/eas-cli/releases/tag/v13.0.1) - 2024-11-05
### 🧹 Chores
- Upgrade EAS Metadata with new properties from App Store. ([#2671](https://github.com/expo/eas-cli/pull/2671) by [@byCedric](https://github.com/byCedric))
## [13.0.0](https://github.com/expo/eas-cli/releases/tag/v13.0.0) - 2024-11-05
### 🛠 Breaking changes
- Resolve versioned expo config using `npx expo config` command instead of using fixed `@expo/config` version shipped with EAS CLI, if available. ([#2529](https://github.com/expo/eas-cli/pull/2529) by [@szdziedzic](https://github.com/szdziedzic))
### 🧹 Chores
- Add `macos-sonoma-14.6-xcode-16.1` image and `sdk-52` image tag to `eas.schema.json`. ([#2666](https://github.com/expo/eas-cli/pull/2666) by [@szdziedzic](https://github.com/szdziedzic))
- Update `@expo` packages versions. ([#2530](https://github.com/expo/eas-cli/pull/2530) by [@szdziedzic](https://github.com/szdziedzic))
## [12.6.2](https://github.com/expo/eas-cli/releases/tag/v12.6.2) - 2024-10-29
### 🐛 Bug fixes
- Make email case insensitive during Apple authentication. ([#2659](https://github.com/expo/eas-cli/pull/2659) by [@byCedric](https://github.com/byCedric))
## [12.6.1](https://github.com/expo/eas-cli/releases/tag/v12.6.1) - 2024-10-25
### 🧹 Chores
- Create dynamic logged in context field and clean up erroneous SessionManager context field uses. ([#2648](https://github.com/expo/eas-cli/pull/2648) by [@wschurman](https://github.com/wschurman))
## [12.6.0](https://github.com/expo/eas-cli/releases/tag/v12.6.0) - 2024-10-21
### 🎉 New features
- Add `eas channel:pause` and `eas channel:resume` commands to pause/resume update delivery to builds using specific update channels and display paused status in channel details output. ([#2614](https://github.com/expo/eas-cli/pull/2614) by [@fiberjw](https://github.com/fiberjw))
- Add interactivity to eas update:edit command. ([#2638](https://github.com/expo/eas-cli/pull/2638) by [@wschurman](https://github.com/wschurman))
## [12.5.4](https://github.com/expo/eas-cli/releases/tag/v12.5.4) - 2024-10-19
## [12.5.3](https://github.com/expo/eas-cli/releases/tag/v12.5.3) - 2024-10-16
## [12.5.2](https://github.com/expo/eas-cli/releases/tag/v12.5.2) - 2024-10-11
### 🐛 Bug fixes
- Disallow republishing an update that is being rolled-out. ([#2602](https://github.com/expo/eas-cli/pull/2602) by [@wschurman](https://github.com/wschurman))
- Bump `@expo/apple-utils` to `2.0.2` resolving the Apple authentication error. ([#2641](https://github.com/expo/eas-cli/pull/2641) by [@byCedric](https://github.com/byCedric))
### 🧹 Chores
- Implement new `worker` deploy API flow. ([#2601](https://github.com/expo/eas-cli/pull/2601) by [@kitten](https://github.com/kitten)))
- Unhide rollout-percentage flag on update publish command. ([#2608](https://github.com/expo/eas-cli/pull/2608) by [@wschurman](https://github.com/wschurman))
- Let folks know about the new concurrency add-on ([#2611](https://github.com/expo/eas-cli/pull/2611) by [@brentvatne](https://github.com/brentvatne))
## [12.5.1](https://github.com/expo/eas-cli/releases/tag/v12.5.1) - 2024-09-27
### 🐛 Bug fixes
- Support assigning dev domain names in non interactive mode. ([#2595](https://github.com/expo/eas-cli/pull/2595) by [@byCedric](https://github.com/byCedric))
### 🧹 Chores
- Simplify the output of `eas deploy --json`. ([#2596](https://github.com/expo/eas-cli/pull/2596) by [@byCedric](https://github.com/byCedric))
- Support deploying Expo Router server exports without client directory. ([#2597](https://github.com/expo/eas-cli/pull/2597) by [@byCedric](https://github.com/byCedric))
- Add exit option to `eas credentials` interactive menu. ([#2570](https://github.com/expo/eas-cli/pull/2570) by [@szdziedzic](https://github.com/szdziedzic))
## [12.5.0](https://github.com/expo/eas-cli/releases/tag/v12.5.0) - 2024-09-23
### 🎉 New features
- Log command execution to assist in debugging local builds. ([#2526](https://github.com/expo/eas-cli/pull/2526) by [@trajano](https://github.com/trajano))
- Allow submitting builds in progress ([#2543](https://github.com/expo/eas-cli/pull/2543) by [@radoslawkrzemien](https://github.com/radoslawkrzemien))
- Use `EAS_DANGEROUS_OVERRIDE_ANDROID_APPLICATION_ID` and `EAS_DANGEROUS_OVERRIDE_IOS_BUNDLE_IDENTIFIER` environment variables as overrides of the Android application ID and iOS bundle identifier in managed workflow too. ([#2576](https://github.com/expo/eas-cli/pull/2576) by [@sjchmiela](https://github.com/sjchmiela))
- Add destination branch arguments to update:republish command. ([#2575](https://github.com/expo/eas-cli/pull/2575) by [@wschurman](https://github.com/wschurman))
### 🐛 Bug fixes
- Avoid malforming `app.json` with empty `.expo` object. ([#2573](https://github.com/expo/eas-cli/pull/2573) by [@byCedric](https://github.com/byCedric))
- Fix typo causing `worker:deploy` asset upload errors not to be shown properly. ([#2579](https://github.com/expo/eas-cli/pull/2579) by [@kitten](https://github.com/kitten))
## [12.4.1](https://github.com/expo/eas-cli/releases/tag/v12.4.1) - 2024-09-14
## [12.4.0](https://github.com/expo/eas-cli/releases/tag/v12.4.0) - 2024-09-14
### 🎉 New features
- Add `worker:alias` command to assign aliases from the CLI. ([#2548](https://github.com/expo/eas-cli/pull/2548) by [@byCedric](https://github.com/byCedric))
- Add `worker --prod` flag to deploy to production from the CLI. ([#2550](https://github.com/expo/eas-cli/pull/2550) by [@byCedric](https://github.com/byCedric))
- Add `worker --alias` flag to assign custom aliases when deploying. ([#2551](https://github.com/expo/eas-cli/pull/2551) by [@byCedric](https://github.com/byCedric)))
- Add `worker --id` flag to use a custom deployment identifier. ([#2552](https://github.com/expo/eas-cli/pull/2552) by [@byCedric](https://github.com/byCedric)))
- Add `worker --environment` flag to deploy with EAS environment variables. ([#2557](https://github.com/expo/eas-cli/pull/2557) by [@kitten](https://github.com/kitten)))
- Add `worker --export-dir` flag to select exported directory. ([#2560](https://github.com/expo/eas-cli/pull/2560) by [@byCedric](https://github.com/byCedric)))
- Add `worker --json` flag to allow integrating with 3rd parties and custom tooling. ([#2561](https://github.com/expo/eas-cli/pull/2561) by [@byCedric](https://github.com/byCedric)))
- Add `worker:alias --json` flag to allow integrating with 3rd parties and custom tooling. ([#2562](https://github.com/expo/eas-cli/pull/2562) by [@byCedric](https://github.com/byCedric)))
### 🐛 Bug fixes
- Avoid merging `expo.extra` plugin-generated data with `expo.extra.eas.projectId` in `eas init`. ([#2554](https://github.com/expo/eas-cli/pull/2554) by [@byCedric](https://github.com/byCedric)))
- Restore "export not found" error and hide recent export timestamps. ([#2566](https://github.com/expo/eas-cli/pull/2566) by [@byCedric](https://github.com/byCedric)))
- Check if export is available before validating project ID in `eas worker`. ([#2569](https://github.com/expo/eas-cli/pull/2569) by [@byCedric](https://github.com/byCedric)))
### 🧹 Chores
- Make error message for invalid CFBundleShortVersionString more descriptive and actionable. Improve CFBundleShortVersionString validation regex. ([#2542](https://github.com/expo/eas-cli/pull/2542) by [@szdziedzic](https://github.com/szdziedzic))
- Add missing `--non-interactive` argument to `worker:deploy` command. ([#2544](https://github.com/expo/eas-cli/pull/2544) by [@kitten](https://github.com/kitten))
- Source `@expo/env` dotenv files for worker deployments. ([#2545](https://github.com/expo/eas-cli/pull/2545) by [@kitten](https://github.com/kitten))
- Support `worker --production` and clean up command output. ([#2555](https://github.com/expo/eas-cli/pull/2555) by [@byCedric](https://github.com/byCedric)))
- Unify both `worker` and `worker:alias` command output. ([#2558](https://github.com/expo/eas-cli/pull/2558) by [@byCedric](https://github.com/byCedric)))
- Share similar table/json output in both `worker` and `worker:alias` command outputs. ([#2563](https://github.com/expo/eas-cli/pull/2563) by [@byCedric](https://github.com/byCedric)))
- Polish the project URL prompt when setting up new projects. ([#2564](https://github.com/expo/eas-cli/pull/2564) by [@byCedric](https://github.com/byCedric)))
- Always assume `static` exports in `eas deploy` and add modified time. ([#2565](https://github.com/expo/eas-cli/pull/2565) by [@byCedric](https://github.com/byCedric)))
- Update the `eas worker --help` `--environment` description. ([#2567](https://github.com/expo/eas-cli/pull/2567) by [@byCedric](https://github.com/byCedric)))
- Remove the cursor space after selecting project dev domain. ([#2568](https://github.com/expo/eas-cli/pull/2568) by [@byCedric](https://github.com/byCedric)))
- Reword the dev domain prompt to mention "preview URL". ([#2572](https://github.com/expo/eas-cli/pull/2572) by [@byCedric](https://github.com/byCedric)))
## [12.3.0](https://github.com/expo/eas-cli/releases/tag/v12.3.0) - 2024-09-09
### 🎉 New features
- Add `--non-interactive` and `--force` support when `--id` is not passed to the `eas init` command. ([#1983](https://github.com/expo/eas-cli/pull/1983) by [@mymattcarroll](https://github.com/mymattcarroll))
## [12.1.1](https://github.com/expo/eas-cli/releases/tag/v12.1.1) - 2024-09-09
### 🐛 Bug fixes
- Fixed an issue where extensions retrieved the main app's entitlements instead of their own. ([#2532](https://github.com/expo/eas-cli/pull/2532) by [@HarrisHan](https://github.com/HarrisHan))
## [12.1.0](https://github.com/expo/eas-cli/releases/tag/v12.1.0) - 2024-09-06
### 🎉 New features
- **Internal/Experimental:** Add EAS Worker command ([#2447](https://github.com/expo/eas-cli/pull/2447) by [@kitten](https://github.com/kitten))
- Upload fingeprint source as part of eas update command. ([#2533](https://github.com/expo/eas-cli/pull/2533) by [@wschurman](https://github.com/wschurman))
## [12.0.0](https://github.com/expo/eas-cli/releases/tag/v12.0.0) - 2024-09-04
### 🛠 Breaking changes
- Prompt the users to set `appVersionSource`, while mentioning that `remote` is the default. ([#2411](https://github.com/expo/eas-cli/pull/2411) by [@radoslawkrzemien](https://github.com/radoslawkrzemien))
### 🎉 New features
- Add support for syncing Journaling Suggestions, Managed App Installation UI, and 5G Network Slicing capabilities. ([#2525](https://github.com/expo/eas-cli/pull/2525) by [@szdziedzic](https://github.com/szdziedzic))
## [11.0.3](https://github.com/expo/eas-cli/releases/tag/v11.0.3) - 2024-08-31
### 🐛 Bug fixes
- Revert config-related packages to SDK 50 version from SDK 51 version to fix broken entitlements behavior for older SDKs. ([#2524](https://github.com/expo/eas-cli/pull/2524) by [@szdziedzic](https://github.com/szdziedzic))
## [11.0.2](https://github.com/expo/eas-cli/releases/tag/v11.0.2) - 2024-08-27
### 🐛 Bug fixes
- Remove unncessary static project config context definition from `eas build` command context, to fix resolving dynamic projest ID and slug for dynamic app configs. ([#2521](https://github.com/expo/eas-cli/pull/2521) by [@szdziedzic](https://github.com/szdziedzic))
## [11.0.1](https://github.com/expo/eas-cli/releases/tag/v11.0.1) - 2024-08-26
### 🐛 Bug fixes
- Make `eas config` command not require authentication when running in `--eas-json-only` mode. ([#2517](https://github.com/expo/eas-cli/pull/2517) by [@szdziedzic](https://github.com/szdziedzic))
## [11.0.0](https://github.com/expo/eas-cli/releases/tag/v11.0.0) - 2024-08-26
### 🛠 Breaking changes
- Remove long-deprecated `eas update` flags. ([#2501](https://github.com/expo/eas-cli/pull/2501) by [@wschurman](https://github.com/wschurman))
### 🎉 New features
- Add new rollout update type for `eas update` and `eas update:edit`. ([#2502](https://github.com/expo/eas-cli/pull/2502), [#2503](https://github.com/expo/eas-cli/pull/2503) by [@wschurman](https://github.com/wschurman))
### 🧹 Chores
- Upgrade packages to SDK 51 release. ([#2498](https://github.com/expo/eas-cli/pull/2498) by [@wschurman](https://github.com/wschurman))
- Enable typescript linting and various lint rules. ([#2505](https://github.com/expo/eas-cli/pull/2505), [#2507](https://github.com/expo/eas-cli/pull/2507), [#2508](https://github.com/expo/eas-cli/pull/2508), [#2509](https://github.com/expo/eas-cli/pull/2509), [#2510](https://github.com/expo/eas-cli/pull/2510) by [@wschurman](https://github.com/wschurman))
- Include debug info in fingerprint metadata during build. ([#2513](https://github.com/expo/eas-cli/pull/2513) by [@wschurman](https://github.com/wschurman))
## [10.2.4](https://github.com/expo/eas-cli/releases/tag/v10.2.4) - 2024-08-19
## [10.2.3](https://github.com/expo/eas-cli/releases/tag/v10.2.3) - 2024-08-13
### 🧹 Chores
- Add support for `EAS_DANGEROUS_OVERRIDE_IOS_BUNDLE_IDENTIFIER` for bare workflow iOS builds. ([#2469](https://github.com/expo/eas-cli/pull/2469) by [@szdziedzic](https://github.com/szdziedzic))
- Update images list in `eas.schema.json` and warn users when using the deprecated Android images. ([#2450](https://github.com/expo/eas-cli/pull/2450) by [@szdziedzic](https://github.com/szdziedzic))
## [10.2.2](https://github.com/expo/eas-cli/releases/tag/v10.2.2) - 2024-07-31
### 🐛 Bug fixes
- Pass correct path to `vcsClient.isFileIgnoredAsync` check for monorepos to validate that custom build config file is not ignored. ([#2470](https://github.com/expo/eas-cli/pull/2470) by [@szdziedzic](https://github.com/szdziedzic))
### 🧹 Chores
- Bump asset upload timeout from 90 to 180 seconds. ([#2466](https://github.com/expo/eas-cli/pull/2466) by [@quinlanj](https://github.com/quinlanj))
## [10.2.1](https://github.com/expo/eas-cli/releases/tag/v10.2.1) - 2024-07-18
### 🧹 Chores
- Indicate if a user is logged in using `EXPO_TOKEN` when running `eas whoami` command. ([#2461](https://github.com/expo/eas-cli/pull/2461) by [@szdziedzic](https://github.com/szdziedzic))
- Throw error when `eas login` command is run with `EXPO_TOKEN` environment variable set. ([#2461](https://github.com/expo/eas-cli/pull/2461) by [@szdziedzic](https://github.com/szdziedzic))
- Check if user is already logged in when running `eas login` command. ([#2461](https://github.com/expo/eas-cli/pull/2461) by [@szdziedzic](https://github.com/szdziedzic))
## [10.2.0](https://github.com/expo/eas-cli/releases/tag/v10.2.0) - 2024-07-15
### 🎉 New features
- Added flag `--emit-metadata` to emit `eas-update-metadata.json` in the bundle folder with detailed information about the generated updates ([#2451](https://github.com/expo/eas-cli/pull/2451) by [@rainst](https://github.com/rainst))
### 🐛 Bug fixes
- Bump `@expo/apple-utils` version to use the fallback Apple Developer Portal domain on every internal server error. ([#2459](https://github.com/expo/eas-cli/pull/2459) by [@szdziedzic](https://github.com/szdziedzic))
## [10.1.1](https://github.com/expo/eas-cli/releases/tag/v10.1.1) - 2024-07-04
## [10.1.0](https://github.com/expo/eas-cli/releases/tag/v10.1.0) - 2024-07-02
### 🎉 New features
- Save local fingeprint sources during build. ([#2422](https://github.com/expo/eas-cli/pull/2422) by [@kadikraman](https://github.com/kadikraman))
## [10.0.3](https://github.com/expo/eas-cli/releases/tag/v10.0.3) - 2024-06-26
### 🧹 Chores
- Track usage of `--local` build mode in analytics. ([#2445](https://github.com/expo/eas-cli/pull/2445) by [@szdziedzic](https://github.com/szdziedzic))
- 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
+16
View File
@@ -0,0 +1,16 @@
* @szdziedzic @khamilowicz @sjchmiela
packages/eas-cli/src/build @szdziedzic @khamilowicz @sjchmiela
packages/eas-cli/src/commands/build @szdziedzic @khamilowicz @sjchmiela
packages/eas-cli/src/submit @szdziedzic @khamilowicz @sjchmiela
packages/eas-cli/src/commands/submit.ts @szdziedzic @khamilowicz @sjchmiela
packages/eas-cli/src/update @EvanBacon @byCedric @wschurman
packages/eas-cli/src/commands/update @EvanBacon @byCedric @wschurman
packages/eas-cli/schema @bycedric
packages/eas-cli/src/metadata @bycedric
packages/eas-cli/src/commands/metadata @bycedric
packages/eas-json @szdziedzic @khamilowicz @sjchmiela
+1 -1
View File
@@ -1,5 +1,5 @@
{
"npmClient": "yarn",
"version": "13.4.2",
"version": "10.0.2",
"$schema": "node_modules/lerna/schemas/lerna-schema.json"
}
+1 -1
View File
@@ -23,7 +23,7 @@
"@types/jest": "29.5.11",
"@types/node": "20.11.0",
"eslint": "8.56.0",
"eslint-config-universe": "13.0.0",
"eslint-config-universe": "12.0.0",
"eslint-plugin-async-protect": "3.1.0",
"eslint-plugin-node": "11.1.0",
"jest": "29.7.0",
+164 -442
View File
File diff suppressed because it is too large. Load diff
-1
View File
@@ -7,7 +7,6 @@ documents:
- 'src/commands/**/*.ts'
- 'src/branch/**/*.ts'
- 'src/channel/**/*.ts'
- 'src/worker/**/*.ts'
generates:
src/graphql/generated.ts:
plugins:
+607 -14292
View File
File diff suppressed because it is too large. Load diff
+18 -29
View File
@@ -1,34 +1,34 @@
{
"name": "eas-cli",
"description": "EAS command line tool",
"version": "13.4.2",
"version": "10.0.2",
"author": "Expo <[email protected]>",
"bin": {
"eas": "./bin/run"
},
"bugs": "https://github.com/expo/eas-cli/issues",
"dependencies": {
"@expo/apple-utils": "2.1.0",
"@expo/apple-utils": "1.7.0",
"@expo/code-signing-certificates": "0.0.5",
"@expo/config": "10.0.4",
"@expo/config-plugins": "9.0.9",
"@expo/eas-build-job": "1.0.149",
"@expo/eas-json": "13.4.0",
"@expo/env": "^0.4.0",
"@expo/json-file": "8.3.3",
"@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/json-file": "8.2.37",
"@expo/logger": "1.0.117",
"@expo/multipart-body-parser": "1.1.0",
"@expo/osascript": "2.1.4",
"@expo/package-manager": "1.6.1",
"@expo/pkcs12": "0.1.3",
"@expo/plist": "0.2.0",
"@expo/osascript": "2.0.33",
"@expo/package-manager": "1.1.2",
"@expo/pkcs12": "0.0.8",
"@expo/plist": "0.0.20",
"@expo/plugin-help": "5.1.23",
"@expo/plugin-warn-if-update-available": "2.5.1",
"@expo/prebuild-config": "8.0.17",
"@expo/prebuild-config": "6.7.3",
"@expo/results": "1.0.0",
"@expo/rudder-sdk-node": "1.1.1",
"@expo/spawn-async": "1.7.2",
"@expo/steps": "1.0.150",
"@expo/spawn-async": "1.7.0",
"@expo/steps": "1.0.118",
"@expo/timeago.js": "1.0.0",
"@oclif/core": "^1.26.2",
"@oclif/plugin-autocomplete": "^2.3.10",
@@ -63,7 +63,6 @@
"log-symbols": "4.1.0",
"mime": "3.0.0",
"minimatch": "5.1.2",
"minizlib": "3.0.1",
"nanoid": "3.3.4",
"node-fetch": "2.6.7",
"node-forge": "1.3.1",
@@ -79,15 +78,12 @@
"semver": "7.5.4",
"slash": "3.0.0",
"tar": "6.2.1",
"tar-stream": "3.1.7",
"terminal-link": "2.1.1",
"tslib": "2.6.2",
"turndown": "7.1.2",
"untildify": "4.0.0",
"uuid": "9.0.1",
"wrap-ansi": "7.0.0",
"yaml": "2.6.0",
"zod": "^3.23.8"
"wrap-ansi": "7.0.0"
},
"devDependencies": {
"@graphql-codegen/cli": "5.0.0",
@@ -109,13 +105,12 @@
"@types/prompts": "2.4.2",
"@types/semver": "7.5.6",
"@types/tar": "6.1.10",
"@types/tar-stream": "3.1.3",
"@types/tough-cookie": "4.0.2",
"@types/uuid": "9.0.7",
"@types/wrap-ansi": "3.0.0",
"axios": "0.28.1",
"axios": "0.27.2",
"eslint-plugin-graphql": "4.0.0",
"express": "4.20.0",
"express": "4.19.2",
"memfs": "3.4.13",
"mockdate": "3.0.5",
"nock": "13.4.0",
@@ -177,17 +172,11 @@
"secret": {
"description": "manage project and account secrets"
},
"env": {
"description": "manage project and account environment variables"
},
"update": {
"description": "manage individual updates"
},
"webhook": {
"description": "manage webhooks"
},
"workflow": {
"description": "manage workflows"
}
},
"warn-if-update-available": {
+18 -53
View File
@@ -1,20 +1,6 @@
{
"$schema": "http://json-schema.org/draft-06/schema",
"type": "object",
"properties": {
"configVersion": {
"enum": [0],
"description": "The EAS metadata store configuration version"
},
"apple": {
"$ref": "#/definitions/AppleConfig"
}
},
"additionalProperties": false,
"required": [
"configVersion",
"apple"
],
"definitions": {
"apple": {
"AppleKidsAge": {
@@ -337,8 +323,7 @@
"gambling",
"unrestrictedWebAccess",
"kidsAgeBand",
"ageRatingOverride",
"koreaAgeRatingOverride"
"seventeenPlus"
],
"defaultSnippets": [
{
@@ -360,9 +345,7 @@
"gambling": false,
"unrestrictedWebAccess": false,
"kidsAgeBand": null,
"ageRatingOverride": "NONE",
"koreaAgeRatingOverride": "NONE",
"lootBox": false
"seventeenPlus": false
}
},
{
@@ -384,9 +367,7 @@
"unrestrictedWebAccess": false,
"gambling": false,
"kidsAgeBand": null,
"ageRatingOverride": "${13|NONE,SEVENTEEN_PLUS,UNRATED|}",
"koreaAgeRatingOverride": "${14|NONE,FIFTEEN_PLUS,NINETEEN_PLUS|}",
"lootBox": false
"seventeenPlus": false
}
}
],
@@ -461,24 +442,8 @@
},
"seventeenPlus": {
"type": "boolean",
"deprecated": true,
"deprecationMessage": "This property is deprecated, use `ageRatingOverride` instead.",
"description": "If your app rates 12+ or lower, and you believe its content may not be suitable for children under 17, you can manually set the age rating to 17+.\n@see https://help.apple.com/app-store-connect/#/dev599d50efb",
"markdownDescription": "If your app rates 12+ or lower, and you believe its content may not be suitable for children under 17, you can manually set the age rating to 17+.\n\n[Learn more](https://help.apple.com/app-store-connect/#/dev599d50efb)"
},
"ageRatingOverride": {
"$ref": "#/definitions/apple/AppleAgeRatingOverride",
"description": "If your app rates 12+ or lower, and you believe its content may not be suitable for children under 17, you can manually set the age rating to 17+.\n\nIf your app will be distributed through alternative app marketplaces or websites in the European Union and you believe your app is [Unrated](https://developer.apple.com/help/app-store-connect/reference/age-ratings), set this to `UNRATED`.\n\n@see https://help.apple.com/app-store-connect/#/dev599d50efb",
"markdownDescription": "If your app rates 12+ or lower, and you believe its content may not be suitable for children under 17, you can manually set the age rating to 17+.\n\nIf your app will be distributed through alternative app marketplaces or websites in the European Union and you believe your app is [Unrated](https://developer.apple.com/help/app-store-connect/reference/age-ratings), set this to `UNRATED`.\n\n[Learn more](https://help.apple.com/app-store-connect/#/dev599d50efb)"
},
"koreaAgeRatingOverride": {
"$ref": "#/definitions/apple/AppleKoreaAgeRatingOverride",
"description": "If your app rates 12+ or lower, and you believe its content may not be suitable for children under 15 or 19, you can manually set the age rating to 15+ or 19+.\n\nIf your app will be distributed through alternative app marketplaces or websites in the European Union and you believe your app is [Unrated](https://developer.apple.com/help/app-store-connect/reference/age-ratings), set this to `UNRATED`.\n\n@see https://help.apple.com/app-store-connect/#/dev599d50efb",
"markdownDescription": "If your app rates 12+ or lower, and you believe its content may not be suitable for children under 15 or 19, you can manually set the age rating to 15+ or 19+.\n\nIf your app will be distributed through alternative app marketplaces or websites in the European Union and you believe your app is [Unrated](https://developer.apple.com/help/app-store-connect/reference/age-ratings), set this to `UNRATED`.\n\n[Learn more](https://help.apple.com/app-store-connect/#/dev599d50efb)"
},
"lootBox": {
"type": "boolean",
"description": "Does your app contain purchasable loot boxes? These virtual containers provide players with in-game items, including functional cards or cosmetic modifications, based on random chance."
}
}
},
@@ -600,20 +565,6 @@
"maxLength": 4000
}
}
},
"AppleAgeRatingOverride": {
"enum": [
"NONE",
"SEVENTEEN_PLUS",
"UNRATED"
]
},
"AppleKoreaAgeRatingOverride": {
"enum": [
"NONE",
"FIFTEEN_PLUS",
"NINETEEN_PLUS"
]
}
},
"AppleConfig": {
@@ -824,5 +775,19 @@
}
}
}
}
},
"properties": {
"configVersion": {
"enum": [0],
"description": "The EAS metadata store configuration version"
},
"apple": {
"$ref": "#/definitions/AppleConfig"
}
},
"additionalProperties": false,
"required": [
"configVersion",
"apple"
]
}
-40
View File
@@ -1,40 +0,0 @@
module.exports = {
extends: ['universe/shared/typescript-analysis'],
overrides: [
{
files: ['*.ts', '*.d.ts'],
parserOptions: {
project: './packages/eas-cli/tsconfig.json',
},
rules: {
'@typescript-eslint/explicit-function-return-type': [
'warn',
{
allowExpressions: true,
},
],
'@typescript-eslint/prefer-nullish-coalescing': ['warn', { ignorePrimitives: true }],
'@typescript-eslint/no-confusing-void-expression': 'warn',
'@typescript-eslint/await-thenable': 'error',
'@typescript-eslint/no-misused-promises': [
'error',
{
checksVoidReturn: false,
},
],
'@typescript-eslint/no-floating-promises': 'error',
'no-void': ['warn', { allowAsStatement: true }],
'no-return-await': 'off',
'@typescript-eslint/return-await': ['error', 'always'],
'@typescript-eslint/no-confusing-non-null-assertion': 'warn',
'@typescript-eslint/no-extra-non-null-assertion': 'warn',
'@typescript-eslint/prefer-as-const': 'warn',
'@typescript-eslint/prefer-includes': 'warn',
'@typescript-eslint/prefer-readonly': 'warn',
'@typescript-eslint/prefer-string-starts-ends-with': 'warn',
'@typescript-eslint/prefer-ts-expect-error': 'warn',
'@typescript-eslint/no-unnecessary-type-assertion': 'warn',
},
},
],
};
@@ -1,5 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`BuildVersionGetView reading version aborts when the appVersionSource is not specified and the user chooses to set it to LOCAL 1`] = `"Aborting..."`;
exports[`BuildVersionGetView reading version when appVersionSource is set to local 1`] = `"This project is not configured for using remote version source. Add {"cli": { "appVersionSource": "remote" }} in eas.json or re-run this command without "--non-interactive" flag."`;
@@ -1,18 +1,10 @@
import { AppVersionSource, EasJson } from '@expo/eas-json';
import chalk from 'chalk';
import {
getMockEasJson,
mockCommandContext,
mockProjectId,
mockTestCommand,
withLocalVersionSource,
withRemoteVersionSource,
} from './utils';
import { getMockEasJson, mockCommandContext, mockProjectId, mockTestCommand } from './utils';
import BuildVersionGetView from '../../commands/build/version/get';
import { AppVersionQuery } from '../../graphql/queries/AppVersionQuery';
import Log from '../../log';
import { AppVersionSourceUpdateOption } from '../../project/remoteVersionSource';
import * as prompts from '../../prompts';
import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
jest.mock('../../project/applicationIdentifier');
@@ -20,7 +12,16 @@ jest.mock('fs');
jest.mock('../../log');
jest.mock('../../utils/json');
jest.mock('../../graphql/queries/AppVersionQuery');
jest.mock('../../prompts');
function withRemoteVersionSource(easJson: EasJson): EasJson {
return {
...easJson,
cli: {
...easJson.cli,
appVersionSource: AppVersionSource.REMOTE,
},
};
}
describe(BuildVersionGetView, () => {
afterEach(() => {
@@ -48,29 +49,6 @@ describe(BuildVersionGetView, () => {
expect(printJsonOnlyOutput).not.toHaveBeenCalled();
});
test('reading version for platform android when the appVersionSource is not specified and the user chooses to set it to REMOTE', async () => {
const ctx = mockCommandContext(BuildVersionGetView, {});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => ({
buildVersion: '100',
storeVersion: '1.0.0',
}));
const cmd = mockTestCommand(BuildVersionGetView, ['--platform=android'], ctx);
jest
.mocked(prompts.selectAsync)
.mockImplementationOnce(async () => AppVersionSourceUpdateOption.SET_TO_REMOTE);
await cmd.run();
expect(AppVersionQuery.latestVersionAsync).toHaveBeenCalledWith(
ctx.loggedIn.graphqlClient,
mockProjectId,
'ANDROID',
'eas.test.com'
);
expect(Log.log).toHaveBeenCalledWith(`Android versionCode - ${chalk.bold('100')}`);
expect(enableJsonOutput).not.toHaveBeenCalled();
expect(printJsonOnlyOutput).not.toHaveBeenCalled();
});
test('reading version for platform android when no remote version is set', async () => {
const ctx = mockCommandContext(BuildVersionGetView, {
easJson: withRemoteVersionSource(getMockEasJson()),
@@ -167,51 +145,6 @@ describe(BuildVersionGetView, () => {
});
test('reading version when appVersionSource is set to local ', async () => {
const ctx = mockCommandContext(BuildVersionGetView, {
easJson: withLocalVersionSource(getMockEasJson()),
});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => ({
buildVersion: '100',
storeVersion: '1.0.0',
}));
const cmd = mockTestCommand(
BuildVersionGetView,
['--non-interactive', '--json', '--platform=android'],
ctx
);
await expect(cmd.run()).rejects.toThrowErrorMatchingSnapshot();
});
test('reading version aborts when the appVersionSource is not specified and the user chooses to set it to LOCAL', async () => {
const ctx = mockCommandContext(BuildVersionGetView, {});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => ({
buildVersion: '100',
storeVersion: '1.0.0',
}));
jest
.mocked(prompts.selectAsync)
.mockImplementationOnce(async () => AppVersionSourceUpdateOption.SET_TO_LOCAL);
const cmd = mockTestCommand(BuildVersionGetView, ['--platform=android'], ctx);
await expect(cmd.run()).rejects.toThrowErrorMatchingSnapshot();
});
test('reading version aborts when the appVersionSource is not specified and the user chooses to configure it manually', async () => {
const ctx = mockCommandContext(BuildVersionGetView, {});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => ({
buildVersion: '100',
storeVersion: '1.0.0',
}));
jest
.mocked(prompts.selectAsync)
.mockImplementationOnce(async () => AppVersionSourceUpdateOption.ABORT);
const cmd = mockTestCommand(BuildVersionGetView, ['--platform=android'], ctx);
await expect(cmd.run()).rejects.toThrowError('Aborted.');
});
test('reading version sets appVersionSource to LOCAL and aborts when the appVersionSource is not specified and is run in non-interactive mode', async () => {
const ctx = mockCommandContext(BuildVersionGetView, {});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => ({
buildVersion: '100',
@@ -223,10 +156,6 @@ describe(BuildVersionGetView, () => {
['--non-interactive', '--json', '--platform=android'],
ctx
);
await expect(cmd.run()).rejects.toThrowError(
`This project is not configured for using remote version source. Add ${chalk.bold(
'{"cli": { "appVersionSource": "remote" }}'
)} in eas.json or re-run this command without "--non-interactive" flag.`
);
await expect(cmd.run()).rejects.toThrowErrorMatchingSnapshot();
});
});
@@ -1,3 +1,4 @@
import { AppVersionSource, EasJson } from '@expo/eas-json';
import fs from 'fs-extra';
import path from 'path';
@@ -7,15 +8,12 @@ import {
mockCommandContext,
mockProjectId,
mockTestCommand,
withLocalVersionSource,
withRemoteVersionSource,
} from './utils';
import BuildVersionSetView from '../../commands/build/version/set';
import { AppVersionMutation } from '../../graphql/mutations/AppVersionMutation';
import { AppQuery } from '../../graphql/queries/AppQuery';
import { AppVersionQuery } from '../../graphql/queries/AppVersionQuery';
import Log from '../../log';
import { AppVersionSourceUpdateOption } from '../../project/remoteVersionSource';
import * as prompts from '../../prompts';
jest.mock('../../project/applicationIdentifier');
@@ -27,6 +25,16 @@ jest.mock('../../log');
jest.mock('../../prompts');
jest.mock('../../utils/json');
function withRemoteVersionSource(easJson: EasJson): EasJson {
return {
...easJson,
cli: {
...easJson.cli,
appVersionSource: AppVersionSource.REMOTE,
},
};
}
describe(BuildVersionSetView, () => {
afterEach(() => {
jest.clearAllMocks();
@@ -59,34 +67,6 @@ describe(BuildVersionSetView, () => {
);
});
test('setting version for platform android when the appVersionSource is not specified and the user chooses to set it to REMOTE', async () => {
const ctx = mockCommandContext(BuildVersionSetView, {});
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => null);
jest.mocked(prompts.promptAsync).mockImplementationOnce(async () => ({
version: '1000',
}));
jest
.mocked(prompts.selectAsync)
.mockImplementationOnce(async () => AppVersionSourceUpdateOption.SET_TO_REMOTE);
const cmd = mockTestCommand(BuildVersionSetView, ['--platform=android'], ctx);
await cmd.run();
expect(AppVersionQuery.latestVersionAsync).toHaveBeenCalledWith(
ctx.loggedIn.graphqlClient,
mockProjectId,
'ANDROID',
'eas.test.com'
);
expect(AppVersionMutation.createAppVersionAsync).toHaveBeenCalledWith(
ctx.loggedIn.graphqlClient,
expect.objectContaining({
buildVersion: '1000',
storeVersion: '1.0.0',
})
);
});
test('printing current remote version before prompting for a new one', async () => {
const ctx = mockCommandContext(BuildVersionSetView, {
easJson: withRemoteVersionSource(getMockEasJson()),
@@ -135,9 +115,7 @@ describe(BuildVersionSetView, () => {
});
test('setting version aborts when appVersionSource is set to local and users refuse auto configuration', async () => {
const ctx = mockCommandContext(BuildVersionSetView, {
easJson: withLocalVersionSource(getMockEasJson()),
});
const ctx = mockCommandContext(BuildVersionSetView, {});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => null);
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest.mocked(prompts.confirmAsync).mockImplementation(async () => false);
@@ -147,24 +125,8 @@ describe(BuildVersionSetView, () => {
expect(AppVersionMutation.createAppVersionAsync).not.toHaveBeenCalledWith();
});
test('setting version aborts when the appVersionSource is not specified and the user chooses to set it to LOCAL, and they refuse auto configuration', async () => {
const ctx = mockCommandContext(BuildVersionSetView, {});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => null);
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest
.mocked(prompts.selectAsync)
.mockImplementationOnce(async () => AppVersionSourceUpdateOption.SET_TO_LOCAL);
jest.mocked(prompts.confirmAsync).mockImplementationOnce(async () => false);
const cmd = mockTestCommand(BuildVersionSetView, ['--platform=android'], ctx);
await expect(cmd.run()).rejects.toThrowError('Aborting...');
expect(AppVersionMutation.createAppVersionAsync).not.toHaveBeenCalledWith();
});
test('setting version when appVersionSource is set to local and user allows auto configuration', async () => {
const ctx = mockCommandContext(BuildVersionSetView, {
easJson: withLocalVersionSource(getMockEasJson()),
});
const ctx = mockCommandContext(BuildVersionSetView, {});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => null);
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest.mocked(prompts.confirmAsync).mockImplementation(async () => true);
@@ -175,33 +137,4 @@ describe(BuildVersionSetView, () => {
const easJsonAfterCmd = await fs.readJson(path.join(ctx.projectDir, 'eas.json'));
expect(easJsonAfterCmd.cli.appVersionSource).toBe('remote');
});
test('setting version when the appVersionSource is not specified and the user chooses to set it to LOCAL, and they allow auto configuration', async () => {
const ctx = mockCommandContext(BuildVersionSetView, {});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => null);
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest
.mocked(prompts.selectAsync)
.mockImplementationOnce(async () => AppVersionSourceUpdateOption.SET_TO_LOCAL);
jest.mocked(prompts.confirmAsync).mockImplementationOnce(async () => true);
const cmd = mockTestCommand(BuildVersionSetView, ['--platform=android'], ctx);
await cmd.run();
const easJsonAfterCmd = await fs.readJson(path.join(ctx.projectDir, 'eas.json'));
expect(easJsonAfterCmd.cli.appVersionSource).toBe('remote');
});
test('setting version aborts when the appVersionSource is not specified and the user chooses to configure manually', async () => {
const ctx = mockCommandContext(BuildVersionSetView, {});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => null);
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest
.mocked(prompts.selectAsync)
.mockImplementationOnce(async () => AppVersionSourceUpdateOption.ABORT);
const cmd = mockTestCommand(BuildVersionSetView, ['--platform=android'], ctx);
await expect(cmd.run()).rejects.toThrowError('Aborted.');
expect(AppVersionMutation.createAppVersionAsync).not.toHaveBeenCalledWith();
});
});
@@ -1,4 +1,5 @@
import { Workflow } from '@expo/eas-build-job';
import { AppVersionSource, EasJson } from '@expo/eas-json';
import fs from 'fs-extra';
import path from 'path';
@@ -8,8 +9,6 @@ import {
mockCommandContext,
mockProjectId,
mockTestCommand,
withLocalVersionSource,
withRemoteVersionSource,
} from './utils';
import { updateNativeVersionsAsync as updateAndroidNativeVersionsAsync } from '../../build/android/version';
import { updateNativeVersionsAsync as updateIosNativeVersionsAsync } from '../../build/ios/version';
@@ -20,7 +19,6 @@ import { AppQuery } from '../../graphql/queries/AppQuery';
import { AppVersionQuery } from '../../graphql/queries/AppVersionQuery';
import { getAppBuildGradleAsync } from '../../project/android/gradleUtils';
import { resolveTargetsAsync } from '../../project/ios/target';
import { AppVersionSourceUpdateOption } from '../../project/remoteVersionSource';
import { resolveWorkflowAsync } from '../../project/workflow';
import * as prompts from '../../prompts';
@@ -39,6 +37,16 @@ jest.mock('../../log');
jest.mock('../../prompts');
jest.mock('../../utils/json');
function withRemoteVersionSource(easJson: EasJson): EasJson {
return {
...easJson,
cli: {
...easJson.cli,
appVersionSource: AppVersionSource.REMOTE,
},
};
}
describe(BuildVersionSyncView, () => {
afterEach(() => {
jest.clearAllMocks();
@@ -71,34 +79,6 @@ describe(BuildVersionSyncView, () => {
expect(syncAndroidAsync).not.toHaveBeenCalled();
});
test('syncing version for managed project on platform android when appVersionSource is not set and the user chooses to set it to REMOTE', async () => {
const ctx = mockCommandContext(BuildVersionSyncView, {});
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => ({
buildVersion: '1000',
storeVersion: '0.0.1',
}));
jest.mocked(prompts.promptAsync).mockImplementationOnce(async () => ({
version: '1000',
}));
jest
.mocked(prompts.selectAsync)
.mockImplementationOnce(async () => AppVersionSourceUpdateOption.SET_TO_REMOTE);
jest.mocked(resolveWorkflowAsync).mockImplementation(async () => Workflow.MANAGED);
const cmd = mockTestCommand(BuildVersionSyncView, ['--platform=android'], ctx);
const syncAndroidAsync = jest.spyOn(cmd, 'syncAndroidAsync' as any);
await cmd.run();
expect(AppVersionQuery.latestVersionAsync).toHaveBeenCalledWith(
ctx.loggedIn.graphqlClient,
mockProjectId,
'ANDROID',
'eas.test.com'
);
expect(syncAndroidAsync).not.toHaveBeenCalled();
});
test('syncing version for bare project on platform android', async () => {
const ctx = mockCommandContext(BuildVersionSyncView, {
easJson: withRemoteVersionSource(getMockEasJson()),
@@ -199,25 +179,9 @@ describe(BuildVersionSyncView, () => {
});
test('syncing version aborts when appVersionSource is set to local and users refuse auto configuration', async () => {
const ctx = mockCommandContext(BuildVersionSyncView, {
easJson: withLocalVersionSource(getMockEasJson()),
});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => null);
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest.mocked(prompts.confirmAsync).mockImplementation(async () => false);
const cmd = mockTestCommand(BuildVersionSyncView, ['--platform=android'], ctx);
await expect(cmd.run()).rejects.toThrowError('Aborting...');
expect(AppVersionMutation.createAppVersionAsync).not.toHaveBeenCalledWith();
});
test('syncing version aborts when appVersionSource is not set and the user chooses to set it to LOCAL, and they refuse auto configuration', async () => {
const ctx = mockCommandContext(BuildVersionSyncView, {});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => null);
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest
.mocked(prompts.selectAsync)
.mockImplementationOnce(async () => AppVersionSourceUpdateOption.SET_TO_LOCAL);
jest.mocked(prompts.confirmAsync).mockImplementation(async () => false);
const cmd = mockTestCommand(BuildVersionSyncView, ['--platform=android'], ctx);
@@ -226,9 +190,7 @@ describe(BuildVersionSyncView, () => {
});
test('syncing version when appVersionSource is set to local and user allows auto configuration', async () => {
const ctx = mockCommandContext(BuildVersionSyncView, {
easJson: withLocalVersionSource(getMockEasJson()),
});
const ctx = mockCommandContext(BuildVersionSyncView, {});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => null);
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest.mocked(prompts.confirmAsync).mockImplementation(async () => true);
@@ -239,33 +201,4 @@ describe(BuildVersionSyncView, () => {
const easJsonAfterCmd = await fs.readJson(path.join(ctx.projectDir, 'eas.json'));
expect(easJsonAfterCmd.cli.appVersionSource).toBe('remote');
});
test('syncing version when appVersionSource is not set and the user chooses to set it to LOCAL and they allow auto configuration', async () => {
const ctx = mockCommandContext(BuildVersionSyncView, {});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => null);
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest
.mocked(prompts.selectAsync)
.mockImplementationOnce(async () => AppVersionSourceUpdateOption.SET_TO_LOCAL);
jest.mocked(prompts.confirmAsync).mockImplementation(async () => true);
const cmd = mockTestCommand(BuildVersionSyncView, ['--platform=android'], ctx);
await cmd.run();
const easJsonAfterCmd = await fs.readJson(path.join(ctx.projectDir, 'eas.json'));
expect(easJsonAfterCmd.cli.appVersionSource).toBe('remote');
});
test('syncing version aborts when appVersionSource is not set and the user chooses to configure manually', async () => {
const ctx = mockCommandContext(BuildVersionSyncView, {});
jest.mocked(AppVersionQuery.latestVersionAsync).mockImplementation(async () => null);
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest
.mocked(prompts.selectAsync)
.mockImplementationOnce(async () => AppVersionSourceUpdateOption.ABORT);
const cmd = mockTestCommand(BuildVersionSyncView, ['--platform=android'], ctx);
await expect(cmd.run()).rejects.toThrowError('Aborted.');
expect(AppVersionMutation.createAppVersionAsync).not.toHaveBeenCalledWith();
});
});
@@ -1,5 +1,5 @@
import { ExpoConfig } from '@expo/config';
import { AppVersionSource, EasJson } from '@expo/eas-json';
import { ExpoConfig } from '@expo/config-types';
import { EasJson } from '@expo/eas-json';
import { Command, Config } from '@oclif/core';
import { vol } from 'memfs';
import path from 'path';
@@ -148,23 +148,3 @@ export const getError = <TError = any>(call: () => unknown): TError | NoErrorThr
return error as TError;
}
};
export function withRemoteVersionSource(easJson: EasJson): EasJson {
return {
...easJson,
cli: {
...easJson.cli,
appVersionSource: AppVersionSource.REMOTE,
},
};
}
export function withLocalVersionSource(easJson: EasJson): EasJson {
return {
...easJson,
cli: {
...easJson.cli,
appVersionSource: AppVersionSource.LOCAL,
},
};
}
@@ -28,7 +28,7 @@ import {
*/
export class SelectBranch implements EASUpdateAction<UpdateBranchBasicInfoFragment | null> {
constructor(
private readonly options: {
private options: {
filterPredicate?: (branchInfo: UpdateBranchBasicInfoFragment) => boolean;
printedType?: string;
pageSize?: number;
@@ -91,8 +91,8 @@ export class SelectBranch implements EASUpdateAction<UpdateBranchBasicInfoFragme
queryParams: QueryParams
): Promise<Connection<UpdateBranchBasicInfoFragment>> =>
filterPredicate
? await this.filterQueryAsync(ctx, queryParams, filterPredicate)
: await this.queryAsync(ctx, queryParams);
? this.filterQueryAsync(ctx, queryParams, filterPredicate)
: this.queryAsync(ctx, queryParams);
const getTitleAsync = async (branchInfo: UpdateBranchBasicInfoFragment): Promise<string> =>
branchInfo.name;
+1 -3
View File
@@ -84,9 +84,7 @@ export async function listAndRenderBranchesOnAppAsync(
queryBranchesOnProjectAsync(graphqlClient, limit, offset, projectId),
promptOptions: {
title: 'Load more branches?',
renderListItems: branches => {
renderPageOfBranches(branches, paginatedQueryOptions);
},
renderListItems: branches => renderPageOfBranches(branches, paginatedQueryOptions),
},
});
}
@@ -47,14 +47,14 @@ describe(selectBuildToCancelAsync.name, () => {
it('does not return build id when confirmation is rejected', async () => {
const graphqlClient = instance(mock<ExpoGraphqlClient>());
jest.mocked(confirmAsync).mockResolvedValueOnce(false);
await expect(selectBuildToCancelAsync(graphqlClient, projectId, 'blah')).resolves.toEqual(null);
expect(selectBuildToCancelAsync(graphqlClient, projectId, 'blah')).resolves.toEqual(null);
});
it('returns build id when confirmation is confirmed', async () => {
const graphqlClient = instance(mock<ExpoGraphqlClient>());
jest.mocked(selectAsync).mockResolvedValueOnce(selectedBuildId);
jest.mocked(confirmAsync).mockResolvedValueOnce(true);
await expect(selectBuildToCancelAsync(graphqlClient, projectId, 'blah')).resolves.toEqual(
expect(selectBuildToCancelAsync(graphqlClient, projectId, 'blah')).resolves.toEqual(
selectedBuildId
);
});
@@ -1,77 +0,0 @@
import { AppVersionSource, EasJsonAccessor } from '@expo/eas-json';
import fs from 'fs-extra';
import { vol } from 'memfs';
import { easCliVersion } from '../../utils/easCli';
import GitClient from '../../vcs/clients/git';
import { Client } from '../../vcs/vcs';
import { ensureProjectConfiguredAsync } from '../configure';
jest.mock('fs');
jest.mock('../../vcs/vcs');
jest.mock('../../vcs/clients/git');
beforeEach(async () => {
vol.reset();
});
describe(ensureProjectConfiguredAsync, () => {
it('returns false and does not configure if eas.json exists', async () => {
vol.fromJSON({
'./eas.json': JSON.stringify({
cli: {
version: `>= ${easCliVersion}`,
},
build: {
development: {
developmentClient: true,
distribution: 'internal',
},
preview: {
distribution: 'internal',
},
production: {},
},
submit: {
production: {},
},
}),
});
await expect(fs.pathExists(EasJsonAccessor.formatEasJsonPath('.'))).resolves.toBeTruthy();
const vcsClientMock = jest.mocked(new GitClient());
vcsClientMock.showChangedFilesAsync.mockImplementation(async () => {});
vcsClientMock.isCommitRequiredAsync.mockImplementation(async () => false);
vcsClientMock.trackFileAsync.mockImplementation(async () => {});
const result = await ensureProjectConfiguredAsync({
projectDir: '.',
nonInteractive: false,
vcsClient: vcsClientMock as unknown as Client,
});
expect(result).toBeFalsy();
await expect(fs.pathExists(EasJsonAccessor.formatEasJsonPath('.'))).resolves.toBeTruthy();
});
it('returns true and configures if eas.json does not exist', async () => {
const writeFileMock = jest.spyOn(fs, 'writeFile');
writeFileMock.mockImplementation(async (...args) => {
const easJsonPath = args[0] as string;
const easJsonData = args[1] as string;
vol.fromJSON({
[easJsonPath]: easJsonData,
});
});
await expect(fs.pathExists(EasJsonAccessor.formatEasJsonPath('.'))).resolves.toBeFalsy();
const vcsClientMock = jest.mocked(new GitClient());
vcsClientMock.showChangedFilesAsync.mockImplementation(async () => {});
vcsClientMock.isCommitRequiredAsync.mockImplementation(async () => false);
vcsClientMock.trackFileAsync.mockImplementation(async () => {});
const result = await ensureProjectConfiguredAsync({
projectDir: '.',
nonInteractive: false,
vcsClient: vcsClientMock as unknown as Client,
});
expect(result).toBeTruthy();
await expect(fs.pathExists(EasJsonAccessor.formatEasJsonPath('.'))).resolves.toBeTruthy();
const easJson = await EasJsonAccessor.fromProjectPath('.').readAsync();
expect(easJson.cli?.appVersionSource).toEqual(AppVersionSource.REMOTE);
});
});
@@ -47,14 +47,14 @@ describe(selectBuildToDeleteAsync.name, () => {
it('does not return build id when confirmation is rejected', async () => {
const graphqlClient = instance(mock<ExpoGraphqlClient>());
jest.mocked(confirmAsync).mockResolvedValueOnce(false);
await expect(selectBuildToDeleteAsync(graphqlClient, projectId, 'blah')).resolves.toEqual(null);
expect(selectBuildToDeleteAsync(graphqlClient, projectId, 'blah')).resolves.toEqual(null);
});
it('returns build id when confirmation is confirmed', async () => {
const graphqlClient = instance(mock<ExpoGraphqlClient>());
jest.mocked(selectAsync).mockResolvedValueOnce(selectedBuildId);
jest.mocked(confirmAsync).mockResolvedValueOnce(true);
await expect(selectBuildToDeleteAsync(graphqlClient, projectId, 'blah')).resolves.toEqual(
expect(selectBuildToDeleteAsync(graphqlClient, projectId, 'blah')).resolves.toEqual(
selectedBuildId
);
});
+1 -1
View File
@@ -107,7 +107,7 @@ export async function prepareAndroidBuildAsync(
? false
: ctx.buildProfile.autoIncrement,
vcsClient: ctx.vcsClient,
env: ctx.env,
env: ctx.buildProfile.env,
});
},
prepareJobAsync: async (
@@ -115,10 +115,6 @@ export async function prepareJobAsync(
},
}),
loggerLevel: ctx.loggerLevel,
// Technically, these are unused, but let's include them here for type consistency.
// See: https://github.com/expo/eas-build/pull/454
appId: ctx.projectId,
initiatingUserId: ctx.user.id,
};
return sanitizeBuildJob(job) as Android.Job;
@@ -44,7 +44,7 @@ export async function bumpVersionAsync({
const buildGradle = await getAppBuildGradleAsync(projectDir);
const isMultiFlavor =
buildGradle.android?.productFlavors ?? buildGradle.android?.flavorDimensions;
buildGradle.android?.productFlavors || buildGradle.android?.flavorDimensions;
if (isMultiFlavor) {
throw new Error(
'Automatic version bumping is not supported for multi-flavor Android projects.'
+12 -120
View File
@@ -2,7 +2,6 @@ import {
ArchiveSource,
ArchiveSourceType,
BuildJob,
FingerprintSource,
Metadata,
Platform,
} from '@expo/eas-build-job';
@@ -57,16 +56,12 @@ import { BuildQuery } from '../graphql/queries/BuildQuery';
import Log, { learnMore, link } from '../log';
import { Ora, ora } from '../ora';
import {
RequestedPlatform,
appPlatformDisplayNames,
appPlatformEmojis,
requestedPlatformDisplayNames,
} from '../platform';
import { maybeUploadFingerprintAsync } from '../project/maybeUploadFingerprintAsync';
import { resolveRuntimeVersionAsync } from '../project/resolveRuntimeVersionAsync';
import { uploadFileAtPathToGCSAsync } from '../uploads';
import { formatBytes } from '../utils/files';
import { createFingerprintAsync } from '../utils/fingerprintCli';
import { printJsonOnlyOutput } from '../utils/json';
import { createProgressTracker } from '../utils/progress';
import { sleepAsync } from '../utils/promise';
@@ -129,9 +124,7 @@ export async function prepareBuildRequestForPlatformAsync<
await withAnalyticsAsync(
ctx.analytics,
async () => {
await builder.syncProjectConfigurationAsync(ctx);
},
async () => await builder.syncProjectConfigurationAsync(ctx),
{
attemptEvent: BuildEvent.CONFIGURE_PROJECT_ATTEMPT,
successEvent: BuildEvent.CONFIGURE_PROJECT_SUCCESS,
@@ -142,15 +135,9 @@ export async function prepareBuildRequestForPlatformAsync<
if (await ctx.vcsClient.isCommitRequiredAsync()) {
Log.addNewLineIfNone();
const platformToRequestedPlatform: Record<Platform, RequestedPlatform> = {
[Platform.ANDROID]: RequestedPlatform.Android,
[Platform.IOS]: RequestedPlatform.Ios,
};
await reviewAndCommitChangesAsync(
ctx.vcsClient,
`[EAS Build] Run EAS Build for ${
requestedPlatformDisplayNames[platformToRequestedPlatform[ctx.platform]]
}`,
`[EAS Build] Run EAS Build for ${requestedPlatformDisplayNames[ctx.platform as Platform]}`,
{ nonInteractive: ctx.nonInteractive }
);
}
@@ -175,9 +162,7 @@ export async function prepareBuildRequestForPlatformAsync<
}
assert(projectArchive);
const runtimeAndFingerprintMetadata =
await computeAndMaybeUploadRuntimeAndFingerprintMetadataAsync(ctx);
const metadata = await collectMetadataAsync(ctx, runtimeAndFingerprintMetadata);
const metadata = await collectMetadataAsync(ctx);
const buildParams = resolveBuildParamsInput(ctx, metadata);
const job = await builder.prepareJobAsync(ctx, {
projectArchive,
@@ -186,7 +171,7 @@ export async function prepareBuildRequestForPlatformAsync<
return async () => {
if (ctx.localBuildOptions.localBuildMode === LocalBuildMode.LOCAL_BUILD_PLUGIN) {
await runLocalBuildAsync(job, metadata, ctx.localBuildOptions, ctx.env);
await runLocalBuildAsync(job, metadata, ctx.localBuildOptions);
return undefined;
} else if (ctx.localBuildOptions.localBuildMode === LocalBuildMode.INTERNAL) {
await BuildMutation.updateBuildMetadataAsync(ctx.graphqlClient, {
@@ -488,8 +473,8 @@ async function handleSingleBuildProgressAsync(
spinner.succeed('Build finished');
return { refetch: false };
case BuildStatus.New:
spinner.text = `Build concurrency limit reached for your account. Build will enter queue once a concurrency becomes available. Add additional concurrencies at ${link(
formatAccountBillingUrl(accountName)
spinner.text = `Build is waiting to enter the queue. Check your concurrency limit at ${link(
formatAccountSubscriptionsUrl(accountName)
)}.`;
break;
case BuildStatus.InQueue: {
@@ -511,7 +496,7 @@ async function handleSingleBuildProgressAsync(
Log.log('Start builds sooner in the priority queue.');
Log.log(
`Sign up for EAS Production or Enterprise at ${link(
formatAccountBillingUrl(accountName)
formatAccountSubscriptionsUrl(accountName)
)}`
);
}
@@ -658,102 +643,9 @@ function formatEstimatedWaitTime(estimatedWaitTimeLeftSeconds: number): string {
}
}
function formatAccountBillingUrl(accountName: string): string {
return new URL(`/accounts/${accountName}/settings/billing`, getExpoWebsiteBaseUrl()).toString();
}
async function computeAndMaybeUploadRuntimeAndFingerprintMetadataAsync<T extends Platform>(
ctx: BuildContext<T>
): Promise<{
runtimeVersion?: string | undefined;
fingerprintHash?: string | undefined;
fingerprintSource?: FingerprintSource | undefined;
}> {
const runtimeAndFingerprintMetadata =
await computeAndMaybeUploadFingerprintFromExpoUpdatesAsync(ctx);
if (!runtimeAndFingerprintMetadata?.fingerprintHash) {
const fingerprint = await computeAndMaybeUploadFingerprintWithoutExpoUpdatesAsync(ctx);
return {
...runtimeAndFingerprintMetadata,
...fingerprint,
};
} else {
return {
...runtimeAndFingerprintMetadata,
fingerprintHash: runtimeAndFingerprintMetadata.runtimeVersion,
};
}
}
async function computeAndMaybeUploadFingerprintFromExpoUpdatesAsync<T extends Platform>(
ctx: BuildContext<T>
): Promise<{
runtimeVersion?: string;
fingerprintSource?: FingerprintSource;
fingerprintHash?: string;
}> {
const resolvedRuntimeVersion = await resolveRuntimeVersionAsync({
exp: ctx.exp,
platform: ctx.platform,
workflow: ctx.workflow,
projectDir: ctx.projectDir,
env: ctx.env,
cwd: ctx.projectDir,
});
if (!resolvedRuntimeVersion) {
return {};
}
/**
* It's ok for fingerprintSources or runtimeVersion to be empty
* fingerprintSources only exist if the project is using runtimeVersion.policy: fingerprint
*/
if (!resolvedRuntimeVersion.fingerprint || !resolvedRuntimeVersion.runtimeVersion) {
return {
runtimeVersion: resolvedRuntimeVersion.runtimeVersion ?? undefined,
};
}
const uploadedFingerprint = await maybeUploadFingerprintAsync({
hash: resolvedRuntimeVersion.runtimeVersion,
fingerprint: resolvedRuntimeVersion.fingerprint,
graphqlClient: ctx.graphqlClient,
localBuildMode: ctx.localBuildOptions.localBuildMode,
});
return {
runtimeVersion: uploadedFingerprint.hash,
fingerprintSource: uploadedFingerprint.fingerprintSource,
fingerprintHash: resolvedRuntimeVersion.fingerprintHash ?? undefined,
};
}
async function computeAndMaybeUploadFingerprintWithoutExpoUpdatesAsync<T extends Platform>(
ctx: BuildContext<T>,
{ debug }: { debug?: boolean } = {}
): Promise<{
fingerprintHash?: string;
fingerprintSource?: FingerprintSource;
}> {
const fingerprint = await createFingerprintAsync(ctx.projectDir, {
workflow: ctx.workflow,
platforms: [ctx.platform],
env: ctx.env,
});
if (!fingerprint) {
return {};
}
const uploadedFingerprint = await maybeUploadFingerprintAsync({
hash: fingerprint.hash,
fingerprint: {
fingerprintSources: fingerprint.sources,
isDebugFingerprintSource: debug ?? false,
},
graphqlClient: ctx.graphqlClient,
localBuildMode: ctx.localBuildOptions.localBuildMode,
});
return {
fingerprintHash: uploadedFingerprint.hash,
fingerprintSource: uploadedFingerprint.fingerprintSource,
};
function formatAccountSubscriptionsUrl(accountName: string): string {
return new URL(
`/accounts/${accountName}/settings/subscriptions`,
getExpoWebsiteBaseUrl()
).toString();
}
+2 -5
View File
@@ -1,4 +1,4 @@
import { AppVersionSource, EasJson, EasJsonAccessor } from '@expo/eas-json';
import { EasJson, EasJsonAccessor } from '@expo/eas-json';
import chalk from 'chalk';
import fs from 'fs-extra';
@@ -55,7 +55,6 @@ async function configureAsync({
const EAS_JSON_DEFAULT: EasJson = {
cli: {
version: `>= ${easCliVersion}`,
appVersionSource: AppVersionSource.REMOTE,
},
build: {
development: {
@@ -65,9 +64,7 @@ const EAS_JSON_DEFAULT: EasJson = {
preview: {
distribution: 'internal',
},
production: {
autoIncrement: true,
},
production: {},
},
submit: {
production: {},
-1
View File
@@ -63,5 +63,4 @@ export interface BuildContext<T extends Platform> {
vcsClient: Client;
loggerLevel?: LoggerLevel;
repack: boolean;
env: Record<string, string>;
}
+3 -9
View File
@@ -10,7 +10,7 @@ import { v4 as uuidv4 } from 'uuid';
import { createAndroidContextAsync } from './android/build';
import { BuildContext, CommonContext } from './context';
import { createIosContextAsync } from './ios/build';
import { LocalBuildMode, LocalBuildOptions } from './local';
import { LocalBuildOptions } from './local';
import { resolveBuildResourceClassAsync } from './utils/resourceClass';
import { Analytics, AnalyticsEventProperties, BuildEvent } from '../analytics/AnalyticsManager';
import { DynamicConfigContextFn } from '../commandUtils/context/DynamicProjectConfigContextField';
@@ -43,7 +43,6 @@ export async function createBuildContextAsync<T extends Platform>({
buildLoggerLevel,
freezeCredentials,
repack,
env,
}: {
buildProfileName: string;
buildProfile: BuildProfile<T>;
@@ -65,11 +64,8 @@ export async function createBuildContextAsync<T extends Platform>({
buildLoggerLevel?: LoggerLevel;
freezeCredentials: boolean;
repack: boolean;
env: Record<string, string>;
}): Promise<BuildContext<T>> {
const { exp, projectId } = await getDynamicPrivateProjectConfigAsync({
env,
});
const { exp, projectId } = await getDynamicPrivateProjectConfigAsync({ env: buildProfile.env });
const projectName = exp.slug;
const account = await getOwnerAccountForProjectIdAsync(graphqlClient, projectId);
const workflow = await resolveWorkflowAsync(projectDir, platform, vcsClient);
@@ -91,7 +87,7 @@ export async function createBuildContextAsync<T extends Platform>({
user: actor,
graphqlClient,
analytics,
env,
env: buildProfile.env,
easJsonCliConfig,
vcsClient,
freezeCredentials,
@@ -112,7 +108,6 @@ export async function createBuildContextAsync<T extends Platform>({
...devClientProperties,
no_wait: noWait,
run_from_ci: runFromCI,
local: localBuildOptions.localBuildMode === LocalBuildMode.LOCAL_BUILD_PLUGIN,
};
analytics.logEvent(BuildEvent.BUILD_COMMAND, analyticsEventProperties);
@@ -151,7 +146,6 @@ export async function createBuildContextAsync<T extends Platform>({
requiredPackageManager,
loggerLevel: buildLoggerLevel,
repack,
env,
};
if (platform === Platform.ANDROID) {
const common = commonContext as CommonContext<Platform.ANDROID>;
@@ -1,157 +0,0 @@
import { Env } from '@expo/eas-build-job';
import { BuildProfile } from '@expo/eas-json';
import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
import { EnvironmentVariableEnvironment } from '../graphql/generated';
import { EnvironmentVariablesQuery } from '../graphql/queries/EnvironmentVariablesQuery';
import Log, { learnMore } from '../log';
function isEnvironment(env: string): env is EnvironmentVariableEnvironment {
return Object.values(EnvironmentVariableEnvironment).includes(
env as EnvironmentVariableEnvironment
);
}
export async function evaluateConfigWithEnvVarsAsync<Config extends { projectId: string }, Opts>({
buildProfile,
buildProfileName,
graphqlClient,
getProjectConfig,
opts,
}: {
buildProfile: BuildProfile;
buildProfileName: string;
graphqlClient: ExpoGraphqlClient | null;
opts: Opts;
getProjectConfig(opts: Opts): Promise<Config>;
}): Promise<Config & { env: Env }> {
if (!graphqlClient) {
Log.warn('An Expo user account is required to fetch environment variables.');
const config = await getProjectConfig(opts);
return { env: buildProfile.env ?? {}, ...config };
}
const { projectId } = await getProjectConfig({ env: buildProfile.env, ...opts });
const env = await resolveEnvVarsAsync({
buildProfile,
buildProfileName,
graphqlClient,
projectId,
});
const config = await getProjectConfig({ ...opts, env });
return { env, ...config };
}
async function resolveEnvVarsAsync({
buildProfile,
buildProfileName,
graphqlClient,
projectId,
}: {
buildProfile: BuildProfile;
buildProfileName: string;
graphqlClient: ExpoGraphqlClient;
projectId: string;
}): Promise<Env> {
const environment =
buildProfile.environment?.toUpperCase() ??
resolveSuggestedEnvironmentForBuildProfileConfiguration(buildProfile);
if (!isEnvironment(environment)) {
Log.log(
`Loaded "env" configuration for the "${buildProfileName}" profile: ${
buildProfile.env && Object.keys(buildProfile.env).length > 0
? Object.keys(buildProfile.env).join(', ')
: 'no environment variables specified'
}. ${learnMore('https://docs.expo.dev/build-reference/variables/')}`
);
return { ...buildProfile.env };
}
try {
const environmentVariables = await EnvironmentVariablesQuery.byAppIdWithSensitiveAsync(
graphqlClient,
{
appId: projectId,
environment,
}
);
const serverEnvVars = Object.fromEntries(
environmentVariables
.filter(({ name, value }) => name && value)
.map(({ name, value }) => [name, value])
) as Record<string, string>;
if (Object.keys(serverEnvVars).length > 0) {
Log.log(
`Environment variables with visibility "Plain text" and "Sensitive" loaded from the "${environment.toLowerCase()}" environment on EAS servers: ${Object.keys(
serverEnvVars
).join(', ')}.`
);
} else {
Log.log(
`No environment variables with visibility "Plain text" and "Sensitive" found for the "${environment.toLowerCase()}" environment on EAS servers.`
);
}
if (buildProfile.env && Object.keys(buildProfile.env).length > 0) {
Log.log(
`Environment variables loaded from the "${buildProfileName}" build profile "env" configuration: ${
buildProfile.env && Object.keys(buildProfile.env).join(', ')
}.`
);
}
if (
buildProfile.env &&
Object.keys(buildProfile.env).length > 0 &&
Object.keys(serverEnvVars).length > 0
) {
const overlappingKeys = Object.keys(serverEnvVars).filter(
key => buildProfile.env && Object.keys(buildProfile.env).includes(key)
);
if (overlappingKeys.length > 0) {
Log.warn(
`The following environment variables are defined in both the "${buildProfileName}" build profile "env" configuration and the "${environment.toLowerCase()}" environment on EAS servers: ${overlappingKeys.join(
', '
)}. The values from the build profile configuration will be used.`
);
}
}
Log.newLine();
return { ...serverEnvVars, ...buildProfile.env };
} catch (e) {
Log.error(`Failed to pull env variables for environment ${environment} from EAS servers`);
Log.error(e);
Log.error(
'This can possibly be a bug in EAS/EAS CLI. Report it here: https://github.com/expo/eas-cli/issues'
);
return { ...buildProfile.env };
}
}
function resolveSuggestedEnvironmentForBuildProfileConfiguration(
buildProfile: BuildProfile
): EnvironmentVariableEnvironment {
const setEnvironmentMessage =
'Set the "environment" field in the build profile if you want to specify the environment manually.';
if (buildProfile.distribution === 'store') {
Log.log(
`We detected that you are building for the "store" distribution. Resolving the environment for environment variables used during the build to "production". ${setEnvironmentMessage}`
);
return EnvironmentVariableEnvironment.Production;
} else {
if (buildProfile.developmentClient) {
Log.log(
`We detected that you are building the development client. Resolving the environment for environment variables used during the build to "development". ${setEnvironmentMessage}`
);
return EnvironmentVariableEnvironment.Development;
}
Log.log(
`We detected that you are building for the "internal" distribution. Resolving the environment for environment variables used during the build to "preview". ${setEnvironmentMessage}`
);
return EnvironmentVariableEnvironment.Preview;
}
}
-19
View File
@@ -3,7 +3,6 @@ import {
ArchiveSourceType,
BuildMode,
BuildTrigger,
FingerprintSourceType,
Metadata,
Workflow,
} from '@expo/eas-build-job';
@@ -16,10 +15,8 @@ import {
BuildMetadataInput,
BuildWorkflow,
DistributionType,
FingerprintSourceInput,
BuildMode as GraphQLBuildMode,
BuildTrigger as GraphQLBuildTrigger,
FingerprintSourceType as GraphQLFingeprintSourceType,
ProjectArchiveSourceInput,
ProjectArchiveSourceType,
WorkerLoggerLevel,
@@ -45,8 +42,6 @@ export function transformProjectArchive(archiveSource: ArchiveSource): ProjectAr
export function transformMetadata(metadata: Metadata): BuildMetadataInput {
return {
...metadata,
fingerprintSource:
metadata.fingerprintSource && transformFingerprintSource(metadata.fingerprintSource),
credentialsSource:
metadata.credentialsSource && transformCredentialsSource(metadata.credentialsSource),
distribution: metadata.distribution && transformDistribution(metadata.distribution),
@@ -57,20 +52,6 @@ export function transformMetadata(metadata: Metadata): BuildMetadataInput {
};
}
export function transformFingerprintSource(
fingerprintSource: NonNullable<Metadata['fingerprintSource']>
): FingerprintSourceInput | null {
if (fingerprintSource.type !== FingerprintSourceType.GCS) {
return null;
}
return {
type: GraphQLFingeprintSourceType.Gcs,
bucketKey: fingerprintSource.bucketKey,
isDebugFingerprint: fingerprintSource.isDebugFingerprint,
};
}
function transformCredentialsSource(
credentialsSource: Metadata['credentialsSource']
): BuildCredentialsSource {
@@ -5,7 +5,6 @@ import { vol } from 'memfs';
import os from 'os';
import type { XCBuildConfiguration } from 'xcode';
import { learnMore } from '../../../log';
import { readPlistAsync } from '../../../utils/plist';
import { resolveVcsClient } from '../../../vcs';
import {
@@ -317,9 +316,7 @@ describe(readShortVersionAsync, () => {
vcsClient
)
).rejects.toThrowError(
`The required format for "CFBundleShortVersionString" in Info.plist is one to three period-separated integers, such as 10.14.1. The string can only contain numeric characters (0-9) and periods. Current value: 0.0.7.1.028. Edit the "CFBundleShortVersionString" in your Info.plist to match the required format. ${learnMore(
'https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleshortversionstring'
)}`
'CFBundleShortVersionString (version field in app.json/app.config.js) must be a period-separated list of three non-negative integers. Current value: 0.0.7.1.028'
);
});
});
+4 -4
View File
@@ -24,7 +24,7 @@ import {
export async function createIosContextAsync(
ctx: CommonContext<Platform.IOS>
): Promise<IosBuildContext> {
const { buildProfile, env } = ctx;
const { buildProfile } = ctx;
if (ctx.workflow === Workflow.MANAGED) {
await ensureBundleIdentifierIsDefinedForManagedProjectAsync(ctx);
@@ -47,7 +47,7 @@ export async function createIosContextAsync(
projectDir: ctx.projectDir,
exp: ctx.exp,
xcodeBuildContext,
env,
env: buildProfile.env,
vcsClient: ctx.vcsClient,
});
const applicationTarget = findApplicationTarget(targets);
@@ -77,7 +77,7 @@ export async function prepareIosBuildAsync(
return await prepareBuildRequestForPlatformAsync({
ctx,
ensureCredentialsAsync: async (ctx: BuildContext<Platform.IOS>) => {
return await ensureIosCredentialsAsync(ctx, ctx.ios.targets);
return ensureIosCredentialsAsync(ctx, ctx.ios.targets);
},
syncProjectConfigurationAsync: async () => {
await syncProjectConfigurationAsync({
@@ -89,7 +89,7 @@ export async function prepareIosBuildAsync(
? false
: ctx.buildProfile.autoIncrement,
vcsClient: ctx.vcsClient,
env: ctx.env,
env: ctx.buildProfile.env,
});
},
prepareJobAsync: async (
@@ -110,10 +110,6 @@ export async function prepareJobAsync(
},
}),
loggerLevel: ctx.loggerLevel,
// Technically, these are unused, but let's include them here for type consistency.
// See: https://github.com/expo/eas-build/pull/454
appId: ctx.projectId,
initiatingUserId: ctx.user.id,
};
return sanitizeBuildJob(job) as Ios.Job;
}
+8 -24
View File
@@ -11,7 +11,7 @@ import { Target } from '../../credentials/ios/types';
import { AppPlatform } from '../../graphql/generated';
import { AppVersionMutation } from '../../graphql/mutations/AppVersionMutation';
import { AppVersionQuery } from '../../graphql/queries/AppVersionQuery';
import Log, { learnMore } from '../../log';
import Log from '../../log';
import { ora } from '../../ora';
import { findApplicationTarget } from '../../project/ios/target';
import { getNextBuildNumber, isValidBuildNumber } from '../../project/ios/versions';
@@ -23,7 +23,7 @@ import { Client } from '../../vcs/vcs';
import { updateAppJsonConfigAsync } from '../utils/appJson';
import { bumpAppVersionAsync, ensureStaticConfigExists } from '../utils/version';
const SHORT_VERSION_REGEX = /^\d+(\.\d+){0,2}$/;
const SHORT_VERSION_REGEX = /^\d+.\d+.\d+$/;
export enum BumpStrategy {
APP_VERSION,
@@ -100,27 +100,11 @@ export async function bumpVersionInAppJsonAsync({
}
}
function validateShortVersion({
shortVersion,
workflow,
}: {
shortVersion: string | undefined;
workflow: Workflow;
}): void {
function validateShortVersion(shortVersion: string | undefined): void {
if (shortVersion && !SHORT_VERSION_REGEX.test(shortVersion)) {
if (workflow === Workflow.MANAGED) {
throw new Error(
`The required format for "version" field from app.json/app.config.ts is one to three period-separated integers, such as 10.14.1. The string can only contain numeric characters (0-9) and periods. Current value: ${shortVersion}. Edit the "version" field in your app.json/app.config.ts to match the required format. ${learnMore(
'https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleshortversionstring'
)}`
);
} else {
throw new Error(
`The required format for "CFBundleShortVersionString" in Info.plist is one to three period-separated integers, such as 10.14.1. The string can only contain numeric characters (0-9) and periods. Current value: ${shortVersion}. Edit the "CFBundleShortVersionString" in your Info.plist to match the required format. ${learnMore(
'https://developer.apple.com/documentation/bundleresources/information_property_list/cfbundleshortversionstring'
)}`
);
}
throw new Error(
`CFBundleShortVersionString (version field in app.json/app.config.js) must be a period-separated list of three non-negative integers. Current value: ${shortVersion}`
);
}
}
@@ -138,10 +122,10 @@ export async function readShortVersionAsync(
infoPlist.CFBundleShortVersionString &&
evaluateTemplateString(infoPlist.CFBundleShortVersionString, buildSettings);
validateShortVersion({ shortVersion, workflow });
validateShortVersion(shortVersion);
return shortVersion;
} else {
validateShortVersion({ shortVersion: exp.version, workflow });
validateShortVersion(exp.version);
return exp.version;
}
}
+12 -22
View File
@@ -3,11 +3,10 @@ import spawnAsync from '@expo/spawn-async';
import { ChildProcess } from 'child_process';
import semver from 'semver';
import Log from '../log';
import { ora } from '../ora';
const PLUGIN_PACKAGE_NAME = 'eas-cli-local-build-plugin';
const PLUGIN_PACKAGE_VERSION = '1.0.144';
const PLUGIN_PACKAGE_VERSION = '1.0.118';
export enum LocalBuildMode {
/**
@@ -40,8 +39,7 @@ export interface LocalBuildOptions {
export async function runLocalBuildAsync(
job: Job,
metadata: Metadata,
options: LocalBuildOptions,
env: Record<string, string>
options: LocalBuildOptions
): Promise<void> {
const { command, args } = await getCommandAndArgsAsync(job, metadata);
let spinner;
@@ -56,26 +54,18 @@ export async function runLocalBuildAsync(
};
process.on('SIGINT', interruptHandler);
try {
const mergedEnv = {
...env,
...process.env,
EAS_LOCAL_BUILD_WORKINGDIR: options.workingdir ?? process.env.EAS_LOCAL_BUILD_WORKINGDIR,
...(options.skipCleanup || options.skipNativeBuild
? { EAS_LOCAL_BUILD_SKIP_CLEANUP: '1' }
: {}),
...(options.skipNativeBuild ? { EAS_LOCAL_BUILD_SKIP_NATIVE_BUILD: '1' } : {}),
...(options.artifactsDir ? { EAS_LOCAL_BUILD_ARTIFACTS_DIR: options.artifactsDir } : {}),
...(options.artifactPath ? { EAS_LOCAL_BUILD_ARTIFACT_PATH: options.artifactPath } : {}),
};
// log command execution to assist in debugging local builds
Log.debug('Running local build, using local-build-plugin', {
command,
args,
env: mergedEnv,
});
const spawnPromise = spawnAsync(command, args, {
stdio: options.verbose ? 'inherit' : 'pipe',
env: mergedEnv,
env: {
...process.env,
EAS_LOCAL_BUILD_WORKINGDIR: options.workingdir ?? process.env.EAS_LOCAL_BUILD_WORKINGDIR,
...(options.skipCleanup || options.skipNativeBuild
? { EAS_LOCAL_BUILD_SKIP_CLEANUP: '1' }
: {}),
...(options.skipNativeBuild ? { EAS_LOCAL_BUILD_SKIP_NATIVE_BUILD: '1' } : {}),
...(options.artifactsDir ? { EAS_LOCAL_BUILD_ARTIFACTS_DIR: options.artifactsDir } : {}),
...(options.artifactPath ? { EAS_LOCAL_BUILD_ARTIFACT_PATH: options.artifactPath } : {}),
},
});
childProcess = spawnPromise.child;
await spawnPromise;
+12 -11
View File
@@ -1,4 +1,4 @@
import { FingerprintSource, Metadata, Platform, sanitizeMetadata } from '@expo/eas-build-job';
import { Metadata, Platform, sanitizeMetadata } from '@expo/eas-build-job';
import { IosEnterpriseProvisioning } from '@expo/eas-json';
import fs from 'fs-extra';
import resolveFrom from 'resolve-from';
@@ -10,17 +10,13 @@ import { LocalBuildMode } from './local';
import { BuildDistributionType } from './types';
import Log from '../log';
import { getUsername, 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 { easCliVersion } from '../utils/easCli';
export async function collectMetadataAsync<T extends Platform>(
ctx: BuildContext<T>,
runtimeAndFingerprintMetadata: {
runtimeVersion?: string | undefined;
fingerprintHash?: string | undefined;
fingerprintSource?: FingerprintSource | undefined;
}
ctx: BuildContext<T>
): Promise<Metadata> {
const channelObject = await resolveChannelAsync(ctx);
const distribution = ctx.buildProfile.distribution ?? BuildDistributionType.STORE;
@@ -31,9 +27,15 @@ export async function collectMetadataAsync<T extends Platform>(
workflow: ctx.workflow,
credentialsSource: ctx.buildProfile.credentialsSource,
sdkVersion: ctx.exp.sdkVersion,
runtimeVersion: runtimeAndFingerprintMetadata?.runtimeVersion,
fingerprintHash: runtimeAndFingerprintMetadata?.fingerprintHash,
fingerprintSource: runtimeAndFingerprintMetadata?.fingerprintSource,
runtimeVersion:
(await resolveRuntimeVersionAsync({
exp: ctx.exp,
platform: ctx.platform,
workflow: ctx.workflow,
projectDir: ctx.projectDir,
env: ctx.buildProfile.env,
cwd: ctx.projectDir,
})) ?? undefined,
reactNativeVersion: await getReactNativeVersionAsync(ctx.projectDir),
...channelObject,
distribution,
@@ -62,7 +64,6 @@ export async function collectMetadataAsync<T extends Platform>(
requiredPackageManager: ctx.requiredPackageManager ?? undefined,
selectedImage: ctx.buildProfile.image,
customNodeVersion: ctx.buildProfile.node,
environment: ctx.buildProfile.environment,
simulator: 'simulator' in ctx.buildProfile && ctx.buildProfile.simulator,
};
return sanitizeMetadata(metadata);
+2 -3
View File
@@ -50,9 +50,8 @@ export async function listAndRenderBuildsOnAppAsync(
}),
promptOptions: {
title: 'Load more builds?',
renderListItems: builds => {
renderPageOfBuilds({ builds, projectDisplayName, paginatedQueryOptions });
},
renderListItems: builds =>
renderPageOfBuilds({ builds, projectDisplayName, paginatedQueryOptions }),
},
});
}
+16 -62
View File
@@ -1,7 +1,8 @@
import { ExpoConfig } from '@expo/config';
import { ExpoConfig } from '@expo/config-types';
import { Env, Platform, Workflow } from '@expo/eas-build-job';
import {
AppVersionSource,
BuildProfile,
EasJson,
EasJsonAccessor,
EasJsonUtils,
@@ -18,7 +19,6 @@ import { BuildRequestSender, MaybeBuildFragment, waitForBuildEndAsync } from './
import { ensureProjectConfiguredAsync } from './configure';
import { BuildContext } from './context';
import { createBuildContextAsync } from './createContext';
import { evaluateConfigWithEnvVarsAsync } from './evaluateConfigWithEnvVarsAsync';
import { prepareIosBuildAsync } from './ios/build';
import { LocalBuildMode, LocalBuildOptions } from './local';
import { ensureExpoDevClientInstalledForDevClientBuildsAsync } from './utils/devClient';
@@ -57,9 +57,8 @@ import {
validateAppVersionRuntimePolicySupportAsync,
} from '../project/projectUtils';
import {
ensureAppVersionSourceIsSetAsync,
validateAppConfigForRemoteVersionSource,
validateBuildProfileVersionSettingsAsync,
validateBuildProfileVersionSettings,
} from '../project/remoteVersionSource';
import { confirmAsync } from '../prompts';
import { runAsync } from '../run/run';
@@ -130,30 +129,19 @@ export async function runBuildAndSubmitAsync(
profileName: flags.profile ?? undefined,
projectDir,
});
Log.log(
`Loaded "env" configuration for the "${buildProfiles[0].profileName}" profile: ${
buildProfiles[0].profile.env
? Object.keys(buildProfiles[0].profile.env).join(', ')
: 'no environment variables specified'
}. ${learnMore('https://docs.expo.dev/build-reference/variables/')}`
);
for (const buildProfile of buildProfiles) {
if (buildProfile.profile.image && ['default', 'stable'].includes(buildProfile.profile.image)) {
Log.warn(
`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/`
);
} else if (
buildProfile.profile.image &&
[
'ubuntu-20.04-jdk-11-ndk-r19c',
'ubuntu-20.04-jdk-8-ndk-r19c',
'ubuntu-20.04-jdk-11-ndk-r21e',
'ubuntu-20.04-jdk-8-ndk-r21e',
'ubuntu-22.04-jdk-8-ndk-r21e',
'ubuntu-20.04-jdk-11-ndk-r23b',
].includes(buildProfile.profile.image)
) {
Log.warn(
`The "image" field in the build profile "${buildProfile.profileName}" is set to "${
buildProfile.profile.image
}". This image is deprecated and will be removed on September 1st, 2024. ${learnMore(
'https://expo.dev/changelog/2024/07-12-eas-build-upcoming-android-images-updates'
)}`
);
}
}
@@ -167,12 +155,7 @@ export async function runBuildAndSubmitAsync(
const customBuildConfigMetadataByPlatform: { [p in AppPlatform]?: CustomBuildConfigMetadata } =
{};
for (const buildProfile of buildProfiles) {
await validateBuildProfileVersionSettingsAsync(
buildProfile,
easJsonCliConfig,
projectDir,
flags
);
validateBuildProfileVersionSettings(buildProfile, easJsonCliConfig);
const maybeMetadata = await validateCustomBuildConfigAsync({
projectDir,
profile: buildProfile.profile,
@@ -191,15 +174,6 @@ export async function runBuildAndSubmitAsync(
for (const buildProfile of buildProfiles) {
const platform = toAppPlatform(buildProfile.platform);
const { env } = await evaluateConfigWithEnvVarsAsync({
buildProfile: buildProfile.profile,
buildProfileName: buildProfile.profileName,
graphqlClient,
getProjectConfig: getDynamicPrivateProjectConfigAsync,
opts: { env: buildProfile.profile.env },
});
const { build: maybeBuild, buildCtx } = await prepareAndStartBuildAsync({
projectDir,
flags,
@@ -212,7 +186,6 @@ export async function runBuildAndSubmitAsync(
vcsClient,
getDynamicPrivateProjectConfigAsync,
customBuildConfigMetadata: customBuildConfigMetadataByPlatform[platform],
env,
});
if (maybeBuild) {
startedBuilds.push({ build: maybeBuild, buildProfile });
@@ -260,6 +233,7 @@ export async function runBuildAndSubmitAsync(
buildCtx: nullthrows(buildCtxByPlatform[startedBuild.build.platform]),
moreBuilds: startedBuilds.length > 1,
projectDir,
buildProfile: startedBuild.buildProfile.profile,
submitProfile,
nonInteractive: flags.nonInteractive,
selectedSubmitProfileName: flags.submitProfile,
@@ -348,7 +322,6 @@ async function prepareAndStartBuildAsync({
vcsClient,
getDynamicPrivateProjectConfigAsync,
customBuildConfigMetadata,
env,
}: {
projectDir: string;
flags: BuildFlags;
@@ -361,7 +334,6 @@ async function prepareAndStartBuildAsync({
vcsClient: Client;
getDynamicPrivateProjectConfigAsync: DynamicConfigContextFn;
customBuildConfigMetadata?: CustomBuildConfigMetadata;
env: Env;
}): Promise<{ build: BuildFragment | undefined; buildCtx: BuildContext<Platform> }> {
const buildCtx = await createBuildContextAsync({
buildProfileName: buildProfile.profileName,
@@ -381,10 +353,9 @@ async function prepareAndStartBuildAsync({
vcsClient,
getDynamicPrivateProjectConfigAsync,
customBuildConfigMetadata,
buildLoggerLevel: flags.buildLoggerLevel ?? (Log.isDebug ? LoggerLevel.DEBUG : undefined),
buildLoggerLevel: flags.buildLoggerLevel,
freezeCredentials: flags.freezeCredentials,
repack: flags.repack,
env,
});
if (moreBuilds) {
@@ -423,25 +394,6 @@ async function prepareAndStartBuildAsync({
}
await validateAppVersionRuntimePolicySupportAsync(buildCtx.projectDir, buildCtx.exp);
if (
easJsonCliConfig?.appVersionSource === undefined &&
buildProfile.profile.autoIncrement !== 'version'
) {
if (buildProfile.profile.autoIncrement !== true) {
Log.warn(
`The field "cli.appVersionSource" is not set, but it will be required in the future. ${learnMore(
'https://docs.expo.dev/build-reference/app-versions/'
)}`
);
} else {
const easJsonAccessor = EasJsonAccessor.fromProjectPath(projectDir);
easJsonCliConfig = await ensureAppVersionSourceIsSetAsync(
easJsonAccessor,
easJsonCliConfig,
flags.nonInteractive
);
}
}
if (easJsonCliConfig?.appVersionSource === AppVersionSource.REMOTE) {
validateAppConfigForRemoteVersionSource(buildCtx.exp, buildProfile.platform);
}
@@ -478,6 +430,7 @@ async function prepareAndStartSubmissionAsync({
buildCtx,
moreBuilds,
projectDir,
buildProfile,
submitProfile,
selectedSubmitProfileName,
nonInteractive,
@@ -486,6 +439,7 @@ async function prepareAndStartSubmissionAsync({
buildCtx: BuildContext<Platform>;
moreBuilds: boolean;
projectDir: string;
buildProfile: BuildProfile;
submitProfile: SubmitProfile;
selectedSubmitProfileName?: string;
nonInteractive: boolean;
@@ -497,7 +451,7 @@ async function prepareAndStartSubmissionAsync({
profile: submitProfile,
archiveFlags: { id: build.id },
nonInteractive,
env: buildCtx.env,
env: buildProfile.env,
credentialsCtx: buildCtx.credentialsCtx,
applicationIdentifier: buildCtx.android?.applicationId ?? buildCtx.ios?.bundleIdentifier,
actor: buildCtx.user,
-23
View File
@@ -1,9 +1,3 @@
import { ResourceClass } from '@expo/eas-json';
import { LoggerLevel } from '@expo/logger';
import { LocalBuildOptions } from './local';
import { RequestedPlatform } from '../platform';
export enum BuildStatus {
NEW = 'new',
IN_QUEUE = 'in-queue',
@@ -20,20 +14,3 @@ export enum BuildDistributionType {
/** @deprecated Use simulator flag instead */
SIMULATOR = 'simulator',
}
export interface BuildFlags {
requestedPlatform: RequestedPlatform;
profile?: string;
nonInteractive: boolean;
wait: boolean;
clearCache: boolean;
json: boolean;
autoSubmit: boolean;
submitProfile?: string;
localBuildOptions: LocalBuildOptions;
resourceClass?: ResourceClass;
message?: string;
buildLoggerLevel?: LoggerLevel;
freezeCredentials: boolean;
repack: boolean;
}
@@ -62,9 +62,7 @@ export function printBuildResults(builds: (BuildFragment | null)[]): void {
assert(build, 'Build should be defined');
printBuildResult(build);
} else {
(builds.filter(i => i) as BuildFragment[]).forEach(build => {
printBuildResult(build);
});
(builds.filter(i => i) as BuildFragment[]).forEach(build => printBuildResult(build));
}
}
@@ -99,9 +97,9 @@ function printBuildResult(build: BuildFragment): void {
// to the build details page and let people press the button to download there
const qrcodeUrl =
build.platform === AppPlatform.Ios ? getInternalDistributionInstallUrl(build) : logsUrl;
qrcodeTerminal.generate(qrcodeUrl, { small: true }, code => {
Log.log(`${indentString(code, 2)}\n`);
});
qrcodeTerminal.generate(qrcodeUrl, { small: true }, code =>
Log.log(`${indentString(code, 2)}\n`)
);
Log.log(
`${appPlatformEmojis[build.platform]} Open this link on your ${
appPlatformDisplayNames[build.platform]
@@ -100,7 +100,6 @@ export type LocalFile = {
};
export async function makeProjectMetadataFileAsync(archivePath: string): Promise<LocalFile> {
await fs.mkdirp(getTmpDirectory());
const metadataLocation = path.join(getTmpDirectory(), `${uuidv4()}-eas-build-metadata.json`);
const archiveContent: string[] = [];
+25 -19
View File
@@ -51,24 +51,30 @@ export function getUpdateGroupUrl(
).toString();
}
export function getWorkflowRunUrl(
accountName: string,
projectName: string,
workflowRunId: string
): string {
return new URL(
`/accounts/${encodeURIComponent(accountName)}/projects/${encodeURIComponent(
projectName
)}/workflows/${workflowRunId}`,
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);
}
export function getProjectGitHubSettingsUrl(accountName: string, projectName: string): string {
return new URL(
`/accounts/${encodeURIComponent(accountName)}/projects/${encodeURIComponent(
projectName
)}/github`,
getExpoWebsiteBaseUrl()
).toString();
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();
}
+2 -2
View File
@@ -9,9 +9,9 @@ import Log, { learnMore } from '../log';
import { isPNGAsync } from '../utils/image';
export function checkNodeEnvVariable(ctx: CommonContext<Platform>): void {
if (ctx.env?.NODE_ENV === 'production') {
if (ctx.buildProfile.env?.NODE_ENV === 'production') {
Log.warn(
'You set NODE_ENV=production in the build profile or environment variables. Remember that it will be available during the entire build process. In particular, it will make yarn/npm install only production packages.'
'You set NODE_ENV=production in the build profile. Remember that it will be available during the entire build process. In particular, it will make yarn/npm install only production packages.'
);
Log.newLine();
}
@@ -17,9 +17,7 @@ import {
describe(assertVersion, () => {
it('throws if the branch mapping is not the correct version', () => {
expect(() => {
assertVersion(testChannelBasicInfo, 5);
}).toThrowError(BranchMappingValidationError);
expect(() => assertVersion(testChannelBasicInfo, 5)).toThrowError(BranchMappingValidationError);
});
it('asserts the correct version', () => {
assertVersion(testChannelBasicInfo, 0);
@@ -128,7 +128,6 @@ export const testChannelObject: UpdateChannelObject = {
branchMapping:
'{"data":[{"branchId":"754bf17f-efc0-46ab-8a59-a03f20e53e9b","branchMappingLogic":{"operand":0.15,"clientKey":"rolloutToken","branchMappingOperator":"hash_lt"}},{"branchId":"6941a8dd-5c0a-48bc-8876-f49c88ed419f","branchMappingLogic":"true"}],"version":0}',
updateBranches: [testUpdateBranch1, testUpdateBranch2],
isPaused: false,
__typename: 'UpdateChannel',
};
@@ -28,7 +28,7 @@ import {
*/
export class SelectChannel implements EASUpdateAction<UpdateChannelBasicInfoFragment | null> {
constructor(
private readonly options: {
private options: {
filterPredicate?: (channelInfo: UpdateChannelBasicInfoFragment) => boolean;
printedType?: string;
pageSize?: number;
@@ -91,8 +91,8 @@ export class SelectChannel implements EASUpdateAction<UpdateChannelBasicInfoFrag
queryParams: QueryParams
): Promise<Connection<UpdateChannelBasicInfoFragment>> =>
filterPredicate
? await this.filterQueryAsync(ctx, queryParams, filterPredicate)
: await this.queryAsync(ctx, queryParams);
? this.filterQueryAsync(ctx, queryParams, filterPredicate)
: this.queryAsync(ctx, queryParams);
const getTitleAsync = async (channelInfo: UpdateChannelBasicInfoFragment): Promise<string> =>
channelInfo.name;
+5 -19
View File
@@ -89,9 +89,7 @@ export async function listAndRenderChannelsOnAppAsync(
queryChannelsOnAppAsync(graphqlClient, { limit, offset, appId: projectId }),
promptOptions: {
title: 'Load more channels?',
renderListItems: channels => {
renderPageOfChannels(channels, paginatedQueryOptions);
},
renderListItems: channels => renderPageOfChannels(channels, paginatedQueryOptions),
},
});
}
@@ -110,11 +108,7 @@ export async function listAndRenderBranchesAndUpdatesOnChannelAsync(
}
): Promise<void> {
const channel = await ChannelQuery.viewUpdateChannelAsync(graphqlClient, { appId, channelName });
renderChannelHeaderContent({
channelName: channel.name,
channelId: channel.id,
isPaused: channel.isPaused,
});
renderChannelHeaderContent({ channelName: channel.name, channelId: channel.id });
if (paginatedQueryOptions.nonInteractive) {
const branches = await queryBranchesAndUpdateGroupsOnChannelAsync(graphqlClient, {
@@ -137,9 +131,8 @@ export async function listAndRenderBranchesAndUpdatesOnChannelAsync(
}),
promptOptions: {
title: 'Load more channels?',
renderListItems: branches => {
renderPageOfBranchesOnChannel(channel, branches, paginatedQueryOptions);
},
renderListItems: branches =>
renderPageOfBranchesOnChannel(channel, branches, paginatedQueryOptions),
},
});
}
@@ -171,11 +164,7 @@ function renderPageOfChannels(
printJsonOnlyOutput({ currentPage });
} else {
for (const channel of currentPage) {
renderChannelHeaderContent({
channelName: channel.name,
channelId: channel.id,
isPaused: channel.isPaused,
});
renderChannelHeaderContent({ channelName: channel.name, channelId: channel.id });
Log.addNewLineIfNone();
logChannelDetails(channel);
@@ -204,11 +193,9 @@ function renderPageOfBranchesOnChannel(
function renderChannelHeaderContent({
channelName,
channelId,
isPaused,
}: {
channelName: string;
channelId: string;
isPaused: boolean;
}): void {
Log.addNewLineIfNone();
Log.log(chalk.bold('Channel:'));
@@ -216,7 +203,6 @@ function renderChannelHeaderContent({
formatFields([
{ label: 'Name', value: channelName },
{ label: 'ID', value: channelId },
{ label: 'Status', value: isPaused ? 'Paused' : 'Active' },
])
);
Log.addNewLineIfNone();
@@ -6,7 +6,6 @@ import nullthrows from 'nullthrows';
import AnalyticsContextField from './context/AnalyticsContextField';
import ContextField from './context/ContextField';
import DynamicLoggedInContextField from './context/DynamicLoggedInContextField';
import {
DynamicPrivateProjectConfigContextField,
DynamicPublicProjectConfigContextField,
@@ -16,8 +15,6 @@ import MaybeLoggedInContextField from './context/MaybeLoggedInContextField';
import { OptionalPrivateProjectConfigContextField } from './context/OptionalPrivateProjectConfigContextField';
import { PrivateProjectConfigContextField } from './context/PrivateProjectConfigContextField';
import ProjectDirContextField from './context/ProjectDirContextField';
import { ProjectIdContextField } from './context/ProjectIdContextField';
import { ServerSideEnvironmentVariablesContextField } from './context/ServerSideEnvironmentVariablesContextField';
import SessionManagementContextField from './context/SessionManagementContextField';
import VcsClientContextField from './context/VcsClientContextField';
import { EasCommandError } from './errors';
@@ -26,7 +23,6 @@ import {
CommandEvent,
createAnalyticsAsync,
} from '../analytics/AnalyticsManager';
import { EnvironmentVariableEnvironment } from '../graphql/generated';
import Log from '../log';
import SessionManager from '../user/SessionManager';
import { Client } from '../vcs/vcs';
@@ -47,26 +43,8 @@ export type ContextOutput<
[P in keyof T]: T[P];
};
type GetContextType<Type> = {
[Property in keyof Type]: any;
};
const BASE_GRAPHQL_ERROR_MESSAGE: string = 'GraphQL request failed.';
interface BaseGetContextAsyncArgs {
nonInteractive: boolean;
vcsClientOverride?: Client;
}
interface GetContextAsyncArgsWithRequiredServerSideEnvironmentArgument
extends BaseGetContextAsyncArgs {
withServerSideEnvironment: EnvironmentVariableEnvironment | null;
}
interface GetContextAsyncArgsWithoutServerSideEnvironmentArgument extends BaseGetContextAsyncArgs {
withServerSideEnvironment?: never;
}
export default abstract class EasCommand extends Command {
protected static readonly ContextOptions = {
/**
@@ -83,16 +61,8 @@ export default abstract class EasCommand extends Command {
MaybeLoggedIn: {
maybeLoggedIn: new MaybeLoggedInContextField(),
},
/**
* Specify this context if the logged-in requirement is only necessary in a particular execution of the command.
*/
DynamicLoggedIn: {
// eslint-disable-next-line async-protect/async-suffix
getDynamicLoggedInAsync: new DynamicLoggedInContextField(),
},
/**
* Specify this context requirement if the command needs to mutate the user session.
* @deprecated Should not be used outside of session management commands, which currently only includes `login` and `logout`.
*/
SessionManagment: {
sessionManager: new SessionManagementContextField(),
@@ -102,7 +72,7 @@ export default abstract class EasCommand extends Command {
* run within a project directory, null otherwise.
*/
OptionalProjectConfig: {
optionalPrivateProjectConfig: new OptionalPrivateProjectConfigContextField(),
privateProjectConfig: new OptionalPrivateProjectConfigContextField(),
},
/**
* Require this command to be run in a project directory. Return the project directory in the context.
@@ -137,16 +107,6 @@ export default abstract class EasCommand extends Command {
Vcs: {
vcsClient: new VcsClientContextField(),
},
ServerSideEnvironmentVariables: {
// eslint-disable-next-line async-protect/async-suffix
getServerSideEnvironmentVariablesAsync: new ServerSideEnvironmentVariablesContextField(),
},
/**
* Require the project to be identified and registered on server. Returns the project ID evaluated from the app config.
*/
ProjectId: {
projectId: new ProjectIdContextField(),
},
};
/**
@@ -181,19 +141,7 @@ export default abstract class EasCommand extends Command {
} = object,
>(
commandClass: { contextDefinition: ContextInput<C> },
{
nonInteractive,
vcsClientOverride,
// if specified and not null, the env vars from the selected environment will be fetched from the server
// to resolve dynamic config (if dynamic config context is used) and enable getServerSideEnvironmentVariablesAsync function (if server side environment variables context is used)
withServerSideEnvironment,
}: C extends
| GetContextType<typeof EasCommand.ContextOptions.ProjectConfig>
| GetContextType<typeof EasCommand.ContextOptions.DynamicProjectConfig>
| GetContextType<typeof EasCommand.ContextOptions.OptionalProjectConfig>
| GetContextType<typeof EasCommand.ContextOptions.ServerSideEnvironmentVariables>
? GetContextAsyncArgsWithRequiredServerSideEnvironmentArgument
: GetContextAsyncArgsWithoutServerSideEnvironmentArgument
{ nonInteractive, vcsClientOverride }: { nonInteractive: boolean; vcsClientOverride?: Client }
): Promise<ContextOutput<C>> {
const contextDefinition = commandClass.contextDefinition;
@@ -207,7 +155,6 @@ export default abstract class EasCommand extends Command {
sessionManager: this.sessionManager,
analytics: this.analytics,
vcsClientOverride,
withServerSideEnvironment,
}),
]);
}
@@ -240,13 +187,13 @@ export default abstract class EasCommand extends Command {
action: `eas ${this.id}`,
});
return await this.runAsync();
return this.runAsync();
}
// eslint-disable-next-line async-protect/async-suffix
override async finally(err: Error): Promise<any> {
await this.analytics.flushAsync();
return await super.finally(err);
return super.finally(err);
}
protected override catch(err: Error): Promise<any> {
@@ -1,5 +1,4 @@
import { Analytics } from '../../analytics/AnalyticsManager';
import { EnvironmentVariableEnvironment } from '../../graphql/generated';
import SessionManager from '../../user/SessionManager';
import { Client } from '../../vcs/vcs';
@@ -8,10 +7,6 @@ export interface ContextOptions {
analytics: Analytics;
nonInteractive: boolean;
vcsClientOverride?: Client;
/**
* If specified, env variables from the selected environment will be fetched from the server and used to evaluate the dynamic config.
*/
withServerSideEnvironment?: EnvironmentVariableEnvironment | null;
}
export default abstract class ContextField<T> {
@@ -1,36 +0,0 @@
import ContextField, { ContextOptions } from './ContextField';
import { ExpoGraphqlClient, createGraphqlClient } from './contextUtils/createGraphqlClient';
import { LoggedInAuthenticationInfo } from '../../user/SessionManager';
import { Actor } from '../../user/User';
import FeatureGateEnvOverrides from '../gating/FeatureGateEnvOverrides';
import FeatureGating from '../gating/FeatureGating';
export type DynamicLoggedInContextFn = () => Promise<{
actor: Actor;
featureGating: FeatureGating;
graphqlClient: ExpoGraphqlClient;
authenticationInfo: LoggedInAuthenticationInfo;
}>;
export default class DynamicLoggedInContextField extends ContextField<DynamicLoggedInContextFn> {
async getValueAsync({
nonInteractive,
sessionManager,
}: ContextOptions): Promise<DynamicLoggedInContextFn> {
return async () => {
const { actor, authenticationInfo } = await sessionManager.ensureLoggedInAsync({
nonInteractive,
});
const featureGateServerValues: { [key: string]: boolean } = actor?.featureGates ?? {};
const graphqlClient = createGraphqlClient(authenticationInfo);
return {
actor,
featureGating: new FeatureGating(featureGateServerValues, new FeatureGateEnvOverrides()),
graphqlClient,
authenticationInfo,
};
};
}
}
@@ -1,14 +1,12 @@
import { ExpoConfig } from '@expo/config';
import { ExpoConfig } from '@expo/config-types';
import ContextField, { ContextOptions } from './ContextField';
import { createGraphqlClient } from './contextUtils/createGraphqlClient';
import { findProjectDirAndVerifyProjectSetupAsync } from './contextUtils/findProjectDirAndVerifyProjectSetupAsync';
import { getProjectIdAsync } from './contextUtils/getProjectIdAsync';
import { loadServerSideEnvironmentVariablesAsync } from './contextUtils/loadServerSideEnvironmentVariablesAsync';
import {
ExpoConfigOptions,
getPrivateExpoConfigAsync,
getPublicExpoConfigAsync,
getPrivateExpoConfig,
getPublicExpoConfig,
} from '../../project/expoConfig';
export type DynamicConfigContextFn = (options?: ExpoConfigOptions) => Promise<{
@@ -21,34 +19,15 @@ export class DynamicPublicProjectConfigContextField extends ContextField<Dynamic
async getValueAsync({
nonInteractive,
sessionManager,
withServerSideEnvironment,
}: ContextOptions): Promise<DynamicConfigContextFn> {
const projectDir = await findProjectDirAndVerifyProjectSetupAsync();
return async (options?: ExpoConfigOptions) => {
const expBefore = await getPublicExpoConfigAsync(projectDir, options);
const expBefore = getPublicExpoConfig(projectDir, options);
const projectId = await getProjectIdAsync(sessionManager, expBefore, {
nonInteractive,
env: options?.env,
});
if (withServerSideEnvironment) {
const { authenticationInfo } = await sessionManager.ensureLoggedInAsync({
nonInteractive,
});
const graphqlClient = createGraphqlClient(authenticationInfo);
const serverSideEnvironmentVariables = await loadServerSideEnvironmentVariablesAsync({
environment: withServerSideEnvironment,
projectId,
graphqlClient,
});
options = {
...options,
env: {
...options?.env,
...serverSideEnvironmentVariables,
},
};
}
const exp = await getPublicExpoConfigAsync(projectDir, options);
const exp = getPublicExpoConfig(projectDir, options);
return {
exp,
projectDir,
@@ -62,34 +41,15 @@ export class DynamicPrivateProjectConfigContextField extends ContextField<Dynami
async getValueAsync({
nonInteractive,
sessionManager,
withServerSideEnvironment,
}: ContextOptions): Promise<DynamicConfigContextFn> {
const projectDir = await findProjectDirAndVerifyProjectSetupAsync();
return async (options?: ExpoConfigOptions) => {
const expBefore = await getPrivateExpoConfigAsync(projectDir, options);
const expBefore = getPrivateExpoConfig(projectDir, options);
const projectId = await getProjectIdAsync(sessionManager, expBefore, {
nonInteractive,
env: options?.env,
});
if (withServerSideEnvironment) {
const { authenticationInfo } = await sessionManager.ensureLoggedInAsync({
nonInteractive,
});
const graphqlClient = createGraphqlClient(authenticationInfo);
const serverSideEnvironmentVariables = await loadServerSideEnvironmentVariablesAsync({
environment: withServerSideEnvironment,
projectId,
graphqlClient,
});
options = {
...options,
env: {
...options?.env,
...serverSideEnvironmentVariables,
},
};
}
const exp = await getPrivateExpoConfigAsync(projectDir, options);
const exp = getPrivateExpoConfig(projectDir, options);
return {
exp,
projectDir,
@@ -1,22 +1,19 @@
import ContextField, { ContextOptions } from './ContextField';
import { ExpoGraphqlClient, createGraphqlClient } from './contextUtils/createGraphqlClient';
import { LoggedInAuthenticationInfo } from '../../user/SessionManager';
import { Actor } from '../../user/User';
import FeatureGateEnvOverrides from '../gating/FeatureGateEnvOverrides';
import FeatureGating from '../gating/FeatureGating';
type LoggedInContextType = {
export default class LoggedInContextField extends ContextField<{
actor: Actor;
featureGating: FeatureGating;
graphqlClient: ExpoGraphqlClient;
authenticationInfo: LoggedInAuthenticationInfo;
};
export default class LoggedInContextField extends ContextField<LoggedInContextType> {
async getValueAsync({
nonInteractive,
sessionManager,
}: ContextOptions): Promise<LoggedInContextType> {
}> {
async getValueAsync({ nonInteractive, sessionManager }: ContextOptions): Promise<{
actor: Actor;
featureGating: FeatureGating;
graphqlClient: ExpoGraphqlClient;
}> {
const { actor, authenticationInfo } = await sessionManager.ensureLoggedInAsync({
nonInteractive,
});
@@ -28,7 +25,6 @@ export default class LoggedInContextField extends ContextField<LoggedInContextTy
actor,
featureGating: new FeatureGating(featureGateServerValues, new FeatureGateEnvOverrides()),
graphqlClient,
authenticationInfo,
};
}
}
@@ -4,18 +4,16 @@ import { Actor } from '../../user/User';
import FeatureGateEnvOverrides from '../gating/FeatureGateEnvOverrides';
import FeatureGating from '../gating/FeatureGating';
type MaybeLoggedInContextType = {
export default class MaybeLoggedInContextField extends ContextField<{
actor: Actor | null;
featureGating: FeatureGating;
graphqlClient: ExpoGraphqlClient;
authenticationInfo: {
accessToken: string | null;
sessionSecret: string | null;
};
};
export default class MaybeLoggedInContextField extends ContextField<MaybeLoggedInContextType> {
async getValueAsync({ sessionManager }: ContextOptions): Promise<MaybeLoggedInContextType> {
}> {
async getValueAsync({ sessionManager }: ContextOptions): Promise<{
actor: Actor | null;
featureGating: FeatureGating;
graphqlClient: ExpoGraphqlClient;
}> {
const authenticationInfo = {
accessToken: sessionManager.getAccessToken(),
sessionSecret: sessionManager.getSessionSecret(),
@@ -29,7 +27,6 @@ export default class MaybeLoggedInContextField extends ContextField<MaybeLoggedI
actor: actor ?? null,
featureGating: new FeatureGating(featureGateServerValues, new FeatureGateEnvOverrides()),
graphqlClient,
authenticationInfo,
};
}
}
@@ -1,12 +1,10 @@
import { ExpoConfig } from '@expo/config';
import { ExpoConfig } from '@expo/config-types';
import { InvalidEasJsonError } from '@expo/eas-json/build/errors';
import ContextField, { ContextOptions } from './ContextField';
import { createGraphqlClient } from './contextUtils/createGraphqlClient';
import { findProjectDirAndVerifyProjectSetupAsync } from './contextUtils/findProjectDirAndVerifyProjectSetupAsync';
import { getProjectIdAsync } from './contextUtils/getProjectIdAsync';
import { loadServerSideEnvironmentVariablesAsync } from './contextUtils/loadServerSideEnvironmentVariablesAsync';
import { getPrivateExpoConfigAsync } from '../../project/expoConfig';
import { getPrivateExpoConfig } from '../../project/expoConfig';
export class OptionalPrivateProjectConfigContextField extends ContextField<
| {
@@ -16,11 +14,7 @@ export class OptionalPrivateProjectConfigContextField extends ContextField<
}
| undefined
> {
async getValueAsync({
nonInteractive,
sessionManager,
withServerSideEnvironment,
}: ContextOptions): Promise<
async getValueAsync({ nonInteractive, sessionManager }: ContextOptions): Promise<
| {
projectId: string;
exp: ExpoConfig;
@@ -41,24 +35,11 @@ export class OptionalPrivateProjectConfigContextField extends ContextField<
return undefined;
}
const expBefore = await getPrivateExpoConfigAsync(projectDir);
const expBefore = getPrivateExpoConfig(projectDir);
const projectId = await getProjectIdAsync(sessionManager, expBefore, {
nonInteractive,
});
let serverSideEnvVars: Record<string, string> | undefined;
if (withServerSideEnvironment) {
const { authenticationInfo } = await sessionManager.ensureLoggedInAsync({
nonInteractive,
});
const graphqlClient = createGraphqlClient(authenticationInfo);
const serverSideEnvironmentVariables = await loadServerSideEnvironmentVariablesAsync({
environment: withServerSideEnvironment,
projectId,
graphqlClient,
});
serverSideEnvVars = serverSideEnvironmentVariables;
}
const exp = await getPrivateExpoConfigAsync(projectDir, { env: serverSideEnvVars });
const exp = getPrivateExpoConfig(projectDir);
return {
exp,
projectDir,
@@ -1,45 +1,26 @@
import { ExpoConfig } from '@expo/config';
import { ExpoConfig } from '@expo/config-types';
import ContextField, { ContextOptions } from './ContextField';
import { createGraphqlClient } from './contextUtils/createGraphqlClient';
import { findProjectDirAndVerifyProjectSetupAsync } from './contextUtils/findProjectDirAndVerifyProjectSetupAsync';
import { getProjectIdAsync } from './contextUtils/getProjectIdAsync';
import { loadServerSideEnvironmentVariablesAsync } from './contextUtils/loadServerSideEnvironmentVariablesAsync';
import { getPrivateExpoConfigAsync } from '../../project/expoConfig';
import { getPrivateExpoConfig } from '../../project/expoConfig';
export class PrivateProjectConfigContextField extends ContextField<{
projectId: string;
exp: ExpoConfig;
projectDir: string;
}> {
async getValueAsync({
nonInteractive,
sessionManager,
withServerSideEnvironment,
}: ContextOptions): Promise<{
async getValueAsync({ nonInteractive, sessionManager }: ContextOptions): Promise<{
projectId: string;
exp: ExpoConfig;
projectDir: string;
}> {
const projectDir = await findProjectDirAndVerifyProjectSetupAsync();
const expBefore = await getPrivateExpoConfigAsync(projectDir);
const expBefore = getPrivateExpoConfig(projectDir);
const projectId = await getProjectIdAsync(sessionManager, expBefore, {
nonInteractive,
});
let serverSideEnvVars: Record<string, string> | undefined;
if (withServerSideEnvironment) {
const { authenticationInfo } = await sessionManager.ensureLoggedInAsync({
nonInteractive,
});
const graphqlClient = createGraphqlClient(authenticationInfo);
const serverSideEnvironmentVariables = await loadServerSideEnvironmentVariablesAsync({
environment: withServerSideEnvironment,
projectId,
graphqlClient,
});
serverSideEnvVars = serverSideEnvironmentVariables;
}
const exp = await getPrivateExpoConfigAsync(projectDir, { env: serverSideEnvVars });
const exp = getPrivateExpoConfig(projectDir);
return {
projectId,
@@ -1,15 +0,0 @@
import ContextField, { ContextOptions } from './ContextField';
import { findProjectDirAndVerifyProjectSetupAsync } from './contextUtils/findProjectDirAndVerifyProjectSetupAsync';
import { getProjectIdAsync } from './contextUtils/getProjectIdAsync';
import { getPrivateExpoConfigAsync } from '../../project/expoConfig';
export class ProjectIdContextField extends ContextField<string> {
async getValueAsync({ nonInteractive, sessionManager }: ContextOptions): Promise<string> {
const projectDir = await findProjectDirAndVerifyProjectSetupAsync();
const expBefore = await getPrivateExpoConfigAsync(projectDir);
const projectId = await getProjectIdAsync(sessionManager, expBefore, {
nonInteractive,
});
return projectId;
}
}
@@ -1,42 +0,0 @@
import ContextField, { ContextOptions } from './ContextField';
import { createGraphqlClient } from './contextUtils/createGraphqlClient';
import { findProjectDirAndVerifyProjectSetupAsync } from './contextUtils/findProjectDirAndVerifyProjectSetupAsync';
import { getProjectIdAsync } from './contextUtils/getProjectIdAsync';
import { loadServerSideEnvironmentVariablesAsync } from './contextUtils/loadServerSideEnvironmentVariablesAsync';
import { getPublicExpoConfigAsync } from '../../project/expoConfig';
type GetServerSideEnvironmentVariablesFn = (
maybeEnv?: Record<string, string>
) => Promise<Record<string, string>>;
export class ServerSideEnvironmentVariablesContextField extends ContextField<GetServerSideEnvironmentVariablesFn> {
async getValueAsync({
nonInteractive,
sessionManager,
withServerSideEnvironment,
}: ContextOptions): Promise<GetServerSideEnvironmentVariablesFn> {
const projectDir = await findProjectDirAndVerifyProjectSetupAsync();
return async (maybeEnv?: Record<string, string>) => {
if (!withServerSideEnvironment) {
throw new Error(
'withServerSideEnvironment parameter is required to evaluate ServerSideEnvironmentVariablesContextField'
);
}
const exp = await getPublicExpoConfigAsync(projectDir, { env: maybeEnv });
const projectId = await getProjectIdAsync(sessionManager, exp, {
nonInteractive,
env: maybeEnv,
});
const { authenticationInfo } = await sessionManager.ensureLoggedInAsync({
nonInteractive,
});
const graphqlClient = createGraphqlClient(authenticationInfo);
const serverSideEnvironmentVariables = await loadServerSideEnvironmentVariablesAsync({
environment: withServerSideEnvironment,
projectId,
graphqlClient,
});
return serverSideEnvironmentVariables;
};
}
}
@@ -6,7 +6,6 @@ import { Role } from '../../../../graphql/generated';
import { AppQuery } from '../../../../graphql/queries/AppQuery';
import { learnMore } from '../../../../log';
import { fetchOrCreateProjectIDForWriteToConfigWithConfirmationAsync } from '../../../../project/fetchOrCreateProjectIDForWriteToConfigWithConfirmationAsync';
import { isExpoInstalled } from '../../../../project/projectUtils';
import SessionManager from '../../../../user/SessionManager';
import { findProjectRootAsync } from '../findProjectDirAndVerifyProjectSetupAsync';
import { getProjectIdAsync } from '../getProjectIdAsync';
@@ -22,7 +21,6 @@ jest.mock('../../../../ora', () => ({
}),
}));
jest.mock('../../../../project/fetchOrCreateProjectIDForWriteToConfigWithConfirmationAsync');
jest.mock('../../../../project/projectUtils');
describe(getProjectIdAsync, () => {
let sessionManager: SessionManager;
@@ -73,7 +71,6 @@ describe(getProjectIdAsync, () => {
);
jest.mocked(findProjectRootAsync).mockResolvedValue('/app');
jest.mocked(isExpoInstalled).mockReturnValue(true);
});
it('gets the project ID from app config if exists', async () => {
@@ -225,7 +222,7 @@ describe(getProjectIdAsync, () => {
jest.mocked(getConfig).mockReturnValue({ exp: { name: 'test', slug: 'test' } } as any);
jest.mocked(modifyConfigAsync).mockResolvedValue({
type: 'success',
config: { name: 'test', slug: 'test', extra: { eas: { projectId: '2345' } } },
config: { expo: { name: 'test', slug: 'test', extra: { eas: { projectId: '2345' } } } },
});
jest
.mocked(fetchOrCreateProjectIDForWriteToConfigWithConfirmationAsync)
@@ -38,7 +38,7 @@ export function createGraphqlClient(authInfo: {
return !!(
err &&
!operation.context.noRetry &&
(err.networkError ?? err.graphQLErrors.some(e => e?.extensions?.isTransient))
(err.networkError || err.graphQLErrors.some(e => e?.extensions?.isTransient))
);
},
}),
@@ -42,7 +42,7 @@ async function ensureEasCliIsNotInDependenciesAsync(projectDir: string): Promise
consoleWarn(`Found ${chalk.bold('eas-cli')} in your project dependencies.`);
}
const maybeRepoRoot = PackageManagerUtils.resolveWorkspaceRoot(projectDir) ?? projectDir;
const maybeRepoRoot = PackageManagerUtils.findWorkspaceRoot(projectDir) ?? projectDir;
if (maybeRepoRoot !== projectDir && (await isEasCliInDependenciesAsync(maybeRepoRoot))) {
printCliVersionWarning = true;
consoleWarn(`Found ${chalk.bold('eas-cli')} in your monorepo dependencies.`);
@@ -1,4 +1,5 @@
import { ExpoConfig, getProjectConfigDescription } from '@expo/config';
import { getProjectConfigDescription } from '@expo/config';
import { ExpoConfig } from '@expo/config-types';
import { Env } from '@expo/eas-build-job';
import chalk from 'chalk';
@@ -7,11 +8,9 @@ import { findProjectRootAsync } from './findProjectDirAndVerifyProjectSetupAsync
import { AppQuery } from '../../../graphql/queries/AppQuery';
import Log, { learnMore } from '../../../log';
import { ora } from '../../../ora';
import {
createOrModifyExpoConfigAsync,
getPrivateExpoConfigAsync,
} from '../../../project/expoConfig';
import { createOrModifyExpoConfigAsync, getPrivateExpoConfig } from '../../../project/expoConfig';
import { fetchOrCreateProjectIDForWriteToConfigWithConfirmationAsync } from '../../../project/fetchOrCreateProjectIDForWriteToConfigWithConfirmationAsync';
import { toAppPrivacy } from '../../../project/projectUtils';
import SessionManager from '../../../user/SessionManager';
import { Actor, getActorUsername } from '../../../user/User';
@@ -19,15 +18,13 @@ import { Actor, getActorUsername } from '../../../user/User';
* Save an EAS project ID to the appropriate field in the app config.
*
* @deprecated Should not be used outside of context functions except in the init command.
* @deprecated Starting from `@expo/config` from SDK 52, the `modifyConfigAsync` function is merging existing data. Once this is released, we can use that instead of manually merging.
*/
export async function saveProjectIdToAppConfigAsync(
projectDir: string,
projectId: string,
options: { env?: Env } = {}
): Promise<void> {
// NOTE(cedric): we disable plugins to avoid writing plugin-generated content to `expo.extra`
const exp = await getPrivateExpoConfigAsync(projectDir, { skipPlugins: true, ...options });
const exp = getPrivateExpoConfig(projectDir, options);
const result = await createOrModifyExpoConfigAsync(
projectDir,
{
@@ -196,6 +193,7 @@ export async function validateOrSetProjectIdAsync({
{
accountName: getAccountNameForEASProjectSync(exp, actor),
projectName: exp.slug,
privacy: toAppPrivacy(exp.privacy),
},
{
nonInteractive: options.nonInteractive,
@@ -1,59 +0,0 @@
import { ExpoGraphqlClient } from './createGraphqlClient';
import { EnvironmentVariableEnvironment } from '../../../graphql/generated';
import { EnvironmentVariablesQuery } from '../../../graphql/queries/EnvironmentVariablesQuery';
import Log from '../../../log';
const cachedServerSideEnvironmentVariables: Record<
EnvironmentVariableEnvironment,
Record<string, string> | null
> = {
[EnvironmentVariableEnvironment.Development]: null,
[EnvironmentVariableEnvironment.Preview]: null,
[EnvironmentVariableEnvironment.Production]: null,
};
export async function loadServerSideEnvironmentVariablesAsync({
environment,
projectId,
graphqlClient,
}: {
environment: EnvironmentVariableEnvironment;
projectId: string;
graphqlClient: ExpoGraphqlClient;
}): Promise<Record<string, string>> {
// don't load environment variables if they were already loaded while executing a command
const cachedEnvVarsForEnvironment = cachedServerSideEnvironmentVariables[environment];
if (cachedEnvVarsForEnvironment) {
return cachedEnvVarsForEnvironment;
}
const environmentVariables = await EnvironmentVariablesQuery.byAppIdWithSensitiveAsync(
graphqlClient,
{
appId: projectId,
environment,
}
);
const serverEnvVars = Object.fromEntries(
environmentVariables
.filter(({ name, value }) => name && value)
.map(({ name, value }) => [name, value])
) as Record<string, string>;
if (Object.keys(serverEnvVars).length > 0) {
Log.log(
`Environment variables with visibility "Plain text" and "Sensitive" loaded from the "${environment.toLowerCase()}" environment on EAS servers: ${Object.keys(
serverEnvVars
).join(', ')}.`
);
} else {
Log.log(
`No environment variables with visibility "Plain text" and "Sensitive" found for the "${environment.toLowerCase()}" environment on EAS servers.`
);
}
Log.newLine();
cachedServerSideEnvironmentVariables[environment] = serverEnvVars;
return serverEnvVars;
}
@@ -1,17 +1,5 @@
import { Flags } from '@oclif/core';
import { EnvironmentVariableEnvironment } from '../graphql/generated';
// NOTE: not exactly true, but, provided mapToLowercase and upperCaseAsync
// are used in tandem, it saves on unnecessary typying in commands
async function upperCaseAsync<T>(input: string): Promise<T> {
return input.toUpperCase() as T;
}
function mapToLowercase<T extends string>(options: T[]): T[] {
return options.map(option => option.toLowerCase()) as T[];
}
export const EasNonInteractiveAndJsonFlags = {
json: Flags.boolean({
description: 'Enable JSON output, non-JSON messages will be printed to stderr.',
@@ -22,52 +10,6 @@ export const EasNonInteractiveAndJsonFlags = {
}),
};
export const EasEnvironmentFlagParameters = {
description: "Environment variable's environment",
parse: upperCaseAsync,
options: mapToLowercase([
EnvironmentVariableEnvironment.Development,
EnvironmentVariableEnvironment.Preview,
EnvironmentVariableEnvironment.Production,
]),
};
export const EASEnvironmentFlag = {
environment: Flags.enum<EnvironmentVariableEnvironment>(EasEnvironmentFlagParameters),
};
export const EASMultiEnvironmentFlag = {
environment: Flags.enum<EnvironmentVariableEnvironment>({
...EasEnvironmentFlagParameters,
multiple: true,
}),
};
export const EASVariableFormatFlag = {
format: Flags.enum({
description: 'Output format',
options: ['long', 'short'],
default: 'short',
}),
};
export const EASVariableVisibilityFlag = {
visibility: Flags.enum<'plaintext' | 'sensitive' | 'secret'>({
description: 'Visibility of the variable',
options: ['plaintext', 'sensitive', 'secret'],
}),
};
export type EASEnvironmentVariableScopeFlagValue = 'project' | 'account';
export const EASEnvironmentVariableScopeFlag = {
scope: Flags.enum<EASEnvironmentVariableScopeFlagValue>({
description: 'Scope for the variable',
options: ['project', 'account'],
default: 'project',
}),
};
export const EASNonInteractiveFlag = {
'non-interactive': Flags.boolean({
description: 'Run the command in non-interactive mode.',
@@ -79,14 +21,3 @@ export const EasJsonOnlyFlag = {
description: 'Enable JSON output, non-JSON messages will be printed to stderr.',
}),
};
export const EasUpdateEnvironmentFlag = {
environment: Flags.enum<EnvironmentVariableEnvironment | null>({
description:
'Environment to use for the server-side defined EAS environment variables during command execution.',
options: mapToLowercase(Object.values(EnvironmentVariableEnvironment)),
parse: upperCaseAsync,
required: false,
default: null,
}),
};
@@ -63,11 +63,7 @@ export default class FeatureGating {
}
public static overrideKeyForEachInTest(key: FeatureGateKey, enabled: boolean): void {
beforeEach(() => {
FeatureGateTestOverrides.setOverride(key, enabled);
});
afterEach(() => {
FeatureGateTestOverrides.removeOverride(key);
});
beforeEach(() => FeatureGateTestOverrides.setOverride(key, enabled));
afterEach(() => FeatureGateTestOverrides.removeOverride(key));
}
}
+2 -27
View File
@@ -1,10 +1,7 @@
import { Errors, Flags } from '@oclif/core';
import chalk from 'chalk';
import { Flags } from '@oclif/core';
import EasCommand from '../../commandUtils/EasCommand';
import Log from '../../log';
import { confirmAsync } from '../../prompts';
import { getActorDisplayName } from '../../user/User';
export default class AccountLogin extends EasCommand {
static override description = 'log in with your Expo account';
@@ -20,7 +17,6 @@ export default class AccountLogin extends EasCommand {
};
static override contextDefinition = {
...this.ContextOptions.MaybeLoggedIn,
...this.ContextOptions.SessionManagment,
};
@@ -29,28 +25,7 @@ export default class AccountLogin extends EasCommand {
flags: { sso },
} = await this.parse(AccountLogin);
const {
sessionManager,
maybeLoggedIn: { actor },
} = await this.getContextAsync(AccountLogin, { nonInteractive: false });
if (sessionManager.getAccessToken()) {
throw new Error(
'EXPO_TOKEN is set in your environment, and is being used for all EAS authentication. To use username/password authentication, unset EXPO_TOKEN in your environment and re-run the command.'
);
}
if (actor) {
Log.warn(`You are already logged in as ${chalk.bold(getActorDisplayName(actor))}.`);
const shouldContinue = await confirmAsync({
message: 'Do you want to continue?',
});
if (!shouldContinue) {
Errors.error('Aborted', { exit: 1 });
}
}
const { sessionManager } = await this.getContextAsync(AccountLogin, { nonInteractive: false });
await sessionManager.showLoginPromptAsync({ sso });
Log.log('Logged in');
}
@@ -16,13 +16,10 @@ export default class AccountView extends EasCommand {
async runAsync(): Promise<void> {
const {
maybeLoggedIn: { actor, authenticationInfo },
maybeLoggedIn: { actor },
} = await this.getContextAsync(AccountView, { nonInteractive: true });
if (actor) {
const loggedInAs = authenticationInfo.accessToken
? `${getActorDisplayName(actor)} (authenticated using EXPO_TOKEN)`
: getActorDisplayName(actor);
Log.log(chalk.green(loggedInAs));
Log.log(chalk.green(getActorDisplayName(actor)));
// personal account is included, only show if more accounts that personal account
// but do show personal account in list if there are more
+1 -1
View File
@@ -10,7 +10,7 @@ export default class AnalyticsView extends EasCommand {
async runAsync(): Promise<void> {
const { STATUS: status } = (await this.parse(AnalyticsView)).args;
if (status) {
await setAnalyticsEnabledAsync(status === 'on');
setAnalyticsEnabledAsync(status === 'on');
Log.withTick(`${status === 'on' ? 'Enabling' : 'Disabling'} analytics.`);
} else {
const analyticsEnabled = await getAnalyticsEnabledAsync();
@@ -25,7 +25,7 @@ export default class BranchCreate extends EasCommand {
};
static override contextDefinition = {
...this.ContextOptions.ProjectId,
...this.ContextOptions.ProjectConfig,
...this.ContextOptions.LoggedIn,
...this.ContextOptions.Vcs,
};
@@ -36,7 +36,7 @@ export default class BranchCreate extends EasCommand {
flags: { json: jsonFlag, 'non-interactive': nonInteractive },
} = await this.parse(BranchCreate);
const {
projectId,
privateProjectConfig: { projectId },
loggedIn: { graphqlClient },
vcsClient,
} = await this.getContextAsync(BranchCreate, {
@@ -79,7 +79,7 @@ export default class BranchDelete extends EasCommand {
static override description = 'delete a branch';
static override contextDefinition = {
...this.ContextOptions.ProjectId,
...this.ContextOptions.ProjectConfig,
...this.ContextOptions.LoggedIn,
};
@@ -108,7 +108,7 @@ export default class BranchDelete extends EasCommand {
}
const {
projectId,
privateProjectConfig: { projectId },
loggedIn: { graphqlClient },
} = await this.getContextAsync(BranchDelete, { nonInteractive });
const projectDisplayName = await getDisplayNameForProjectIdAsync(graphqlClient, projectId);
+2 -2
View File
@@ -13,14 +13,14 @@ export default class BranchList extends EasCommand {
};
static override contextDefinition = {
...this.ContextOptions.ProjectId,
...this.ContextOptions.ProjectConfig,
...this.ContextOptions.LoggedIn,
};
async runAsync(): Promise<void> {
const { flags } = await this.parse(BranchList);
const {
projectId,
privateProjectConfig: { projectId },
loggedIn: { graphqlClient },
} = await this.getContextAsync(BranchList, {
nonInteractive: flags['non-interactive'],
@@ -63,7 +63,7 @@ export default class BranchRename extends EasCommand {
};
static override contextDefinition = {
...this.ContextOptions.ProjectId,
...this.ContextOptions.ProjectConfig,
...this.ContextOptions.LoggedIn,
};
@@ -72,7 +72,7 @@ export default class BranchRename extends EasCommand {
flags: { json: jsonFlag, from: currentName, to: newName, 'non-interactive': nonInteractive },
} = await this.parse(BranchRename);
const {
projectId,
privateProjectConfig: { projectId },
loggedIn: { graphqlClient },
} = await this.getContextAsync(BranchRename, {
nonInteractive,
+2 -2
View File
@@ -27,7 +27,7 @@ export default class BranchView extends EasCommand {
};
static override contextDefinition = {
...this.ContextOptions.ProjectId,
...this.ContextOptions.ProjectConfig,
...this.ContextOptions.LoggedIn,
};
@@ -38,7 +38,7 @@ export default class BranchView extends EasCommand {
} = await this.parse(BranchView);
const { 'non-interactive': nonInteractive } = flags;
const {
projectId,
privateProjectConfig: { projectId },
loggedIn: { graphqlClient },
} = await this.getContextAsync(BranchView, {
nonInteractive,
@@ -39,7 +39,7 @@ async function cancelBuildAsync(
)
.toPromise()
);
return data.build.cancel;
return data.build!.cancel;
}
export async function selectBuildToCancelAsync(
@@ -110,7 +110,7 @@ export default class BuildCancel extends EasCommand {
};
static override contextDefinition = {
...this.ContextOptions.ProjectId,
...this.ContextOptions.ProjectConfig,
...this.ContextOptions.LoggedIn,
...this.ContextOptions.Vcs,
};
@@ -128,7 +128,7 @@ export default class BuildCancel extends EasCommand {
}
const {
projectId,
privateProjectConfig: { projectId },
loggedIn: { graphqlClient },
} = await this.getContextAsync(BuildCancel, {
nonInteractive,
@@ -38,7 +38,6 @@ export default class BuildConfigure extends EasCommand {
vcsClient,
} = await this.getContextAsync(BuildConfigure, {
nonInteractive: false,
withServerSideEnvironment: null,
});
Log.log(
@@ -33,7 +33,7 @@ async function deleteBuildAsync(
)
.toPromise()
);
return data.build.deleteBuild;
return data.build!.deleteBuild;
}
export async function selectBuildToDeleteAsync(
@@ -94,7 +94,7 @@ export default class BuildDelete extends EasCommand {
}),
};
static override contextDefinition = {
...this.ContextOptions.ProjectId,
...this.ContextOptions.ProjectConfig,
...this.ContextOptions.LoggedIn,
...this.ContextOptions.Vcs,
};
@@ -112,7 +112,7 @@ export default class BuildDelete extends EasCommand {
}
const {
projectId,
privateProjectConfig: { projectId },
loggedIn: { graphqlClient },
} = await this.getContextAsync(BuildDelete, { nonInteractive });
const displayName = await getDisplayNameForProjectIdAsync(graphqlClient, projectId);
@@ -142,7 +142,6 @@ export default class Build extends EasCommand {
vcsClient,
} = await this.getContextAsync(Build, {
nonInteractive: flags.nonInteractive,
withServerSideEnvironment: null,
});
await handleDeprecatedEasJsonAsync(projectDir, flags.nonInteractive);
@@ -79,7 +79,6 @@ export default class BuildInspect extends EasCommand {
vcsClient,
} = await this.getContextAsync(BuildInspect, {
nonInteractive: false,
withServerSideEnvironment: null,
});
const outputDirectory = path.resolve(process.cwd(), flags.output);
@@ -7,7 +7,6 @@ import EasCommand from '../../commandUtils/EasCommand';
import { RequestedPlatform } from '../../platform';
import { enableJsonOutput } from '../../utils/json';
import GitNoCommitClient from '../../vcs/clients/gitNoCommit';
import NoVcsClient from '../../vcs/clients/noVcs';
/**
* This command will be run on the EAS Build workers, when building
@@ -64,8 +63,7 @@ export default class BuildInternal extends EasCommand {
vcsClient,
} = await this.getContextAsync(BuildInternal, {
nonInteractive: true,
vcsClientOverride: process.env.EAS_NO_VCS ? new NoVcsClient() : new GitNoCommitClient(),
withServerSideEnvironment: null,
vcsClientOverride: new GitNoCommitClient(),
});
await handleDeprecatedEasJsonAsync(projectDir, flags.nonInteractive);
+2 -2
View File
@@ -72,7 +72,7 @@ export default class BuildList extends EasCommand {
};
static override contextDefinition = {
...this.ContextOptions.ProjectId,
...this.ContextOptions.ProjectConfig,
...this.ContextOptions.LoggedIn,
...this.ContextOptions.Vcs,
};
@@ -99,7 +99,7 @@ export default class BuildList extends EasCommand {
process.exit(1);
}
const {
projectId,
privateProjectConfig: { projectId },
loggedIn: { graphqlClient },
} = await this.getContextAsync(BuildList, {
nonInteractive,
+3 -17
View File
@@ -6,7 +6,6 @@ import chalk from 'chalk';
import { handleDeprecatedEasJsonAsync } from '.';
import { waitForBuildEndAsync } from '../../build/build';
import { evaluateConfigWithEnvVarsAsync } from '../../build/evaluateConfigWithEnvVarsAsync';
import { ensureIosCredentialsForBuildResignAsync } from '../../build/ios/credentials';
import { prepareCredentialsToResign } from '../../build/ios/prepareJob';
import { listAndSelectBuildOnAppAsync } from '../../build/queries';
@@ -22,7 +21,6 @@ import {
BuildStatus,
BuildWorkflow,
DistributionType,
EnvironmentVariableEnvironment,
IosJobOverridesInput,
ProjectArchiveSourceType,
StatuspageServiceName,
@@ -48,7 +46,6 @@ interface BuildResignFlags {
sourceProfile?: string;
maybeBuildId?: string;
wait: boolean;
environment?: EnvironmentVariableEnvironment;
}
interface RawBuildResignFlags {
json: boolean;
@@ -60,7 +57,6 @@ interface RawBuildResignFlags {
'source-profile': string | undefined;
wait: boolean;
id: string | undefined;
environment: EnvironmentVariableEnvironment | undefined;
}
export default class BuildResign extends EasCommand {
@@ -120,7 +116,6 @@ export default class BuildResign extends EasCommand {
vcsClient,
} = await this.getContextAsync(BuildResign, {
nonInteractive: flags.nonInteractive,
withServerSideEnvironment: null,
});
const maybeBuild = flags.maybeBuildId
@@ -145,15 +140,7 @@ export default class BuildResign extends EasCommand {
platform,
flags.targetProfile ?? 'production'
);
const { exp, projectId, env } = await evaluateConfigWithEnvVarsAsync({
buildProfile,
buildProfileName: flags.targetProfile ?? 'production',
graphqlClient,
getProjectConfig: getDynamicPrivateProjectConfigAsync,
opts: { env: buildProfile.env },
});
const { exp, projectId } = await getDynamicPrivateProjectConfigAsync({ env: buildProfile.env });
const account = await getOwnerAccountForProjectIdAsync(graphqlClient, projectId);
const build = await this.ensureBuildSelectedAsync(
{
@@ -174,7 +161,7 @@ export default class BuildResign extends EasCommand {
user: actor,
graphqlClient,
analytics,
env,
env: buildProfile.env,
easJsonCliConfig,
vcsClient,
});
@@ -194,7 +181,7 @@ export default class BuildResign extends EasCommand {
projectDir,
exp,
xcodeBuildContext,
env,
env: buildProfile.env,
vcsClient,
});
const credentialsResult = await ensureIosCredentialsForBuildResignAsync(
@@ -261,7 +248,6 @@ export default class BuildResign extends EasCommand {
targetProfile: flags['target-profile'],
maybeBuildId: flags.id,
wait: flags.wait,
environment: flags.environment,
};
}
+3 -2
View File
@@ -79,7 +79,8 @@ export default class Run extends EasCommand {
static override contextDefinition = {
...this.ContextOptions.LoggedIn,
...this.ContextOptions.ProjectId,
...this.ContextOptions.ProjectConfig,
...this.ContextOptions.ProjectDir,
...this.ContextOptions.Vcs,
};
@@ -89,7 +90,7 @@ export default class Run extends EasCommand {
const queryOptions = getPaginatedQueryOptions(flags);
const {
loggedIn: { graphqlClient },
projectId,
privateProjectConfig: { projectId },
} = await this.getContextAsync(Run, {
nonInteractive: false,
});
@@ -3,7 +3,6 @@ import { EasJsonAccessor } from '@expo/eas-json';
import { Flags } from '@oclif/core';
import chalk from 'chalk';
import { evaluateConfigWithEnvVarsAsync } from '../../../build/evaluateConfigWithEnvVarsAsync';
import EasCommand from '../../../commandUtils/EasCommand';
import { EasNonInteractiveAndJsonFlags } from '../../../commandUtils/flags';
import { AppVersionQuery } from '../../../graphql/queries/AppVersionQuery';
@@ -54,7 +53,6 @@ export default class BuildVersionGetView extends EasCommand {
vcsClient,
} = await this.getContextAsync(BuildVersionGetView, {
nonInteractive: true,
withServerSideEnvironment: null,
});
if (!flags.platform && flags['non-interactive']) {
@@ -76,12 +74,8 @@ export default class BuildVersionGetView extends EasCommand {
});
const results: { [key in Platform]?: string } = {};
for (const { profile, platform } of buildProfiles) {
const { exp, projectId, env } = await evaluateConfigWithEnvVarsAsync({
buildProfile: profile,
buildProfileName: flags.profile ?? 'production',
graphqlClient,
getProjectConfig: getDynamicPrivateProjectConfigAsync,
opts: { env: profile.env },
const { exp, projectId } = await getDynamicPrivateProjectConfigAsync({
env: profile.env,
});
validateAppConfigForRemoteVersionSource(exp, platform);
@@ -95,7 +89,6 @@ export default class BuildVersionGetView extends EasCommand {
platform,
vcsClient,
nonInteractive: flags['non-interactive'],
env,
});
const remoteVersions = await AppVersionQuery.latestVersionAsync(
graphqlClient,
@@ -4,7 +4,6 @@ import { EasJsonAccessor, EasJsonUtils } from '@expo/eas-json';
import { Flags } from '@oclif/core';
import chalk from 'chalk';
import { evaluateConfigWithEnvVarsAsync } from '../../../build/evaluateConfigWithEnvVarsAsync';
import EasCommand from '../../../commandUtils/EasCommand';
import { AppVersionMutation } from '../../../graphql/mutations/AppVersionMutation';
import { AppVersionQuery } from '../../../graphql/queries/AppVersionQuery';
@@ -54,7 +53,6 @@ export default class BuildVersionSetView extends EasCommand {
vcsClient,
} = await this.getContextAsync(BuildVersionSetView, {
nonInteractive: false,
withServerSideEnvironment: null,
});
const platform = await selectPlatformAsync(flags.platform);
@@ -66,13 +64,7 @@ export default class BuildVersionSetView extends EasCommand {
flags.profile ?? undefined
);
const { exp, projectId, env } = await evaluateConfigWithEnvVarsAsync({
buildProfile: profile,
buildProfileName: flags.profile ?? 'production',
graphqlClient,
getProjectConfig: getDynamicPrivateProjectConfigAsync,
opts: { env: profile.env },
});
const { exp, projectId } = await getDynamicPrivateProjectConfigAsync({ env: profile.env });
const displayName = await getDisplayNameForProjectIdAsync(graphqlClient, projectId);
validateAppConfigForRemoteVersionSource(exp, platform);
@@ -86,7 +78,6 @@ export default class BuildVersionSetView extends EasCommand {
platform,
vcsClient,
nonInteractive: false,
env,
});
const remoteVersions = await AppVersionQuery.latestVersionAsync(
graphqlClient,
@@ -5,7 +5,6 @@ import { Flags } from '@oclif/core';
import chalk from 'chalk';
import { updateNativeVersionsAsync as updateAndroidNativeVersionsAsync } from '../../../build/android/version';
import { evaluateConfigWithEnvVarsAsync } from '../../../build/evaluateConfigWithEnvVarsAsync';
import { updateNativeVersionsAsync as updateIosNativeVersionsAsync } from '../../../build/ios/version';
import EasCommand from '../../../commandUtils/EasCommand';
import { AppVersionQuery } from '../../../graphql/queries/AppVersionQuery';
@@ -73,7 +72,6 @@ export default class BuildVersionSyncView extends EasCommand {
vcsClient,
} = await this.getContextAsync(BuildVersionSyncView, {
nonInteractive: true,
withServerSideEnvironment: null,
});
const requestedPlatform = await selectRequestedPlatformAsync(flags.platform);
@@ -89,12 +87,8 @@ export default class BuildVersionSyncView extends EasCommand {
projectDir,
});
for (const profileInfo of buildProfiles) {
const { exp, projectId, env } = await evaluateConfigWithEnvVarsAsync({
buildProfile: profileInfo.profile,
buildProfileName: profileInfo.profileName,
graphqlClient,
getProjectConfig: getDynamicPrivateProjectConfigAsync,
opts: { env: profileInfo.profile.env },
const { exp, projectId } = await getDynamicPrivateProjectConfigAsync({
env: profileInfo.profile.env,
});
validateAppConfigForRemoteVersionSource(exp, profileInfo.platform);
@@ -109,7 +103,6 @@ export default class BuildVersionSyncView extends EasCommand {
platform: profileInfo.platform,
vcsClient,
nonInteractive: false,
env,
});
const remoteVersions = await AppVersionQuery.latestVersionAsync(
graphqlClient,
@@ -135,7 +128,7 @@ export default class BuildVersionSyncView extends EasCommand {
continue;
}
if (profileInfo.platform === Platform.ANDROID) {
await this.syncAndroidAsync({
this.syncAndroidAsync({
projectDir,
exp,
profile: profileInfo.profile as BuildProfile<Platform.ANDROID>,
@@ -144,7 +137,7 @@ export default class BuildVersionSyncView extends EasCommand {
vcsClient,
});
} else {
await this.syncIosAsync({
this.syncIosAsync({
projectDir,
exp,
profile: profileInfo.profile as BuildProfile<Platform.IOS>,
@@ -206,7 +199,7 @@ export default class BuildVersionSyncView extends EasCommand {
if (workflow === Workflow.GENERIC) {
const buildGradle = await getAppBuildGradleAsync(projectDir);
const isMultiFlavor =
buildGradle.android?.productFlavors ?? buildGradle.android?.flavorDimensions;
buildGradle.android?.productFlavors || buildGradle.android?.flavorDimensions;
if (isMultiFlavor) {
throw new Error(
"Versions in native code can't be automatically synced in multi-flavor Android projects. If you are using EAS Build with app version source set to remote, the correct values will be injected at the build time."
+2 -2
View File
@@ -18,7 +18,7 @@ export default class BuildView extends EasCommand {
};
static override contextDefinition = {
...this.ContextOptions.ProjectId,
...this.ContextOptions.ProjectConfig,
...this.ContextOptions.LoggedIn,
...this.ContextOptions.Vcs,
};
@@ -29,7 +29,7 @@ export default class BuildView extends EasCommand {
flags,
} = await this.parse(BuildView);
const {
projectId,
privateProjectConfig: { projectId },
loggedIn: { graphqlClient },
} = await this.getContextAsync(BuildView, {
nonInteractive: true,
@@ -23,7 +23,7 @@ export default class ChannelCreate extends EasCommand {
};
static override contextDefinition = {
...this.ContextOptions.ProjectId,
...this.ContextOptions.ProjectConfig,
...this.ContextOptions.LoggedIn,
};
@@ -33,7 +33,7 @@ export default class ChannelCreate extends EasCommand {
flags: { json: jsonFlag, 'non-interactive': nonInteractive },
} = await this.parse(ChannelCreate);
const {
projectId,
privateProjectConfig: { projectId },
loggedIn: { graphqlClient },
} = await this.getContextAsync(ChannelCreate, {
nonInteractive,
@@ -31,7 +31,7 @@ export default class ChannelDelete extends EasCommand {
};
static override contextDefinition = {
...this.ContextOptions.ProjectId,
...this.ContextOptions.ProjectConfig,
...this.ContextOptions.LoggedIn,
};
@@ -41,7 +41,7 @@ export default class ChannelDelete extends EasCommand {
flags: { json: jsonFlag, 'non-interactive': nonInteractive },
} = await this.parse(ChannelDelete);
const {
projectId,
privateProjectConfig: { projectId },
loggedIn: { graphqlClient },
} = await this.getContextAsync(ChannelDelete, {
nonInteractive,
@@ -74,7 +74,7 @@ export default class ChannelEdit extends EasCommand {
};
static override contextDefinition = {
...this.ContextOptions.ProjectId,
...this.ContextOptions.ProjectConfig,
...this.ContextOptions.LoggedIn,
};
@@ -84,7 +84,7 @@ export default class ChannelEdit extends EasCommand {
flags: { branch: branchFlag, json, 'non-interactive': nonInteractive },
} = await this.parse(ChannelEdit);
const {
projectId,
privateProjectConfig: { projectId },
loggedIn: { graphqlClient },
} = await this.getContextAsync(ChannelEdit, {
nonInteractive,
@@ -18,7 +18,7 @@ export default class ChannelList extends EasCommand {
};
static override contextDefinition = {
...this.ContextOptions.ProjectId,
...this.ContextOptions.ProjectConfig,
...this.ContextOptions.LoggedIn,
};
@@ -27,7 +27,7 @@ export default class ChannelList extends EasCommand {
const paginatedQueryOptions = getPaginatedQueryOptions(flags);
const { json: jsonFlag, 'non-interactive': nonInteractive } = flags;
const {
projectId,
privateProjectConfig: { projectId },
loggedIn: { graphqlClient },
} = await this.getContextAsync(ChannelList, {
nonInteractive,
@@ -1,113 +0,0 @@
import { Flags } from '@oclif/core';
import chalk from 'chalk';
import { print } from 'graphql';
import gql from 'graphql-tag';
import { selectChannelOnAppAsync } from '../../channel/queries';
import EasCommand from '../../commandUtils/EasCommand';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
import { EasNonInteractiveAndJsonFlags } from '../../commandUtils/flags';
import { withErrorHandlingAsync } from '../../graphql/client';
import {
PauseUpdateChannelMutation,
PauseUpdateChannelMutationVariables,
UpdateChannelBasicInfoFragment,
} from '../../graphql/generated';
import { ChannelQuery } from '../../graphql/queries/ChannelQuery';
import { UpdateChannelBasicInfoFragmentNode } from '../../graphql/types/UpdateChannelBasicInfo';
import Log from '../../log';
import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
export async function pauseUpdateChannelAsync(
graphqlClient: ExpoGraphqlClient,
{ channelId }: PauseUpdateChannelMutationVariables
): Promise<UpdateChannelBasicInfoFragment> {
const data = await withErrorHandlingAsync(
graphqlClient
.mutation<PauseUpdateChannelMutation, PauseUpdateChannelMutationVariables>(
gql`
mutation PauseUpdateChannel($channelId: ID!) {
updateChannel {
pauseUpdateChannel(channelId: $channelId) {
id
...UpdateChannelBasicInfoFragment
}
}
}
${print(UpdateChannelBasicInfoFragmentNode)}
`,
{ channelId }
)
.toPromise()
);
const channel = data.updateChannel.pauseUpdateChannel;
if (!channel) {
throw new Error(`Could not find a channel with id: ${channelId}`);
}
return channel;
}
export default class ChannelPause extends EasCommand {
static override description = 'pause a channel to stop it from sending updates';
static override args = [
{
name: 'name',
required: false,
description: 'Name of the channel to edit',
},
];
static override flags = {
branch: Flags.string({
description: 'Name of the branch to point to',
}),
...EasNonInteractiveAndJsonFlags,
};
static override contextDefinition = {
...this.ContextOptions.ProjectId,
...this.ContextOptions.LoggedIn,
};
async runAsync(): Promise<void> {
const {
args,
flags: { json, 'non-interactive': nonInteractive },
} = await this.parse(ChannelPause);
const {
projectId,
loggedIn: { graphqlClient },
} = await this.getContextAsync(ChannelPause, {
nonInteractive,
});
if (json) {
enableJsonOutput();
}
const existingChannel = args.name
? await ChannelQuery.viewUpdateChannelAsync(graphqlClient, {
appId: projectId,
channelName: args.name,
})
: await selectChannelOnAppAsync(graphqlClient, {
projectId,
selectionPromptTitle: 'Select a channel to edit',
paginatedQueryOptions: { json, nonInteractive, offset: 0 },
});
const channel = await pauseUpdateChannelAsync(graphqlClient, {
channelId: existingChannel.id,
});
if (json) {
printJsonOnlyOutput(channel);
} else {
Log.withTick(chalk`Channel {bold ${channel.name}} is now paused.\n`);
Log.addNewLineIfNone();
Log.log(
chalk`Users with builds on channel {bold ${channel.name}} will no longer receive updates.`
);
}
}
}
@@ -1,111 +0,0 @@
import { Flags } from '@oclif/core';
import chalk from 'chalk';
import { print } from 'graphql';
import gql from 'graphql-tag';
import { selectChannelOnAppAsync } from '../../channel/queries';
import EasCommand from '../../commandUtils/EasCommand';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
import { EasNonInteractiveAndJsonFlags } from '../../commandUtils/flags';
import { withErrorHandlingAsync } from '../../graphql/client';
import {
ResumeUpdateChannelMutation,
ResumeUpdateChannelMutationVariables,
UpdateChannelBasicInfoFragment,
} from '../../graphql/generated';
import { ChannelQuery } from '../../graphql/queries/ChannelQuery';
import { UpdateChannelBasicInfoFragmentNode } from '../../graphql/types/UpdateChannelBasicInfo';
import Log from '../../log';
import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
export async function resumeUpdateChannelAsync(
graphqlClient: ExpoGraphqlClient,
{ channelId }: ResumeUpdateChannelMutationVariables
): Promise<UpdateChannelBasicInfoFragment> {
const data = await withErrorHandlingAsync(
graphqlClient
.mutation<ResumeUpdateChannelMutation, ResumeUpdateChannelMutationVariables>(
gql`
mutation ResumeUpdateChannel($channelId: ID!) {
updateChannel {
resumeUpdateChannel(channelId: $channelId) {
id
...UpdateChannelBasicInfoFragment
}
}
}
${print(UpdateChannelBasicInfoFragmentNode)}
`,
{ channelId }
)
.toPromise()
);
const channel = data.updateChannel.resumeUpdateChannel;
if (!channel) {
throw new Error(`Could not find a channel with id: ${channelId}`);
}
return channel;
}
export default class ChannelResume extends EasCommand {
static override description = 'resume a channel to start sending updates';
static override args = [
{
name: 'name',
required: false,
description: 'Name of the channel to edit',
},
];
static override flags = {
branch: Flags.string({
description: 'Name of the branch to point to',
}),
...EasNonInteractiveAndJsonFlags,
};
static override contextDefinition = {
...this.ContextOptions.ProjectId,
...this.ContextOptions.LoggedIn,
};
async runAsync(): Promise<void> {
const {
args,
flags: { json, 'non-interactive': nonInteractive },
} = await this.parse(ChannelResume);
const {
projectId,
loggedIn: { graphqlClient },
} = await this.getContextAsync(ChannelResume, {
nonInteractive,
});
if (json) {
enableJsonOutput();
}
const existingChannel = args.name
? await ChannelQuery.viewUpdateChannelAsync(graphqlClient, {
appId: projectId,
channelName: args.name,
})
: await selectChannelOnAppAsync(graphqlClient, {
projectId,
selectionPromptTitle: 'Select a channel to edit',
paginatedQueryOptions: { json, nonInteractive, offset: 0 },
});
const channel = await resumeUpdateChannelAsync(graphqlClient, {
channelId: existingChannel.id,
});
if (json) {
printJsonOnlyOutput(channel);
} else {
Log.withTick(chalk`Channel {bold ${channel.name}} is now active.\n`);
Log.addNewLineIfNone();
Log.log(chalk`Users with builds on channel {bold ${channel.name}} will now receive updates.`);
}
}
}
@@ -138,7 +138,6 @@ export default class ChannelRollout extends EasCommand {
loggedIn: { graphqlClient },
} = await this.getContextAsync(ChannelRollout, {
nonInteractive: argsAndFlags.nonInteractive,
withServerSideEnvironment: null,
});
if (argsAndFlags.json) {
enableJsonOutput();
@@ -26,7 +26,7 @@ export default class ChannelView extends EasCommand {
};
static override contextDefinition = {
...this.ContextOptions.ProjectId,
...this.ContextOptions.ProjectConfig,
...this.ContextOptions.LoggedIn,
};
@@ -38,7 +38,7 @@ export default class ChannelView extends EasCommand {
const paginatedQueryOptions = getPaginatedQueryOptions(flags);
const { json: jsonFlag, 'non-interactive': nonInteractive } = flags;
const {
projectId,
privateProjectConfig: { projectId },
loggedIn: { graphqlClient },
} = await this.getContextAsync(ChannelView, {
nonInteractive,
+6 -19
View File
@@ -4,7 +4,6 @@ import { EasJsonAccessor, EasJsonUtils } from '@expo/eas-json';
import { Flags } from '@oclif/core';
import chalk from 'chalk';
import { evaluateConfigWithEnvVarsAsync } from '../build/evaluateConfigWithEnvVarsAsync';
import EasCommand from '../commandUtils/EasCommand';
import { EasNonInteractiveAndJsonFlags } from '../commandUtils/flags';
import { toAppPlatform } from '../graphql/types/AppPlatform';
@@ -34,7 +33,6 @@ export default class Config extends EasCommand {
static override contextDefinition = {
...this.ContextOptions.DynamicProjectConfig,
...this.ContextOptions.ProjectDir,
...this.ContextOptions.DynamicLoggedIn,
};
async runAsync(): Promise<void> {
@@ -42,16 +40,10 @@ export default class Config extends EasCommand {
if (flags.json) {
enableJsonOutput();
}
const {
platform: maybePlatform,
profile: maybeProfile,
'non-interactive': nonInteractive,
} = flags;
const { getDynamicPublicProjectConfigAsync, projectDir, getDynamicLoggedInAsync } =
await this.getContextAsync(Config, {
nonInteractive,
withServerSideEnvironment: null,
});
const { platform: maybePlatform, profile: maybeProfile } = flags;
const { getDynamicPublicProjectConfigAsync, projectDir } = await this.getContextAsync(Config, {
nonInteractive: false,
});
const accessor = EasJsonAccessor.fromProjectPath(projectDir);
const profileName =
@@ -88,13 +80,8 @@ export default class Config extends EasCommand {
Log.log(JSON.stringify(profile, null, 2));
}
} else {
const { graphqlClient } = await getDynamicLoggedInAsync();
const { exp: appConfig } = await evaluateConfigWithEnvVarsAsync({
buildProfile: profile,
buildProfileName: profileName,
graphqlClient,
getProjectConfig: getDynamicPublicProjectConfigAsync,
opts: { env: profile.env },
const { exp: appConfig } = await getDynamicPublicProjectConfigAsync({
env: profile.env,
});
if (flags.json) {
@@ -39,7 +39,6 @@ export default class InitializeBuildCredentials extends EasCommand {
vcsClient,
} = await this.getContextAsync(InitializeBuildCredentials, {
nonInteractive: false,
withServerSideEnvironment: null,
});
const platform = await selectPlatformAsync(flags.platform);
Loaded 100 of 359 files, more files were not shown because too many files have changed in this diff. Show more