mirror of
https://github.com/expo/eas-cli.git
synced 2026-11-14 17:50:32 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7fd0e1b3dc |
No files matched your search
@@ -1,11 +0,0 @@
|
||||
name: setup-mise
|
||||
description: Install tools via mise
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: jdx/mise-action@146a28175021df8ca24f8ee1828cc2a60f980bd5 # v3.5.1
|
||||
with:
|
||||
install: true
|
||||
cache: true
|
||||
experimental: true
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4
|
||||
|
||||
- uses: ./.github/actions/setup-mise
|
||||
- uses: volta-cli/action@5c175f92dea6f48441c436471e6479dbc192e194 # v4
|
||||
|
||||
- uses: ./.github/internal-actions/setup-gcloud
|
||||
|
||||
|
||||
@@ -30,7 +30,9 @@ jobs:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/setup-mise
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
- run: yarn install --frozen-lockfile --check-files
|
||||
- run: yarn build
|
||||
- name: Ensure GraphQL schema and generated code is up-to-date
|
||||
@@ -75,7 +77,9 @@ jobs:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/setup-mise
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
- run: brew install python-setuptools
|
||||
env:
|
||||
HOMEBREW_NO_AUTO_UPDATE: 1
|
||||
@@ -118,7 +122,9 @@ jobs:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/setup-mise
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
- run: yarn install --frozen-lockfile --check-files
|
||||
- run: sudo apt-get install nsis
|
||||
- run: yarn build
|
||||
@@ -158,7 +164,11 @@ jobs:
|
||||
id-token: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/setup-mise
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
registry-url: 'https://registry.npmjs.org/'
|
||||
scope: 'expo'
|
||||
node-version: 22
|
||||
- name: Install dependencies
|
||||
run: yarn install --frozen-lockfile --check-files
|
||||
- name: Build
|
||||
@@ -189,7 +199,9 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.EXPO_BOT_PAT }}
|
||||
- uses: ./.github/actions/setup-mise
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
- name: Install dependencies
|
||||
working-directory: ./scripts
|
||||
run: yarn install --frozen-lockfile --check-files
|
||||
|
||||
@@ -10,7 +10,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: ./.github/actions/setup-mise
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 20
|
||||
- uses: preactjs/compressed-size-action@v2
|
||||
with:
|
||||
build-script: 'build:tarballs:linux'
|
||||
|
||||
@@ -18,8 +18,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup tools
|
||||
uses: ./.github/actions/setup-mise
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 22
|
||||
- run: yarn install --frozen-lockfile
|
||||
- run: yarn verify-graphql-code
|
||||
working-directory: packages/eas-cli
|
||||
@@ -22,7 +22,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup tools
|
||||
uses: ./.github/actions/setup-mise
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 20
|
||||
- run: yarn install --frozen-lockfile --check-files
|
||||
- run: yarn typecheck
|
||||
@@ -31,26 +31,12 @@ jobs:
|
||||
- run: |
|
||||
git config --global user.email "[email protected]"
|
||||
git config --global user.name "Test"
|
||||
- name: Fetch base commit for PR diffing
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
# Lerna needs the base commit to compute affected packages.
|
||||
run: git fetch --no-tags --depth=1 origin ${{ github.event.pull_request.base.sha }}
|
||||
- name: Run tests (affected)
|
||||
# PRs: only run tests for changed packages + dependents.
|
||||
if: ${{ !matrix.coverage && github.event_name == 'pull_request' }}
|
||||
run: yarn lerna run test --since ${{ github.event.pull_request.base.sha }} --include-dependents
|
||||
- run: yarn test
|
||||
if: ${{ !matrix.coverage }}
|
||||
env:
|
||||
NODE_OPTIONS: --max-old-space-size=8192
|
||||
- name: Run tests (all)
|
||||
# Pushes to main: run all package tests.
|
||||
if: ${{ !matrix.coverage && github.event_name == 'push' }}
|
||||
run: yarn lerna run test
|
||||
env:
|
||||
NODE_OPTIONS: --max-old-space-size=8192
|
||||
- name: Run tests (coverage)
|
||||
# Coverage on PRs and main; per-package reports are uploaded to Codecov.
|
||||
- run: yarn test --coverage
|
||||
if: ${{ matrix.coverage }}
|
||||
run: yarn lerna run test -- -- --coverage
|
||||
env:
|
||||
# Oclif seems to cause OOM errors when testing with coverage enabled.
|
||||
# Remove this whenever we solved those OOM errors.
|
||||
|
||||
@@ -27,7 +27,9 @@ jobs:
|
||||
ref: main
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.EXPO_BOT_PAT }}
|
||||
- uses: ./.github/actions/setup-mise
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
- run: |
|
||||
# Lerna will not detect changes correctly without having all tags
|
||||
git fetch --depth=1 origin +refs/tags/*:refs/tags/*
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
name: Open a PR bumping eas-build modules
|
||||
|
||||
on: workflow_dispatch
|
||||
|
||||
jobs:
|
||||
open-pr:
|
||||
name: Open a PR bumping eas-build modules
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: main
|
||||
token: ${{ secrets.EXPO_BOT_PAT }}
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Configure git
|
||||
run: |
|
||||
git config --global user.email "[email protected]"
|
||||
git config --global user.name "Expo Bot"
|
||||
|
||||
- name: Upgrade eas-build modules
|
||||
run: |
|
||||
for DIR in packages/eas-cli packages/eas-json; do
|
||||
pushd $DIR >/dev/null 2>&1
|
||||
# packages are ordered according to output of `lerna list --toposort`
|
||||
# https://github.com/expo/turtle-v2/pull/568
|
||||
for PACKAGE in "@expo/downloader" "@expo/eas-build-job" "@expo/logger" "@expo/template-file" "@expo/steps" "@expo/turtle-spawn" "@expo/build-tools"; do
|
||||
if grep -q $PACKAGE package.json; then
|
||||
echo "[$DIR] yarn --exact add $PACKAGE"
|
||||
yarn add --exact $PACKAGE
|
||||
fi
|
||||
done
|
||||
popd >/dev/null 2>&1
|
||||
done
|
||||
|
||||
- name: Set a branch name
|
||||
id: bump-branch-name
|
||||
run: |
|
||||
HASH="$(echo $RANDOM | md5sum | head -c 10)"
|
||||
BRANCH_NAME="@expo-bot/eas-build-bump-$HASH"
|
||||
|
||||
echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Create a branch, commit, and push
|
||||
run: |
|
||||
BRANCH_NAME="${{ steps.bump-branch-name.outputs.BRANCH_NAME }}"
|
||||
|
||||
git checkout -b $BRANCH_NAME
|
||||
git add .
|
||||
git commit -m "Upgrade eas-build dependencies"
|
||||
git push origin $BRANCH_NAME
|
||||
|
||||
- name: Open a PR to main
|
||||
uses: repo-sync/pull-request@v2
|
||||
id: open-pr
|
||||
with:
|
||||
source_branch: '${{ steps.bump-branch-name.outputs.BRANCH_NAME }}'
|
||||
destination_branch: 'main'
|
||||
pr_title: 'Upgrade eas-build dependencies'
|
||||
pr_body: ':arrow_up: Upgrades [`eas-build`](https://github.com/expo/eas-build) dependencies.'
|
||||
pr_reviewer: 'sjchmiela'
|
||||
github_token: ${{ secrets.EXPO_BOT_PAT }}
|
||||
|
||||
- uses: actions/github-script@v3
|
||||
with:
|
||||
github-token: ${{ secrets.EXPO_BOT_PAT }}
|
||||
script: |
|
||||
github.issues.createComment({
|
||||
issue_number: ${{ steps.open-pr.outputs.pr_number }},
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: "/changelog-entry chore Upgrade [`eas-build`](https://github.com/expo/eas-build) dependencies."
|
||||
})
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4
|
||||
|
||||
- uses: ./.github/actions/setup-mise
|
||||
- uses: volta-cli/action@5c175f92dea6f48441c436471e6479dbc192e194 # v4
|
||||
|
||||
- name: Create test app
|
||||
run: npx -y create-expo-app@latest ${{ runner.temp }}/test-app --template tabs
|
||||
|
||||
@@ -3,35 +3,88 @@ name: worker
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- "packages/worker/**"
|
||||
- "packages/build-tools/**"
|
||||
- "packages/eas-build-job/**"
|
||||
- "packages/steps/**"
|
||||
- "packages/logger/**"
|
||||
- "packages/downloader/**"
|
||||
- "packages/template-file/**"
|
||||
- "packages/turtle-spawn/**"
|
||||
- .github/workflows/worker.yml
|
||||
- .github/workflows/build-and-deploy-worker.yml
|
||||
- yarn.lock
|
||||
pull_request:
|
||||
|
||||
concurrency:
|
||||
group: worker-${{ github.ref }}-${{ github.event_name }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
run_worker: ${{ steps.changes.outputs.run_worker }}
|
||||
steps:
|
||||
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: volta-cli/action@5c175f92dea6f48441c436471e6479dbc192e194 # v4
|
||||
|
||||
- run: yarn install --frozen-lockfile --check-files
|
||||
|
||||
- id: changes
|
||||
name: Determine worker dependency changes
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
|
||||
BASE_SHA="${{ github.event.pull_request.base.sha }}"
|
||||
else
|
||||
BASE_SHA="${{ github.event.before }}"
|
||||
fi
|
||||
|
||||
if git cat-file -e "$BASE_SHA^{commit}" 2>/dev/null; then
|
||||
CHANGED_FILES="$(git diff --name-only "$BASE_SHA" "${{ github.sha }}")"
|
||||
else
|
||||
CHANGED_FILES="$(git diff --name-only --root "${{ github.sha }}")"
|
||||
fi
|
||||
|
||||
ROOT_DIR="$(git rev-parse --show-toplevel)"
|
||||
DEP_DIRS="$(yarn --silent lerna list --include-dependencies --scope @expo/worker --parsable)"
|
||||
RELEVANT_PREFIXES=(
|
||||
"packages/worker/"
|
||||
".github/workflows/worker.yml"
|
||||
".github/workflows/build-and-deploy-worker.yml"
|
||||
)
|
||||
|
||||
while IFS= read -r dir; do
|
||||
[[ -z "$dir" ]] && continue
|
||||
# Lerna may emit absolute paths; normalize to repo-relative for git diff matching.
|
||||
if [[ "$dir" == "$ROOT_DIR"* ]]; then
|
||||
dir="${dir#"$ROOT_DIR"/}"
|
||||
else
|
||||
# Some environments emit paths like ./packages/...
|
||||
dir="${dir#./}"
|
||||
fi
|
||||
RELEVANT_PREFIXES+=("${dir}/")
|
||||
done <<< "$DEP_DIRS"
|
||||
|
||||
RUN_WORKER=false
|
||||
while IFS= read -r file; do
|
||||
for prefix in "${RELEVANT_PREFIXES[@]}"; do
|
||||
if [[ "$file" == "$prefix"* || "$file" == "$prefix" ]]; then
|
||||
RUN_WORKER=true
|
||||
break 2
|
||||
fi
|
||||
done
|
||||
done <<< "$CHANGED_FILES"
|
||||
|
||||
echo "run_worker=$RUN_WORKER" >> "$GITHUB_OUTPUT"
|
||||
|
||||
worker-checks:
|
||||
if: needs.changes.outputs.run_worker == 'true'
|
||||
needs:
|
||||
- changes
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4
|
||||
|
||||
- uses: ./.github/actions/setup-mise
|
||||
- uses: volta-cli/action@5c175f92dea6f48441c436471e6479dbc192e194 # v4
|
||||
|
||||
- run: yarn install --frozen-lockfile --check-files
|
||||
|
||||
- run: yarn typecheck
|
||||
|
||||
- name: Run unit tests
|
||||
working-directory: packages/worker
|
||||
run: yarn test:unit
|
||||
@@ -41,7 +94,9 @@ jobs:
|
||||
run: yarn test:integration
|
||||
|
||||
worker-build:
|
||||
if: needs.changes.outputs.run_worker == 'true'
|
||||
needs:
|
||||
- changes
|
||||
- worker-checks
|
||||
uses: ./.github/workflows/build-and-deploy-worker.yml
|
||||
secrets: inherit
|
||||
@@ -49,16 +104,18 @@ jobs:
|
||||
environment: ${{ github.ref == 'refs/heads/main' && 'staging' || '' }}
|
||||
|
||||
system-tests-staging:
|
||||
if: github.ref == 'refs/heads/main' && !failure() && !cancelled()
|
||||
if: github.ref == 'refs/heads/main' && !failure() && !cancelled() && needs.changes.outputs.run_worker == 'true'
|
||||
needs:
|
||||
- changes
|
||||
- worker-build
|
||||
- worker-checks
|
||||
uses: ./.github/workflows/worker-system-tests.yml
|
||||
secrets: inherit
|
||||
|
||||
deploy-worker-production:
|
||||
if: github.ref == 'refs/heads/main' && !failure() && !cancelled()
|
||||
if: github.ref == 'refs/heads/main' && !failure() && !cancelled() && needs.changes.outputs.run_worker == 'true'
|
||||
needs:
|
||||
- changes
|
||||
- system-tests-staging
|
||||
uses: ./.github/workflows/build-and-deploy-worker.yml
|
||||
secrets: inherit
|
||||
@@ -68,8 +125,9 @@ jobs:
|
||||
notify-slack:
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- changes
|
||||
- deploy-worker-production
|
||||
if: github.ref == 'refs/heads/main' && always() && !cancelled()
|
||||
if: github.ref == 'refs/heads/main' && always() && !cancelled() && needs.changes.outputs.run_worker == 'true'
|
||||
steps:
|
||||
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4
|
||||
|
||||
|
||||
@@ -10,23 +10,14 @@ This is the log of notable changes to EAS CLI and related packages.
|
||||
|
||||
### 🎉 New features
|
||||
|
||||
|
||||
- Hide progress bar in build credits warning when usage reaches 100%. ([#3371](https://github.com/expo/eas-cli/pull/3371) by [@mackenco](https://github.com/mackenco))
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
- Fix `--non-interactive` mode prompting for git initialization. Now auto-initializes git with an initial commit when needed. Set `EAS_NO_VCS=1` to skip. ([#3387](https://github.com/expo/eas-cli/pull/3387) by [@evanbacon](https://github.com/evanbacon))
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Upgrade `tar` to v7. ([#3327](https://github.com/expo/eas-cli/pull/3327) by [@KarolRzeminski](https://github.com/KarolRzeminski))
|
||||
|
||||
## [16.32.0](https://github.com/expo/eas-cli/releases/tag/v16.32.0) - 2026-01-30
|
||||
|
||||
### 🎉 New features
|
||||
|
||||
- Add `--browser` flag to `eas login` for browser-based authentication. ([#3312](https://github.com/expo/eas-cli/pull/3312) by [@byronkarlen](https://github.com/byronkarlen))
|
||||
- List available options in non-interactive mode errors instead of generic "unable to select" messages, making CLI usable by agents and scripts. ([#3359](https://github.com/expo/eas-cli/pull/3359) by [@EvanBacon](https://github.com/EvanBacon))
|
||||
- Hidden beta version of new `eas account:usage` command for viewing account usage and billing estimates. ([#3334](https://github.com/expo/eas-cli/pull/3334) by [@douglowder](https://github.com/douglowder), [@EvanBacon](https://github.com/EvanBacon))
|
||||
- Add `--no-bytecode` and `--source-maps [mode]` flags to `eas update`. ([#3339](https://github.com/expo/eas-cli/pull/3339) by [@brentvatne](https://github.com/brentvatne))
|
||||
- Add App Clip bundle identifier registration support for multi-target iOS builds. ([#3300](https://github.com/expo/eas-cli/pull/3300) by [@evanbacon](https://github.com/evanbacon))
|
||||
|
||||
@@ -106,17 +106,14 @@ yarn start-allow-unused
|
||||
### Testing
|
||||
|
||||
```bash
|
||||
yarn lerna run test # Run all tests across packages
|
||||
yarn lerna run test -- --watch # Watch mode across packages (heavier)
|
||||
#
|
||||
# If you use `yarn test`, remember to pass args through two separators:
|
||||
# yarn test -- -- --watch
|
||||
yarn test # Run all tests across packages (Jest multi-project)
|
||||
yarn test --watch # Run tests in watch mode
|
||||
|
||||
# Run tests for a specific package
|
||||
# Run tests for specific package
|
||||
cd packages/eas-cli && yarn test
|
||||
cd packages/eas-json && yarn test
|
||||
cd packages/worker && yarn test
|
||||
cd packages/build-tools && yarn test
|
||||
cd packages/build-tools && yarn jest-unit
|
||||
cd packages/steps && yarn test
|
||||
```
|
||||
|
||||
@@ -246,8 +243,8 @@ Most packages depend on `@expo/eas-build-job` as the source of truth for types.
|
||||
|
||||
## Testing Architecture
|
||||
|
||||
- **Framework**: Jest with per-package configuration
|
||||
- **Shared base config**: `jest/jest.shared.config.ts`
|
||||
- **Framework**: Jest with multi-project configuration
|
||||
- **Root config**: `jest.config.ts` (combines eas-cli, eas-json, worker)
|
||||
- **Test locations**: `__tests__/` directories alongside source files
|
||||
- **Mocking**:
|
||||
- File system: `memfs`
|
||||
@@ -257,9 +254,9 @@ Most packages depend on `@expo/eas-build-job` as the source of truth for types.
|
||||
Run a single test file:
|
||||
|
||||
```bash
|
||||
cd packages/eas-cli && yarn test <path-to-test-file>
|
||||
yarn test <path-to-test-file>
|
||||
# Example:
|
||||
cd packages/eas-cli && yarn test src/project/__tests__/projectUtils-test.ts
|
||||
yarn test packages/eas-cli/src/project/__tests__/projectUtils-test.ts
|
||||
```
|
||||
|
||||
## Common Development Scenarios
|
||||
@@ -354,6 +351,6 @@ See `LICENSE` (MIT) and `LICENSE-BUSL` (BUSL-1.1) for details.
|
||||
|
||||
## Important Notes
|
||||
|
||||
- **Node Version**: Requires Node.js (managed via Mise)
|
||||
- **Node Version**: Requires Node.js >= 18.0.0 (managed via Volta)
|
||||
- **Package Manager**: Uses Yarn 1.22.21
|
||||
- **Compilation Target**: CommonJS with Node resolution
|
||||
+1
-1
@@ -69,7 +69,7 @@ See [`CLAUDE.md`](./CLAUDE.md) for how to set up your environment when making ch
|
||||
|
||||
## Testing
|
||||
|
||||
From the repository root, run `yarn lerna run test`. For a single package, run `yarn test` in that package directory.
|
||||
Run `yarn test` either in the repository root or in a package directory that you're working on.
|
||||
|
||||
## Releasing
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import type { Config } from 'jest';
|
||||
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import easCliConfig from './packages/eas-cli/jest.config';
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import easJsonConfig from './packages/eas-json/jest.config';
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import workerConfig from './packages/worker/jest.config.unit';
|
||||
|
||||
const config: Config = {
|
||||
projects: [easCliConfig, easJsonConfig, workerConfig],
|
||||
testPathIgnorePatterns: ['.*'],
|
||||
watchPlugins: ['jest-watch-typeahead/filename', 'jest-watch-typeahead/testname'],
|
||||
collectCoverageFrom: ['<rootDir>/src/**/*.{ts,tsx,js,jsx}'],
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -0,0 +1,9 @@
|
||||
import type { Config } from 'jest';
|
||||
|
||||
const config: Config = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
testRegex: '/__tests__/.*(test|spec)\\.[jt]sx?$',
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -1,8 +0,0 @@
|
||||
import type { Config } from '@jest/types';
|
||||
|
||||
const config: Config.InitialOptions = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
};
|
||||
|
||||
export default config;
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"npmClient": "yarn",
|
||||
"version": "17.0.0",
|
||||
"version": "16.32.0",
|
||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json"
|
||||
}
|
||||
+5
-1
@@ -16,7 +16,7 @@
|
||||
"lint": "eslint .",
|
||||
"lint-changelog": "./scripts/bin/run lint-changelog",
|
||||
"release": "lerna run rebuild && ./scripts/bin/run release",
|
||||
"test": "lerna run test",
|
||||
"test": "jest",
|
||||
"clean": "lerna run clean && rm -rf node_modules coverage"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -33,5 +33,9 @@
|
||||
"prettier": "3.1.1",
|
||||
"ts-jest": "29.1.1",
|
||||
"typescript": "5.5.4"
|
||||
},
|
||||
"volta": {
|
||||
"node": "20.19.4",
|
||||
"yarn": "1.22.21"
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
import type { Config } from '@jest/types';
|
||||
import type { Config } from 'jest';
|
||||
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import baseConfig from '../../../jest/jest.shared.config';
|
||||
|
||||
const config: Config.InitialOptions = {
|
||||
...baseConfig,
|
||||
const config: Config = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
rootDir: '../src',
|
||||
testMatch: ['**/__integration-tests__/*.test.ts'],
|
||||
clearMocks: true,
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import type { Config } from '@jest/types';
|
||||
import type { Config } from 'jest';
|
||||
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import baseConfig from '../../../jest/jest.shared.config';
|
||||
|
||||
const config: Config.InitialOptions = {
|
||||
...baseConfig,
|
||||
const config: Config = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
rootDir: '../src',
|
||||
testMatch: [
|
||||
'**/__tests__/*.test.ts',
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"url": "https://github.com/expo/eas-cli.git",
|
||||
"directory": "packages/build-tools"
|
||||
},
|
||||
"version": "17.0.0",
|
||||
"version": "1.0.272",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
@@ -37,17 +37,17 @@
|
||||
"dependencies": {
|
||||
"@expo/config": "10.0.6",
|
||||
"@expo/config-plugins": "9.0.12",
|
||||
"@expo/downloader": "17.0.0",
|
||||
"@expo/eas-build-job": "17.0.0",
|
||||
"@expo/downloader": "1.0.260",
|
||||
"@expo/eas-build-job": "1.0.265",
|
||||
"@expo/env": "^0.4.0",
|
||||
"@expo/logger": "17.0.0",
|
||||
"@expo/logger": "1.0.260",
|
||||
"@expo/package-manager": "1.9.10",
|
||||
"@expo/plist": "^0.2.0",
|
||||
"@expo/results": "^1.0.0",
|
||||
"@expo/spawn-async": "1.7.2",
|
||||
"@expo/steps": "17.0.0",
|
||||
"@expo/template-file": "17.0.0",
|
||||
"@expo/turtle-spawn": "17.0.0",
|
||||
"@expo/steps": "1.0.271",
|
||||
"@expo/template-file": "1.0.260",
|
||||
"@expo/turtle-spawn": "1.0.260",
|
||||
"@expo/xcpretty": "^4.3.1",
|
||||
"@google-cloud/storage": "^7.11.2",
|
||||
"@urql/core": "^6.0.1",
|
||||
@@ -55,7 +55,6 @@
|
||||
"fs-extra": "^11.2.0",
|
||||
"gql.tada": "^1.8.13",
|
||||
"joi": "^17.13.1",
|
||||
"jose": "5.10.0",
|
||||
"lodash": "^4.17.21",
|
||||
"node-fetch": "^2.7.0",
|
||||
"node-forge": "^1.3.1",
|
||||
@@ -66,7 +65,7 @@
|
||||
"resolve-from": "^5.0.0",
|
||||
"retry": "^0.13.1",
|
||||
"semver": "^7.6.2",
|
||||
"tar": "7.5.7",
|
||||
"tar": "^7.4.3",
|
||||
"uuid": "9.0.1",
|
||||
"yaml": "^2.8.1",
|
||||
"zod": "^4.3.5"
|
||||
@@ -87,11 +86,14 @@
|
||||
"bunyan": "^1.8.15",
|
||||
"jest": "^29.7.0",
|
||||
"memfs": "^4.17.1",
|
||||
"nock": "13.4.0",
|
||||
"ts-jest": "^29.1.4",
|
||||
"ts-mockito": "^2.6.1",
|
||||
"tslib": "^2.6.3",
|
||||
"typescript": "^5.5.4",
|
||||
"uuid": "^9.0.1"
|
||||
},
|
||||
"volta": {
|
||||
"node": "20.14.0",
|
||||
"yarn": "1.22.21"
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,6 @@ import { createStartAndroidEmulatorBuildFunction } from './functions/startAndroi
|
||||
import { createStartCuttlefishDeviceBuildFunction } from './functions/startCuttlefishDevice';
|
||||
import { createStartIosSimulatorBuildFunction } from './functions/startIosSimulator';
|
||||
import { createUploadArtifactBuildFunction } from './functions/uploadArtifact';
|
||||
import { createUploadToAscBuildFunction } from './functions/uploadToAsc';
|
||||
import { createSetUpNpmrcBuildFunction } from './functions/useNpmToken';
|
||||
import { CustomBuildContext } from '../customBuildContext';
|
||||
|
||||
@@ -76,7 +75,6 @@ export function getEasFunctions(ctx: CustomBuildContext): BuildFunction[] {
|
||||
calculateEASUpdateRuntimeVersionFunction(),
|
||||
|
||||
createSubmissionEntityFunction(),
|
||||
createUploadToAscBuildFunction(),
|
||||
|
||||
createInternalEasMaestroTestFunction(ctx),
|
||||
];
|
||||
|
||||
@@ -57,12 +57,6 @@ export function createRepackBuildFunction(): BuildFunction {
|
||||
required: false,
|
||||
defaultValue: 'latest',
|
||||
}),
|
||||
BuildStepInput.createProvider({
|
||||
id: 'repack_package',
|
||||
allowedValueTypeName: BuildStepInputValueTypeName.STRING,
|
||||
required: false,
|
||||
defaultValue: '@expo/repack-app',
|
||||
}),
|
||||
],
|
||||
outputProviders: [
|
||||
BuildStepOutput.createProvider({
|
||||
@@ -99,13 +93,8 @@ export function createRepackBuildFunction(): BuildFunction {
|
||||
}
|
||||
: undefined;
|
||||
|
||||
stepsCtx.logger.info(
|
||||
`Using repack from: ${inputs.repack_package.value}@${inputs.repack_version.value}`
|
||||
);
|
||||
const repackApp = await installAndImportRepackAsync({
|
||||
packageName: inputs.repack_package.value as string,
|
||||
version: inputs.repack_version.value as string,
|
||||
});
|
||||
stepsCtx.logger.info(`Using repack tool version: ${inputs.repack_version.value}`);
|
||||
const repackApp = await installAndImportRepackAsync(inputs.repack_version.value as string);
|
||||
const { repackAppIosAsync, repackAppAndroidAsync } = repackApp;
|
||||
|
||||
stepsCtx.logger.info('Repacking the app...');
|
||||
@@ -171,19 +160,15 @@ export function createRepackBuildFunction(): BuildFunction {
|
||||
/**
|
||||
* Install `@expo/repack-app` in a sandbox directory and import it.
|
||||
*/
|
||||
async function installAndImportRepackAsync({
|
||||
packageName,
|
||||
version,
|
||||
}: {
|
||||
packageName: string;
|
||||
version: string;
|
||||
}): Promise<typeof import('@expo/repack-app')> {
|
||||
async function installAndImportRepackAsync(
|
||||
version: string = 'latest'
|
||||
): Promise<typeof import('@expo/repack-app')> {
|
||||
const sandbox = await fs.promises.mkdtemp(path.join(os.tmpdir(), `repack-package-root-`));
|
||||
await spawnAsync('yarn', ['add', `${packageName}@${version}`], {
|
||||
await spawnAsync('yarn', ['add', `@expo/repack-app@${version}`], {
|
||||
stdio: 'inherit',
|
||||
cwd: sandbox,
|
||||
});
|
||||
return require(resolveFrom(sandbox, packageName));
|
||||
return require(resolveFrom(sandbox, '@expo/repack-app'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -132,34 +132,7 @@ export function createStartCuttlefishDeviceBuildFunction(): BuildFunction {
|
||||
|
||||
logger.info('Listing adb devices...');
|
||||
await spawn('adb', ['devices'], { env, logger });
|
||||
|
||||
logger.info('Unlocking device...');
|
||||
const unlockDeadline = Date.now() + 10_000;
|
||||
let isUnlocked = false;
|
||||
while (Date.now() < unlockDeadline) {
|
||||
const dumpsysResult = await asyncResult(
|
||||
spawn('adb', ['shell', 'dumpsys', 'window'], { env })
|
||||
);
|
||||
if (dumpsysResult.ok) {
|
||||
const match = dumpsysResult.value.stdout.match(/mDreamingLockscreen=(true|false)/);
|
||||
if (match?.[1] === 'false') {
|
||||
isUnlocked = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
logger.warn(dumpsysResult.reason, 'Failed to query device lock state.');
|
||||
}
|
||||
|
||||
await spawn('adb', ['shell', 'input', 'keyevent', '82'], { env, logger });
|
||||
await sleepAsync(1_000);
|
||||
}
|
||||
|
||||
if (isUnlocked) {
|
||||
logger.info('Device unlocked, returning to home screen');
|
||||
await spawn('adb', ['shell', 'input', 'keyevent', '3'], { env, logger });
|
||||
} else {
|
||||
logger.warn('Timed out waiting for the device to unlock.');
|
||||
}
|
||||
await spawn('adb', ['shell', 'input', 'keyevent', '82'], { env, logger });
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -1,330 +0,0 @@
|
||||
import {
|
||||
BuildFunction,
|
||||
BuildStepInput,
|
||||
BuildStepInputValueTypeName,
|
||||
BuildStepOutput,
|
||||
} from '@expo/steps';
|
||||
import fs from 'fs-extra';
|
||||
import * as jose from 'jose';
|
||||
import fetch from 'node-fetch';
|
||||
import path from 'node:path';
|
||||
import { setTimeout } from 'node:timers/promises';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { AscApiClient, AscApiClientPostApi } from '../utils/ios/AscApiClient';
|
||||
|
||||
export function createUploadToAscBuildFunction(): BuildFunction {
|
||||
return new BuildFunction({
|
||||
namespace: 'eas',
|
||||
id: 'upload_to_asc',
|
||||
name: 'Upload to App Store Connect',
|
||||
__metricsId: 'eas/upload_to_asc',
|
||||
inputProviders: [
|
||||
BuildStepInput.createProvider({
|
||||
id: 'ipa_path',
|
||||
required: true,
|
||||
allowedValueTypeName: BuildStepInputValueTypeName.STRING,
|
||||
}),
|
||||
BuildStepInput.createProvider({
|
||||
id: 'asc_api_key_path',
|
||||
required: true,
|
||||
allowedValueTypeName: BuildStepInputValueTypeName.STRING,
|
||||
}),
|
||||
BuildStepInput.createProvider({
|
||||
id: 'apple_app_identifier',
|
||||
required: true,
|
||||
allowedValueTypeName: BuildStepInputValueTypeName.STRING,
|
||||
}),
|
||||
BuildStepInput.createProvider({
|
||||
id: 'bundle_version',
|
||||
required: true,
|
||||
allowedValueTypeName: BuildStepInputValueTypeName.STRING,
|
||||
}),
|
||||
BuildStepInput.createProvider({
|
||||
id: 'bundle_short_version',
|
||||
required: true,
|
||||
allowedValueTypeName: BuildStepInputValueTypeName.STRING,
|
||||
}),
|
||||
BuildStepInput.createProvider({
|
||||
id: 'wait_for_processing',
|
||||
required: false,
|
||||
defaultValue: false,
|
||||
allowedValueTypeName: BuildStepInputValueTypeName.BOOLEAN,
|
||||
}),
|
||||
],
|
||||
outputProviders: [
|
||||
BuildStepOutput.createProvider({
|
||||
id: 'build_upload_id',
|
||||
required: false,
|
||||
}),
|
||||
BuildStepOutput.createProvider({
|
||||
id: 'build_upload_url',
|
||||
required: false,
|
||||
}),
|
||||
],
|
||||
fn: async (stepsCtx, { inputs, outputs }) => {
|
||||
const ipaPathInput = z.string().parse(inputs.ipa_path.value);
|
||||
const ascApiKeyPathInput = z.string().parse(inputs.asc_api_key_path.value);
|
||||
const appleAppIdentifier = z.string().parse(inputs.apple_app_identifier.value);
|
||||
const bundleVersion = z.string().parse(inputs.bundle_version.value);
|
||||
const bundleShortVersion = z.string().parse(inputs.bundle_short_version.value);
|
||||
const waitForProcessing = Boolean(inputs.wait_for_processing.value);
|
||||
|
||||
const ipaPath = path.resolve(stepsCtx.workingDirectory, ipaPathInput);
|
||||
if (!(await fs.pathExists(ipaPath))) {
|
||||
throw new Error(`IPA file not found: ${ipaPath}`);
|
||||
}
|
||||
const fileSize = (await fs.stat(ipaPath)).size;
|
||||
const fileName = path.basename(ipaPath);
|
||||
|
||||
const ascApiKeyPath = path.resolve(stepsCtx.workingDirectory, ascApiKeyPathInput);
|
||||
if (!(await fs.pathExists(ascApiKeyPath))) {
|
||||
throw new Error(`ASC API Key file not found: ${ascApiKeyPath}`);
|
||||
}
|
||||
|
||||
const ascApiKeyJson = await fs.readJson(ascApiKeyPath);
|
||||
const ascApiKey = z
|
||||
.object({
|
||||
issuer_id: z.string(),
|
||||
key_id: z.string(),
|
||||
key: z.string(),
|
||||
})
|
||||
.parse(ascApiKeyJson);
|
||||
|
||||
const privateKey = await jose.importPKCS8(ascApiKey.key, 'ES256');
|
||||
const token = await new jose.SignJWT({})
|
||||
.setProtectedHeader({ alg: 'ES256', kid: ascApiKey.key_id })
|
||||
.setIssuer(ascApiKey.issuer_id)
|
||||
.setAudience('appstoreconnect-v1')
|
||||
.setExpirationTime('20m')
|
||||
.sign(privateKey);
|
||||
|
||||
const client = new AscApiClient({ token, logger: stepsCtx.logger });
|
||||
|
||||
stepsCtx.logger.info('Reading App information...');
|
||||
const appResponse = await client.getAsync(
|
||||
'/v1/apps/:id',
|
||||
{ 'fields[apps]': ['bundleId', 'name'] },
|
||||
{ id: appleAppIdentifier }
|
||||
);
|
||||
stepsCtx.logger.info(
|
||||
`Uploading Build to "${appResponse.data.attributes.name}" (${appResponse.data.attributes.bundleId})...`
|
||||
);
|
||||
|
||||
stepsCtx.logger.info('Creating Build Upload...');
|
||||
const buildUploadResponse = await client.postAsync('/v1/buildUploads', {
|
||||
data: {
|
||||
type: 'buildUploads',
|
||||
attributes: {
|
||||
platform: 'IOS',
|
||||
cfBundleShortVersionString: bundleShortVersion,
|
||||
cfBundleVersion: bundleVersion,
|
||||
},
|
||||
relationships: {
|
||||
app: {
|
||||
data: {
|
||||
type: 'apps',
|
||||
id: appleAppIdentifier,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const buildUploadId = buildUploadResponse.data.id;
|
||||
const buildUploadUrl = `https://appstoreconnect.apple.com/apps/${appleAppIdentifier}/testflight/ios/${buildUploadId}`;
|
||||
outputs.build_upload_id.set(buildUploadId);
|
||||
outputs.build_upload_url.set(buildUploadUrl);
|
||||
|
||||
stepsCtx.logger.info(
|
||||
`Build Upload initialized (ID: ${buildUploadId}). Preparing IPA upload...`
|
||||
);
|
||||
const buildFileResponse = await client.postAsync('/v1/buildUploadFiles', {
|
||||
data: {
|
||||
type: 'buildUploadFiles',
|
||||
attributes: {
|
||||
assetType: 'ASSET',
|
||||
fileName,
|
||||
fileSize,
|
||||
uti: 'com.apple.ipa',
|
||||
},
|
||||
relationships: {
|
||||
buildUpload: {
|
||||
data: {
|
||||
type: 'buildUploads',
|
||||
id: buildUploadId,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
stepsCtx.logger.info(
|
||||
`IPA Upload initialized (ID: ${buildFileResponse.data.id}). Uploading IPA...`
|
||||
);
|
||||
await uploadChunksAsync({
|
||||
uploadOperations: buildFileResponse.data.attributes.uploadOperations,
|
||||
ipaPath,
|
||||
logger: stepsCtx.logger,
|
||||
});
|
||||
|
||||
stepsCtx.logger.info('Committing upload...');
|
||||
await client.patchAsync(
|
||||
`/v1/buildUploadFiles/:id`,
|
||||
{
|
||||
data: {
|
||||
type: 'buildUploadFiles',
|
||||
id: buildFileResponse.data.id,
|
||||
attributes: {
|
||||
uploaded: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: buildFileResponse.data.id,
|
||||
}
|
||||
);
|
||||
|
||||
stepsCtx.logger.info('Checking upload file status...');
|
||||
const waitingForFileStartedAt = Date.now();
|
||||
while (Date.now() - waitingForFileStartedAt < 60 * 1000 /* 60 seconds */) {
|
||||
const {
|
||||
data: {
|
||||
attributes: { assetDeliveryState },
|
||||
},
|
||||
} = await client.getAsync(
|
||||
`/v1/buildUploadFiles/:id`,
|
||||
{ 'fields[buildUploadFiles]': ['assetDeliveryState'] },
|
||||
{ id: buildFileResponse.data.id }
|
||||
);
|
||||
|
||||
if (assetDeliveryState.state === 'AWAITING_UPLOAD') {
|
||||
stepsCtx.logger.info(
|
||||
`Waiting for file upload to complete processing... (state = ${assetDeliveryState.state})`
|
||||
);
|
||||
await setTimeout(2000);
|
||||
continue;
|
||||
}
|
||||
|
||||
const { errors = [], warnings = [] } = assetDeliveryState;
|
||||
if (warnings.length > 0) {
|
||||
stepsCtx.logger.warn(`Warnings:\n${itemizeMessages(warnings)}\n`);
|
||||
}
|
||||
if (errors.length > 0) {
|
||||
stepsCtx.logger.error(`Errors:\n${itemizeMessages(errors)}\n`);
|
||||
}
|
||||
|
||||
if (assetDeliveryState.state === 'FAILED') {
|
||||
throw new Error(`File upload (ID: ${buildFileResponse.data.id}) failed.`);
|
||||
} else if (
|
||||
assetDeliveryState.state === 'COMPLETE' ||
|
||||
assetDeliveryState.state === 'UPLOAD_COMPLETE'
|
||||
) {
|
||||
stepsCtx.logger.info(`File upload (ID: ${buildFileResponse.data.id}) completed!`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
stepsCtx.logger.info(`See your build in App Store Connect: ${buildUploadUrl}`);
|
||||
|
||||
if (!waitForProcessing) {
|
||||
stepsCtx.logger.info('Skipping waiting for processing.');
|
||||
return;
|
||||
}
|
||||
|
||||
stepsCtx.logger.info('Checking build upload status...');
|
||||
const waitingForBuildStartedAt = Date.now();
|
||||
while (Date.now() - waitingForBuildStartedAt < 10 * 60 * 1000 /* 10 minutes */) {
|
||||
const {
|
||||
data: {
|
||||
attributes: { state },
|
||||
},
|
||||
} = await client.getAsync(
|
||||
`/v1/buildUploads/:id`,
|
||||
{ 'fields[buildUploads]': ['state', 'build'], include: ['build'] },
|
||||
{ id: buildUploadId }
|
||||
);
|
||||
|
||||
if (state.state === 'AWAITING_UPLOAD' || state.state === 'PROCESSING') {
|
||||
stepsCtx.logger.info(`Waiting for build upload to complete... (status = ${state.state})`);
|
||||
await setTimeout(2000);
|
||||
continue;
|
||||
}
|
||||
|
||||
stepsCtx.logger.info('\n');
|
||||
|
||||
const { errors = [], warnings = [], infos = [] } = state;
|
||||
if (infos.length > 0) {
|
||||
stepsCtx.logger.info(`Infos:\n${itemizeMessages(infos)}\n`);
|
||||
}
|
||||
if (warnings.length > 0) {
|
||||
stepsCtx.logger.warn(`Warnings:\n${itemizeMessages(warnings)}\n`);
|
||||
}
|
||||
if (errors.length > 0) {
|
||||
stepsCtx.logger.error(`Errors:\n${itemizeMessages(errors)}\n`);
|
||||
}
|
||||
|
||||
if (state.state === 'FAILED') {
|
||||
throw new Error(`Build upload (ID: ${buildUploadId}) failed.`);
|
||||
} else if (state.state === 'COMPLETE') {
|
||||
stepsCtx.logger.info(`Build upload (ID: ${buildUploadId}) complete!`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function itemizeMessages(messages: { description: string; code: string }[]): string {
|
||||
return `- ${messages.map(m => `${m.description} (${m.code})`).join('\n- ')}`;
|
||||
}
|
||||
|
||||
async function uploadChunksAsync({
|
||||
uploadOperations,
|
||||
ipaPath,
|
||||
logger,
|
||||
}: {
|
||||
uploadOperations: AscApiClientPostApi['/v1/buildUploadFiles']['response']['data']['attributes']['uploadOperations'];
|
||||
ipaPath: string;
|
||||
logger: { info: (message: string) => void };
|
||||
}): Promise<void> {
|
||||
const fd = await fs.open(ipaPath, 'r');
|
||||
try {
|
||||
const promises = uploadOperations.map(async (op, index) => {
|
||||
logger.info(
|
||||
` Uploading chunk ${index + 1}/${uploadOperations.length} (offset: ${op.offset}, length: ${
|
||||
op.length
|
||||
})...`
|
||||
);
|
||||
|
||||
const buffer = new Uint8Array(op.length);
|
||||
await fs.read(fd, buffer, 0, op.length, op.offset);
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
'Content-Type': 'application/octet-stream',
|
||||
};
|
||||
|
||||
for (const { name, value } of op.requestHeaders) {
|
||||
headers[name] = value;
|
||||
}
|
||||
|
||||
const response = await fetch(op.url, {
|
||||
method: op.method,
|
||||
headers,
|
||||
body: buffer,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const text = await response.text();
|
||||
throw new Error(
|
||||
`Failed to upload chunk ${index + 1}: ${response.status} ${response.statusText}\n${text}`
|
||||
);
|
||||
}
|
||||
logger.info(` Chunk ${index + 1}/${uploadOperations.length} uploaded.`);
|
||||
});
|
||||
|
||||
await Promise.all(promises);
|
||||
} finally {
|
||||
await fs.close(fd);
|
||||
}
|
||||
}
|
||||
+2
-9
@@ -1,10 +1,4 @@
|
||||
import type { Config } from '@jest/types';
|
||||
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import baseConfig from '../../jest/jest.shared.config';
|
||||
|
||||
const config: Config.InitialOptions = {
|
||||
...baseConfig,
|
||||
module.exports = {
|
||||
preset: 'ts-jest/presets/default-esm',
|
||||
transform: {
|
||||
'^.+\\.tsx?$': [
|
||||
@@ -15,6 +9,7 @@ const config: Config.InitialOptions = {
|
||||
},
|
||||
],
|
||||
},
|
||||
testEnvironment: 'node',
|
||||
rootDir: 'src',
|
||||
testMatch: ['**/__tests__/*-test.ts'],
|
||||
coverageReporters: ['json', 'lcov'],
|
||||
@@ -26,5 +21,3 @@ const config: Config.InitialOptions = {
|
||||
clearMocks: true,
|
||||
setupFilesAfterEnv: ['<rootDir>/../jest/setup-tests.ts'],
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -5,7 +5,7 @@
|
||||
"url": "https://github.com/expo/eas-cli.git",
|
||||
"directory": "packages/create-eas-build-function"
|
||||
},
|
||||
"version": "17.0.0",
|
||||
"version": "1.0.271",
|
||||
"bin": {
|
||||
"create-eas-build-function": "./build/index.js"
|
||||
},
|
||||
@@ -34,7 +34,7 @@
|
||||
"clean": "rimraf ./build/ *.tsbuildinfo"
|
||||
},
|
||||
"dependencies": {
|
||||
"@expo/steps": "17.0.0"
|
||||
"@expo/steps": "1.0.271"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@expo/package-manager": "1.9.10",
|
||||
@@ -53,5 +53,9 @@
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"volta": {
|
||||
"node": "20.14.0",
|
||||
"yarn": "1.22.21"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
rootDir: 'src',
|
||||
testMatch: ['**/__tests__/*.test.ts'],
|
||||
clearMocks: true,
|
||||
setupFilesAfterEnv: ['<rootDir>/../jest/setup-tests.ts'],
|
||||
};
|
||||
@@ -1,14 +0,0 @@
|
||||
import type { Config } from '@jest/types';
|
||||
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import baseConfig from '../../jest/jest.shared.config';
|
||||
|
||||
const config: Config.InitialOptions = {
|
||||
...baseConfig,
|
||||
rootDir: 'src',
|
||||
testMatch: ['**/__tests__/*.test.ts'],
|
||||
clearMocks: true,
|
||||
setupFilesAfterEnv: ['<rootDir>/../jest/setup-tests.ts'],
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -5,7 +5,7 @@
|
||||
"url": "https://github.com/expo/eas-cli.git",
|
||||
"directory": "packages/downloader"
|
||||
},
|
||||
"version": "17.0.0",
|
||||
"version": "1.0.260",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
@@ -17,8 +17,8 @@
|
||||
"build": "tsc",
|
||||
"typecheck": "tsc",
|
||||
"prepack": "rm -rf dist && tsc -p tsconfig.build.json",
|
||||
"test": "jest --config jest.config.ts",
|
||||
"test:watch": "jest --config jest.config.ts --watch",
|
||||
"test": "jest --config jest.config.js",
|
||||
"test:watch": "jest --config jest.config.js --watch",
|
||||
"clean": "rm -rf node_modules dist coverage *.tsbuildinfo"
|
||||
},
|
||||
"author": "Expo <[email protected]>",
|
||||
@@ -35,5 +35,9 @@
|
||||
"jest": "^29.7.0",
|
||||
"ts-jest": "^29.1.4",
|
||||
"typescript": "^5.5.4"
|
||||
},
|
||||
"volta": {
|
||||
"node": "20.14.0",
|
||||
"yarn": "1.22.21"
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "eas-build-cache-provider",
|
||||
"description": "A build cache provider plugin for the Expo CLI",
|
||||
"version": "17.0.0",
|
||||
"version": "16.30.0",
|
||||
"author": "Expo <[email protected]>",
|
||||
"bugs": "https://github.com/expo/eas-cli/issues",
|
||||
"dependencies": {
|
||||
@@ -46,7 +46,7 @@
|
||||
"typecheck": "tsc",
|
||||
"prepack": "yarn rebuild",
|
||||
"rebuild": "rimraf build && yarn build",
|
||||
"test": "jest --passWithNoTests",
|
||||
"test": "jest",
|
||||
"clean": "rimraf build node_modules yarn-error.log *.tsbuildinfo"
|
||||
},
|
||||
"files": [
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
rootDir: 'src',
|
||||
testMatch: ['**/__tests__/*.test.ts'],
|
||||
clearMocks: true,
|
||||
setupFilesAfterEnv: ['<rootDir>/../jest/setup-tests.ts'],
|
||||
};
|
||||
@@ -1,14 +0,0 @@
|
||||
import type { Config } from '@jest/types';
|
||||
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import baseConfig from '../../jest/jest.shared.config';
|
||||
|
||||
const config: Config.InitialOptions = {
|
||||
...baseConfig,
|
||||
rootDir: 'src',
|
||||
testMatch: ['**/__tests__/*.test.ts'],
|
||||
clearMocks: true,
|
||||
setupFilesAfterEnv: ['<rootDir>/../jest/setup-tests.ts'],
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -5,7 +5,7 @@
|
||||
"url": "https://github.com/expo/eas-cli.git",
|
||||
"directory": "packages/eas-build-job"
|
||||
},
|
||||
"version": "17.0.0",
|
||||
"version": "1.0.265",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
@@ -17,8 +17,8 @@
|
||||
"build": "tsc",
|
||||
"typecheck": "tsc",
|
||||
"prepack": "rm -rf dist && tsc -p tsconfig.build.json",
|
||||
"test": "jest --config jest.config.ts",
|
||||
"test:watch": "jest --config jest.config.ts --watch",
|
||||
"test": "jest --config jest.config.js",
|
||||
"test:watch": "jest --config jest.config.js --watch",
|
||||
"clean": "rm -rf node_modules dist coverage *.tsbuildinfo"
|
||||
},
|
||||
"author": "Expo <[email protected]>",
|
||||
@@ -32,9 +32,13 @@
|
||||
"typescript": "^5.5.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@expo/logger": "17.0.0",
|
||||
"@expo/logger": "1.0.260",
|
||||
"joi": "^17.13.1",
|
||||
"semver": "^7.6.2",
|
||||
"zod": "^4.3.5"
|
||||
},
|
||||
"volta": {
|
||||
"node": "20.14.0",
|
||||
"yarn": "1.22.21"
|
||||
}
|
||||
}
|
||||
+88
-88
@@ -177,7 +177,7 @@ ALIASES
|
||||
$ eas login
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/account/login.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/account/login.ts)_
|
||||
|
||||
## `eas account:logout`
|
||||
|
||||
@@ -194,7 +194,7 @@ ALIASES
|
||||
$ eas logout
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/account/logout.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/account/logout.ts)_
|
||||
|
||||
## `eas account:usage [ACCOUNT_NAME]`
|
||||
|
||||
@@ -216,7 +216,7 @@ DESCRIPTION
|
||||
view account usage and billing for the current cycle
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/account/usage.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/account/usage.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/account/usage.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/account/usage.ts)_
|
||||
|
||||
## `eas account:view`
|
||||
|
||||
@@ -233,7 +233,7 @@ ALIASES
|
||||
$ eas whoami
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/account/view.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/account/view.ts)_
|
||||
|
||||
## `eas analytics [STATUS]`
|
||||
|
||||
@@ -247,7 +247,7 @@ DESCRIPTION
|
||||
display or change analytics settings
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/analytics.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/analytics.ts)_
|
||||
|
||||
## `eas autocomplete [SHELL]`
|
||||
|
||||
@@ -299,7 +299,7 @@ DESCRIPTION
|
||||
create a branch
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/branch/create.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/branch/create.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/branch/create.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/branch/create.ts)_
|
||||
|
||||
## `eas branch:delete [NAME]`
|
||||
|
||||
@@ -320,7 +320,7 @@ DESCRIPTION
|
||||
delete a branch
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/branch/delete.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/branch/delete.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/branch/delete.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/branch/delete.ts)_
|
||||
|
||||
## `eas branch:list`
|
||||
|
||||
@@ -340,7 +340,7 @@ DESCRIPTION
|
||||
list all branches
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/branch/list.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/branch/list.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/branch/list.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/branch/list.ts)_
|
||||
|
||||
## `eas branch:rename`
|
||||
|
||||
@@ -360,7 +360,7 @@ DESCRIPTION
|
||||
rename a branch
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/branch/rename.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/branch/rename.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/branch/rename.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/branch/rename.ts)_
|
||||
|
||||
## `eas branch:view [NAME]`
|
||||
|
||||
@@ -383,7 +383,7 @@ DESCRIPTION
|
||||
view a branch
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/branch/view.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/branch/view.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/branch/view.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/branch/view.ts)_
|
||||
|
||||
## `eas build`
|
||||
|
||||
@@ -424,7 +424,7 @@ DESCRIPTION
|
||||
start a build
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/build/index.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/build/index.ts)_
|
||||
|
||||
## `eas build:cancel [BUILD_ID]`
|
||||
|
||||
@@ -443,7 +443,7 @@ DESCRIPTION
|
||||
cancel a build
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/build/cancel.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/build/cancel.ts)_
|
||||
|
||||
## `eas build:configure`
|
||||
|
||||
@@ -460,7 +460,7 @@ DESCRIPTION
|
||||
configure the project to support EAS Build
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/build/configure.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/build/configure.ts)_
|
||||
|
||||
## `eas build:delete [BUILD_ID]`
|
||||
|
||||
@@ -479,7 +479,7 @@ DESCRIPTION
|
||||
delete a build
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/delete.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/build/delete.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/delete.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/build/delete.ts)_
|
||||
|
||||
## `eas build:dev`
|
||||
|
||||
@@ -499,7 +499,7 @@ DESCRIPTION
|
||||
run dev client simulator/emulator build with matching fingerprint or create a new one
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/dev.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/build/dev.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/dev.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/build/dev.ts)_
|
||||
|
||||
## `eas build:download`
|
||||
|
||||
@@ -520,7 +520,7 @@ DESCRIPTION
|
||||
download simulator/emulator builds for a given fingerprint hash
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/download.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/build/download.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/download.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/build/download.ts)_
|
||||
|
||||
## `eas build:inspect`
|
||||
|
||||
@@ -555,7 +555,7 @@ DESCRIPTION
|
||||
inspect the state of the project at specific build stages, useful for troubleshooting
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/inspect.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/build/inspect.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/inspect.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/build/inspect.ts)_
|
||||
|
||||
## `eas build:list`
|
||||
|
||||
@@ -607,7 +607,7 @@ DESCRIPTION
|
||||
list all builds for your project
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/build/list.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/build/list.ts)_
|
||||
|
||||
## `eas build:resign`
|
||||
|
||||
@@ -636,7 +636,7 @@ DESCRIPTION
|
||||
re-sign a build archive
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/resign.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/build/resign.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/resign.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/build/resign.ts)_
|
||||
|
||||
## `eas build:run`
|
||||
|
||||
@@ -662,7 +662,7 @@ DESCRIPTION
|
||||
run simulator/emulator builds from eas-cli
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/run.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/build/run.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/run.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/build/run.ts)_
|
||||
|
||||
## `eas build:submit`
|
||||
|
||||
@@ -716,7 +716,7 @@ DESCRIPTION
|
||||
get the latest version from EAS servers
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/version/get.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/build/version/get.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/version/get.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/build/version/get.ts)_
|
||||
|
||||
## `eas build:version:set`
|
||||
|
||||
@@ -735,7 +735,7 @@ DESCRIPTION
|
||||
update version of an app
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/version/set.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/build/version/set.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/version/set.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/build/version/set.ts)_
|
||||
|
||||
## `eas build:version:sync`
|
||||
|
||||
@@ -754,7 +754,7 @@ DESCRIPTION
|
||||
update a version in native code with a value stored on EAS servers
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/version/sync.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/build/version/sync.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/version/sync.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/build/version/sync.ts)_
|
||||
|
||||
## `eas build:view [BUILD_ID]`
|
||||
|
||||
@@ -771,7 +771,7 @@ DESCRIPTION
|
||||
view a build for your project
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/build/view.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/build/view.ts)_
|
||||
|
||||
## `eas channel:create [NAME]`
|
||||
|
||||
@@ -792,7 +792,7 @@ DESCRIPTION
|
||||
create a channel
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/channel/create.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/channel/create.ts)_
|
||||
|
||||
## `eas channel:delete [NAME]`
|
||||
|
||||
@@ -813,7 +813,7 @@ DESCRIPTION
|
||||
Delete a channel
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/channel/delete.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/channel/delete.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/channel/delete.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/channel/delete.ts)_
|
||||
|
||||
## `eas channel:edit [NAME]`
|
||||
|
||||
@@ -835,7 +835,7 @@ DESCRIPTION
|
||||
point a channel at a new branch
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/channel/edit.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/channel/edit.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/channel/edit.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/channel/edit.ts)_
|
||||
|
||||
## `eas channel:list`
|
||||
|
||||
@@ -855,7 +855,7 @@ DESCRIPTION
|
||||
list all channels
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/channel/list.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/channel/list.ts)_
|
||||
|
||||
## `eas channel:pause [NAME]`
|
||||
|
||||
@@ -877,7 +877,7 @@ DESCRIPTION
|
||||
pause a channel to stop it from sending updates
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/channel/pause.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/channel/pause.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/channel/pause.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/channel/pause.ts)_
|
||||
|
||||
## `eas channel:resume [NAME]`
|
||||
|
||||
@@ -899,7 +899,7 @@ DESCRIPTION
|
||||
resume a channel to start sending updates
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/channel/resume.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/channel/resume.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/channel/resume.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/channel/resume.ts)_
|
||||
|
||||
## `eas channel:rollout [CHANNEL]`
|
||||
|
||||
@@ -932,7 +932,7 @@ DESCRIPTION
|
||||
Roll a new branch out on a channel incrementally.
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/channel/rollout.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/channel/rollout.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/channel/rollout.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/channel/rollout.ts)_
|
||||
|
||||
## `eas channel:view [NAME]`
|
||||
|
||||
@@ -955,7 +955,7 @@ DESCRIPTION
|
||||
view a channel
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/channel/view.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/channel/view.ts)_
|
||||
|
||||
## `eas config`
|
||||
|
||||
@@ -976,7 +976,7 @@ DESCRIPTION
|
||||
display project configuration (app.json + eas.json)
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/config.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/config.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/config.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/config.ts)_
|
||||
|
||||
## `eas credentials`
|
||||
|
||||
@@ -993,7 +993,7 @@ DESCRIPTION
|
||||
manage credentials
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/credentials/index.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/credentials/index.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/credentials/index.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/credentials/index.ts)_
|
||||
|
||||
## `eas credentials:configure-build`
|
||||
|
||||
@@ -1011,7 +1011,7 @@ DESCRIPTION
|
||||
Set up credentials for building your project.
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/credentials/configure-build.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/credentials/configure-build.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/credentials/configure-build.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/credentials/configure-build.ts)_
|
||||
|
||||
## `eas deploy [options]`
|
||||
|
||||
@@ -1039,7 +1039,7 @@ ALIASES
|
||||
$ eas worker:deploy
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/deploy/index.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/deploy/index.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/deploy/index.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/deploy/index.ts)_
|
||||
|
||||
## `eas deploy:alias`
|
||||
|
||||
@@ -1064,7 +1064,7 @@ ALIASES
|
||||
$ eas deploy:promote
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/deploy/alias/index.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/deploy/alias/index.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/deploy/alias/index.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/deploy/alias/index.ts)_
|
||||
|
||||
## `eas deploy:alias:delete [ALIAS_NAME]`
|
||||
|
||||
@@ -1085,7 +1085,7 @@ ALIASES
|
||||
$ eas worker:alias:delete
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/deploy/alias/delete.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/deploy/alias/delete.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/deploy/alias/delete.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/deploy/alias/delete.ts)_
|
||||
|
||||
## `eas deploy:delete [DEPLOYMENT_ID]`
|
||||
|
||||
@@ -1106,7 +1106,7 @@ ALIASES
|
||||
$ eas worker:delete
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/deploy/delete.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/deploy/delete.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/deploy/delete.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/deploy/delete.ts)_
|
||||
|
||||
## `eas deploy:promote`
|
||||
|
||||
@@ -1143,7 +1143,7 @@ DESCRIPTION
|
||||
register new Apple Devices to use for internal distribution
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/device/create.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/device/create.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/device/create.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/device/create.ts)_
|
||||
|
||||
## `eas device:delete`
|
||||
|
||||
@@ -1163,7 +1163,7 @@ DESCRIPTION
|
||||
remove a registered device from your account
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/device/delete.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/device/delete.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/device/delete.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/device/delete.ts)_
|
||||
|
||||
## `eas device:list`
|
||||
|
||||
@@ -1184,7 +1184,7 @@ DESCRIPTION
|
||||
list all registered devices for your account
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/device/list.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/device/list.ts)_
|
||||
|
||||
## `eas device:rename`
|
||||
|
||||
@@ -1205,7 +1205,7 @@ DESCRIPTION
|
||||
rename a registered device
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/device/rename.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/device/rename.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/device/rename.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/device/rename.ts)_
|
||||
|
||||
## `eas device:view [UDID]`
|
||||
|
||||
@@ -1219,7 +1219,7 @@ DESCRIPTION
|
||||
view a device for your project
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/device/view.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/device/view.ts)_
|
||||
|
||||
## `eas diagnostics`
|
||||
|
||||
@@ -1233,7 +1233,7 @@ DESCRIPTION
|
||||
display environment info
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/diagnostics.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/diagnostics.ts)_
|
||||
|
||||
## `eas env:create [ENVIRONMENT]`
|
||||
|
||||
@@ -1263,7 +1263,7 @@ DESCRIPTION
|
||||
create an environment variable for the current project or account
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/env/create.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/env/create.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/env/create.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/env/create.ts)_
|
||||
|
||||
## `eas env:delete [ENVIRONMENT]`
|
||||
|
||||
@@ -1288,7 +1288,7 @@ DESCRIPTION
|
||||
delete an environment variable for the current project or account
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/env/delete.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/env/delete.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/env/delete.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/env/delete.ts)_
|
||||
|
||||
## `eas env:exec ENVIRONMENT BASH_COMMAND`
|
||||
|
||||
@@ -1310,7 +1310,7 @@ DESCRIPTION
|
||||
execute a command with environment variables from the selected environment
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/env/exec.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/env/exec.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/env/exec.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/env/exec.ts)_
|
||||
|
||||
## `eas env:get [ENVIRONMENT]`
|
||||
|
||||
@@ -1335,7 +1335,7 @@ DESCRIPTION
|
||||
view an environment variable for the current project or account
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/env/get.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/env/get.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/env/get.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/env/get.ts)_
|
||||
|
||||
## `eas env:list [ENVIRONMENT]`
|
||||
|
||||
@@ -1361,7 +1361,7 @@ DESCRIPTION
|
||||
list environment variables for the current project or account
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/env/list.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/env/list.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/env/list.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/env/list.ts)_
|
||||
|
||||
## `eas env:pull [ENVIRONMENT]`
|
||||
|
||||
@@ -1383,7 +1383,7 @@ DESCRIPTION
|
||||
pull environment variables for the selected environment to .env file
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/env/pull.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/env/pull.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/env/pull.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/env/pull.ts)_
|
||||
|
||||
## `eas env:push [ENVIRONMENT]`
|
||||
|
||||
@@ -1405,7 +1405,7 @@ DESCRIPTION
|
||||
push environment variables from .env file to the selected environment
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/env/push.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/env/push.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/env/push.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/env/push.ts)_
|
||||
|
||||
## `eas env:update [ENVIRONMENT]`
|
||||
|
||||
@@ -1437,7 +1437,7 @@ DESCRIPTION
|
||||
update an environment variable on the current project or account
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/env/update.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/env/update.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/env/update.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/env/update.ts)_
|
||||
|
||||
## `eas fingerprint:compare [HASH1] [HASH2]`
|
||||
|
||||
@@ -1481,7 +1481,7 @@ EXAMPLES
|
||||
$ eas fingerprint:compare <FINGERPRINT-HASH> --update-id <UPDATE-ID> # Compare fingerprint from update against provided fingerprint
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/fingerprint/compare.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/fingerprint/compare.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/fingerprint/compare.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/fingerprint/compare.ts)_
|
||||
|
||||
## `eas fingerprint:generate`
|
||||
|
||||
@@ -1511,7 +1511,7 @@ EXAMPLES
|
||||
$ eas fingerprint:generate --json --non-interactive --platform android # Output fingerprint json to stdout
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/fingerprint/generate.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/fingerprint/generate.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/fingerprint/generate.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/fingerprint/generate.ts)_
|
||||
|
||||
## `eas help [COMMAND]`
|
||||
|
||||
@@ -1619,7 +1619,7 @@ DESCRIPTION
|
||||
validate the local store configuration
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/metadata/lint.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/metadata/lint.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/metadata/lint.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/metadata/lint.ts)_
|
||||
|
||||
## `eas metadata:pull`
|
||||
|
||||
@@ -1636,7 +1636,7 @@ DESCRIPTION
|
||||
generate the local store configuration from the app stores
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/metadata/pull.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/metadata/pull.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/metadata/pull.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/metadata/pull.ts)_
|
||||
|
||||
## `eas metadata:push`
|
||||
|
||||
@@ -1653,7 +1653,7 @@ DESCRIPTION
|
||||
sync the local store configuration to the app stores
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/metadata/push.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/metadata/push.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/metadata/push.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/metadata/push.ts)_
|
||||
|
||||
## `eas new [PATH]`
|
||||
|
||||
@@ -1704,7 +1704,7 @@ DESCRIPTION
|
||||
open the project page in a web browser
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/open.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/open.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/open.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/open.ts)_
|
||||
|
||||
## `eas project:info`
|
||||
|
||||
@@ -1718,7 +1718,7 @@ DESCRIPTION
|
||||
information about the current project
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/project/info.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/project/info.ts)_
|
||||
|
||||
## `eas project:init`
|
||||
|
||||
@@ -1741,7 +1741,7 @@ ALIASES
|
||||
$ eas init
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/project/init.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/project/init.ts)_
|
||||
|
||||
## `eas project:new [PATH]`
|
||||
|
||||
@@ -1764,7 +1764,7 @@ ALIASES
|
||||
$ eas new
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/project/new.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/project/new.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/project/new.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/project/new.ts)_
|
||||
|
||||
## `eas project:onboarding [TARGET_PROJECT_DIRECTORY]`
|
||||
|
||||
@@ -1782,7 +1782,7 @@ ALIASES
|
||||
$ eas onboarding
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/project/onboarding.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/project/onboarding.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/project/onboarding.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/project/onboarding.ts)_
|
||||
|
||||
## `eas submit`
|
||||
|
||||
@@ -1817,7 +1817,7 @@ ALIASES
|
||||
$ eas build:submit
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/submit.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/submit.ts)_
|
||||
|
||||
## `eas update`
|
||||
|
||||
@@ -1857,7 +1857,7 @@ DESCRIPTION
|
||||
publish an update group
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/update/index.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/update/index.ts)_
|
||||
|
||||
## `eas update:configure`
|
||||
|
||||
@@ -1877,7 +1877,7 @@ DESCRIPTION
|
||||
configure the project to support EAS Update
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/configure.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/update/configure.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/update/configure.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/update/configure.ts)_
|
||||
|
||||
## `eas update:delete GROUPID`
|
||||
|
||||
@@ -1898,7 +1898,7 @@ DESCRIPTION
|
||||
delete all the updates in an update group
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/delete.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/update/delete.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/update/delete.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/update/delete.ts)_
|
||||
|
||||
## `eas update:edit [GROUPID]`
|
||||
|
||||
@@ -1922,7 +1922,7 @@ DESCRIPTION
|
||||
edit all the updates in an update group
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/edit.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/update/edit.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/update/edit.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/update/edit.ts)_
|
||||
|
||||
## `eas update:list`
|
||||
|
||||
@@ -1947,7 +1947,7 @@ DESCRIPTION
|
||||
view the recent updates
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/update/list.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/update/list.ts)_
|
||||
|
||||
## `eas update:republish`
|
||||
|
||||
@@ -1983,7 +1983,7 @@ DESCRIPTION
|
||||
roll back to an existing update
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/republish.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/update/republish.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/update/republish.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/update/republish.ts)_
|
||||
|
||||
## `eas update:revert-update-rollout`
|
||||
|
||||
@@ -2010,7 +2010,7 @@ DESCRIPTION
|
||||
revert a rollout update for a project
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/revert-update-rollout.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/update/revert-update-rollout.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/update/revert-update-rollout.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/update/revert-update-rollout.ts)_
|
||||
|
||||
## `eas update:roll-back-to-embedded`
|
||||
|
||||
@@ -2038,7 +2038,7 @@ DESCRIPTION
|
||||
roll back to the embedded update
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/roll-back-to-embedded.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/update/roll-back-to-embedded.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/update/roll-back-to-embedded.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/update/roll-back-to-embedded.ts)_
|
||||
|
||||
## `eas update:rollback`
|
||||
|
||||
@@ -2059,7 +2059,7 @@ DESCRIPTION
|
||||
instead execute "eas update:republish" or "eas update:roll-back-to-embedded".
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/rollback.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/update/rollback.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/update/rollback.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/update/rollback.ts)_
|
||||
|
||||
## `eas update:view GROUPID`
|
||||
|
||||
@@ -2079,7 +2079,7 @@ DESCRIPTION
|
||||
update group details
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/update/view.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/update/view.ts)_
|
||||
|
||||
## `eas upload`
|
||||
|
||||
@@ -2100,7 +2100,7 @@ DESCRIPTION
|
||||
upload a local build and generate a sharable link
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/upload.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/upload.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/upload.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/upload.ts)_
|
||||
|
||||
## `eas webhook:create`
|
||||
|
||||
@@ -2121,7 +2121,7 @@ DESCRIPTION
|
||||
create a webhook
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/webhook/create.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/webhook/create.ts)_
|
||||
|
||||
## `eas webhook:delete [ID]`
|
||||
|
||||
@@ -2141,7 +2141,7 @@ DESCRIPTION
|
||||
delete a webhook
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/webhook/delete.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/webhook/delete.ts)_
|
||||
|
||||
## `eas webhook:list`
|
||||
|
||||
@@ -2159,7 +2159,7 @@ DESCRIPTION
|
||||
list webhooks
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/webhook/list.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/webhook/list.ts)_
|
||||
|
||||
## `eas webhook:update`
|
||||
|
||||
@@ -2181,7 +2181,7 @@ DESCRIPTION
|
||||
update a webhook
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/webhook/update.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/webhook/update.ts)_
|
||||
|
||||
## `eas webhook:view ID`
|
||||
|
||||
@@ -2198,7 +2198,7 @@ DESCRIPTION
|
||||
view a webhook
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/webhook/view.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/webhook/view.ts)_
|
||||
|
||||
## `eas whoami`
|
||||
|
||||
@@ -2318,7 +2318,7 @@ DESCRIPTION
|
||||
to cancel.
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/workflow/cancel.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/workflow/cancel.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/workflow/cancel.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/workflow/cancel.ts)_
|
||||
|
||||
## `eas workflow:create [NAME]`
|
||||
|
||||
@@ -2338,7 +2338,7 @@ DESCRIPTION
|
||||
create a new workflow configuration YAML file
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/workflow/create.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/workflow/create.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/workflow/create.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/workflow/create.ts)_
|
||||
|
||||
## `eas workflow:logs [ID]`
|
||||
|
||||
@@ -2362,7 +2362,7 @@ DESCRIPTION
|
||||
If no ID is passed in, you will be prompted to select from recent workflow runs for the current project.
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/workflow/logs.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/workflow/logs.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/workflow/logs.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/workflow/logs.ts)_
|
||||
|
||||
## `eas workflow:run [FILE]`
|
||||
|
||||
@@ -2402,7 +2402,7 @@ FLAG DESCRIPTIONS
|
||||
Exit codes: 0 = success, 11 = failure, 12 = canceled, 13 = wait aborted.
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/workflow/run.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/workflow/run.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/workflow/run.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/workflow/run.ts)_
|
||||
|
||||
## `eas workflow:runs`
|
||||
|
||||
@@ -2427,7 +2427,7 @@ DESCRIPTION
|
||||
list recent workflow runs for this project, with their IDs, statuses, and timestamps
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/workflow/runs.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/workflow/runs.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/workflow/runs.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/workflow/runs.ts)_
|
||||
|
||||
## `eas workflow:status [WORKFLOW_RUN_ID]`
|
||||
|
||||
@@ -2455,7 +2455,7 @@ FLAG DESCRIPTIONS
|
||||
Exit codes: 0 = success, 11 = failure, 12 = canceled, 13 = wait aborted.
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/workflow/status.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/workflow/status.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/workflow/status.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/workflow/status.ts)_
|
||||
|
||||
## `eas workflow:validate PATH`
|
||||
|
||||
@@ -2475,7 +2475,7 @@ DESCRIPTION
|
||||
validate a workflow configuration yaml file
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/workflow/validate.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/workflow/validate.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/workflow/validate.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/workflow/validate.ts)_
|
||||
|
||||
## `eas workflow:view [ID]`
|
||||
|
||||
@@ -2497,5 +2497,5 @@ DESCRIPTION
|
||||
workflow runs for the current project.
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/workflow/view.ts](https://github.com/expo/eas-cli/blob/v17.0.0/packages/eas-cli/src/commands/workflow/view.ts)_
|
||||
_See code: [packages/eas-cli/src/commands/workflow/view.ts](https://github.com/expo/eas-cli/blob/v16.32.0/packages/eas-cli/src/commands/workflow/view.ts)_
|
||||
<!-- commandsstop -->
|
||||
@@ -1,13 +1,12 @@
|
||||
import type { Config } from '@jest/types';
|
||||
import type { Config } from 'jest';
|
||||
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import baseConfig from '../../jest/jest.shared.config';
|
||||
import baseConfig from '../../jest/jest.config';
|
||||
|
||||
const config: Config.InitialOptions = {
|
||||
const config: Config = {
|
||||
...baseConfig,
|
||||
rootDir: __dirname,
|
||||
roots: ['src', '__mocks__'],
|
||||
testRegex: '/__tests__/.*(test|spec)\\.[jt]sx?$',
|
||||
globalSetup: './jest/global-setup.ts',
|
||||
setupFilesAfterEnv: ['./jest/setup-after-env.ts'],
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "eas-cli",
|
||||
"description": "EAS command line tool",
|
||||
"version": "17.0.0",
|
||||
"version": "16.32.0",
|
||||
"author": "Expo <[email protected]>",
|
||||
"bin": {
|
||||
"eas": "./bin/run"
|
||||
@@ -12,11 +12,11 @@
|
||||
"@expo/code-signing-certificates": "0.0.5",
|
||||
"@expo/config": "10.0.6",
|
||||
"@expo/config-plugins": "9.0.12",
|
||||
"@expo/eas-build-job": "17.0.0",
|
||||
"@expo/eas-json": "17.0.0",
|
||||
"@expo/eas-build-job": "1.0.265",
|
||||
"@expo/eas-json": "16.30.0",
|
||||
"@expo/env": "^1.0.0",
|
||||
"@expo/json-file": "8.3.3",
|
||||
"@expo/logger": "17.0.0",
|
||||
"@expo/logger": "1.0.260",
|
||||
"@expo/multipart-body-parser": "2.0.0",
|
||||
"@expo/osascript": "2.1.4",
|
||||
"@expo/package-manager": "1.9.10",
|
||||
@@ -28,7 +28,7 @@
|
||||
"@expo/results": "1.0.0",
|
||||
"@expo/rudder-sdk-node": "1.1.1",
|
||||
"@expo/spawn-async": "1.7.2",
|
||||
"@expo/steps": "17.0.0",
|
||||
"@expo/steps": "1.0.271",
|
||||
"@expo/timeago.js": "1.0.0",
|
||||
"@oclif/core": "^1.26.2",
|
||||
"@oclif/plugin-autocomplete": "^2.3.10",
|
||||
@@ -61,6 +61,7 @@
|
||||
"invariant": "^2.2.2",
|
||||
"jks-js": "1.1.0",
|
||||
"joi": "17.11.0",
|
||||
"jsonwebtoken": "9.0.0",
|
||||
"keychain": "1.5.0",
|
||||
"log-symbols": "4.1.0",
|
||||
"mime": "3.0.0",
|
||||
@@ -82,7 +83,7 @@
|
||||
"semver": "7.5.4",
|
||||
"set-interval-async": "3.0.3",
|
||||
"slash": "3.0.0",
|
||||
"tar": "7.5.7",
|
||||
"tar": "6.2.1",
|
||||
"tar-stream": "3.1.7",
|
||||
"terminal-link": "2.1.1",
|
||||
"ts-deepmerge": "6.2.0",
|
||||
@@ -108,6 +109,7 @@
|
||||
"@types/fs-extra": "11.0.4",
|
||||
"@types/getenv": "^1.0.0",
|
||||
"@types/invariant": "^2.2.37",
|
||||
"@types/jsonwebtoken": "8.5.1",
|
||||
"@types/mime": "3.0.1",
|
||||
"@types/node-fetch": "2.6.12",
|
||||
"@types/node-forge": "1.3.1",
|
||||
|
||||
@@ -5,57 +5,8 @@ set -eo pipefail
|
||||
EAS_CLI_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/.. && pwd )"
|
||||
PACKAGE_JSON_PATH="$EAS_CLI_DIR/package.json"
|
||||
|
||||
# Define local packages and their directory names
|
||||
# Only include packages that both exist in packages/ and are dependencies of the packages we care about
|
||||
# We start with direct dependencies of eas-cli and their own local dependencies
|
||||
PACKAGES=(
|
||||
"@expo/eas-json:eas-json"
|
||||
"@expo/eas-build-job:eas-build-job"
|
||||
"@expo/logger:logger"
|
||||
"@expo/steps:steps"
|
||||
)
|
||||
|
||||
# Function to rewrite dependencies in a package.json file
|
||||
rewrite_deps() {
|
||||
local PKG_JSON=$1
|
||||
local IS_EAS_CLI=$2
|
||||
|
||||
for package in "${PACKAGES[@]}" ; do
|
||||
KEY="${package%%:*}"
|
||||
DIR="${package##*:}"
|
||||
|
||||
# Determine the relative path. If IS_EAS_CLI we go one level deeper because oclif builds in `tmp` in current directory.
|
||||
if [[ "$IS_EAS_CLI" == "true" ]]; then
|
||||
REL_PATH="file:../../../$DIR"
|
||||
else
|
||||
REL_PATH="file:../$DIR"
|
||||
fi
|
||||
|
||||
# Replace version with relative path
|
||||
# Using # delimiter for sed to handle slashes
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
sed -i '' "s#\"$KEY\": \".*\"#\"$KEY\": \"$REL_PATH\"#g" "$PKG_JSON"
|
||||
else
|
||||
sed -i "s#\"$KEY\": \".*\"#\"$KEY\": \"$REL_PATH\"#g" "$PKG_JSON"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Update eas-cli/package.json
|
||||
echo "Updating eas-cli/package.json"
|
||||
rewrite_deps "$PACKAGE_JSON_PATH" "true"
|
||||
|
||||
# Update other relevant local packages
|
||||
# We iterate the PACKAGES list itself to find their locations and update them
|
||||
# This ensures we only touch packages that are part of the dependency graph we care about
|
||||
WORKSPACE_ROOT="$(cd "$EAS_CLI_DIR/.." && pwd)"
|
||||
|
||||
for package in "${PACKAGES[@]}" ; do
|
||||
DIR="${package##*:}"
|
||||
PKG_JSON="$WORKSPACE_ROOT/$DIR/package.json"
|
||||
|
||||
if [[ -f "$PKG_JSON" ]]; then
|
||||
echo "Updating $DIR/package.json"
|
||||
rewrite_deps "$PKG_JSON" "false"
|
||||
fi
|
||||
done
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
sed -i '' "s/\\\"@expo\/eas-json\\\": \\\".*\\\"/\\\"@expo\/eas-json\\\": \\\"file:..\/..\/..\/eas-json\\\"/g" $PACKAGE_JSON_PATH
|
||||
else
|
||||
sed -i "s/\\\"@expo\/eas-json\\\": \\\".*\\\"/\\\"@expo\/eas-json\\\": \\\"file:..\/..\/..\/eas-json\\\"/g" $PACKAGE_JSON_PATH
|
||||
fi
|
||||
@@ -40,19 +40,7 @@ export async function selectBranchOnAppAsync(
|
||||
}
|
||||
): Promise<UpdateBranchFragment> {
|
||||
if (paginatedQueryOptions.nonInteractive) {
|
||||
const branches = await queryBranchesOnProjectAsync(
|
||||
graphqlClient,
|
||||
paginatedQueryOptions.limit ?? BRANCHES_LIMIT,
|
||||
paginatedQueryOptions.offset,
|
||||
projectId
|
||||
);
|
||||
if (branches.length === 0) {
|
||||
throw new Error(`No branches found for project "${projectId}".`);
|
||||
}
|
||||
const branchList = branches.map(b => b.name).join('\n ');
|
||||
throw new Error(
|
||||
`Unable to select a branch in non-interactive mode. Use the --branch flag to specify the branch. Available branches:\n ${branchList}`
|
||||
);
|
||||
throw new Error('Unable to select a branch in non-interactive mode.');
|
||||
}
|
||||
|
||||
const selectedBranch = await paginatedQueryWithSelectPromptAsync({
|
||||
|
||||
@@ -77,26 +77,7 @@ export async function listAndSelectBuildOnAppAsync(
|
||||
}
|
||||
): Promise<BuildFragment | null> {
|
||||
if (paginatedQueryOptions.nonInteractive) {
|
||||
const builds = await BuildQuery.viewBuildsOnAppAsync(graphqlClient, {
|
||||
appId: projectId,
|
||||
limit: paginatedQueryOptions.limit ?? BUILDS_LIMIT,
|
||||
offset: paginatedQueryOptions.offset,
|
||||
filter,
|
||||
});
|
||||
if (builds.length === 0) {
|
||||
throw new Error('No builds found for this project.');
|
||||
}
|
||||
const buildList = builds
|
||||
.map(
|
||||
b =>
|
||||
`${b.id} (platform: ${b.platform}, status: ${b.status}${
|
||||
b.buildProfile ? `, profile: ${b.buildProfile}` : ''
|
||||
})`
|
||||
)
|
||||
.join('\n ');
|
||||
throw new Error(
|
||||
`Unable to select a build in non-interactive mode. Available builds:\n ${buildList}`
|
||||
);
|
||||
throw new Error('Unable to select a build in non-interactive mode.');
|
||||
} else {
|
||||
const selectedBuild = await paginatedQueryWithSelectPromptAsync({
|
||||
limit: paginatedQueryOptions.limit ?? BUILDS_LIMIT,
|
||||
|
||||
@@ -128,7 +128,7 @@ export async function runBuildAndSubmitAsync({
|
||||
buildIds: string[];
|
||||
buildProfiles?: ProfileData<'build'>[];
|
||||
}> {
|
||||
await vcsClient.ensureRepoExistsAsync({ nonInteractive: flags.nonInteractive });
|
||||
await vcsClient.ensureRepoExistsAsync();
|
||||
await ensureRepoIsCleanAsync(vcsClient, flags.nonInteractive);
|
||||
|
||||
await ensureProjectConfiguredAsync({
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import chalk from 'chalk';
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
import * as tar from 'tar';
|
||||
import tar from 'tar';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import Log, { learnMore } from '../../log';
|
||||
|
||||
@@ -43,18 +43,7 @@ export async function selectChannelOnAppAsync(
|
||||
}
|
||||
): Promise<UpdateChannelObject> {
|
||||
if (paginatedQueryOptions.nonInteractive) {
|
||||
const channels = await queryChannelsOnAppAsync(graphqlClient, {
|
||||
appId: projectId,
|
||||
limit: paginatedQueryOptions.limit ?? CHANNELS_LIMIT,
|
||||
offset: paginatedQueryOptions.offset,
|
||||
});
|
||||
if (channels.length === 0) {
|
||||
throw new Error(`No channels found for project "${projectId}".`);
|
||||
}
|
||||
const channelList = channels.map(c => c.name).join('\n ');
|
||||
throw new Error(
|
||||
`Unable to select a channel in non-interactive mode. Use the --channel flag to specify the channel. Available channels:\n ${channelList}`
|
||||
);
|
||||
throw new Error('Unable to select a channel in non-interactive mode.');
|
||||
}
|
||||
|
||||
const updateChannel = await paginatedQueryWithSelectPromptAsync({
|
||||
|
||||
@@ -17,11 +17,6 @@ export default class AccountLogin extends EasCommand {
|
||||
char: 's',
|
||||
default: false,
|
||||
}),
|
||||
browser: Flags.boolean({
|
||||
description: 'Login with your browser',
|
||||
char: 'b',
|
||||
default: false,
|
||||
}),
|
||||
};
|
||||
|
||||
static override contextDefinition = {
|
||||
@@ -31,7 +26,7 @@ export default class AccountLogin extends EasCommand {
|
||||
|
||||
async runAsync(): Promise<void> {
|
||||
const {
|
||||
flags: { sso, browser },
|
||||
flags: { sso },
|
||||
} = await this.parse(AccountLogin);
|
||||
|
||||
const {
|
||||
@@ -56,7 +51,7 @@ export default class AccountLogin extends EasCommand {
|
||||
}
|
||||
}
|
||||
|
||||
await sessionManager.showLoginPromptAsync({ sso, browser });
|
||||
await sessionManager.showLoginPromptAsync({ sso });
|
||||
Log.log('Logged in');
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,9 @@ export default class BuildConfigure extends EasCommand {
|
||||
'💡 The following process will configure your iOS and/or Android project to be compatible with EAS Build. These changes only apply to your local project files and you can safely revert them at any time.'
|
||||
);
|
||||
|
||||
await vcsClient.ensureRepoExistsAsync({ nonInteractive: false });
|
||||
// BuildConfigure.ContextOptions.Vcs.client.getValueAsync()
|
||||
|
||||
await vcsClient.ensureRepoExistsAsync();
|
||||
|
||||
const expoUpdatesIsInstalled = isExpoUpdatesInstalled(projectDir);
|
||||
|
||||
|
||||
@@ -74,8 +74,8 @@ export default class BuildDev extends EasCommand {
|
||||
Errors.error('Running iOS builds in simulator is only supported on macOS.', { exit: 1 });
|
||||
}
|
||||
|
||||
await vcsClient.ensureRepoExistsAsync({ nonInteractive: false });
|
||||
await ensureRepoIsCleanAsync(vcsClient, false);
|
||||
await vcsClient.ensureRepoExistsAsync();
|
||||
await ensureRepoIsCleanAsync(vcsClient, flags.nonInteractive);
|
||||
await ensureProjectConfiguredAsync({
|
||||
projectDir,
|
||||
nonInteractive: false,
|
||||
|
||||
@@ -94,7 +94,7 @@ export default class BuildInspect extends EasCommand {
|
||||
await this.prepareOutputDirAsync(outputDirectory, flags.force);
|
||||
|
||||
if (flags.stage === InspectStage.ARCHIVE) {
|
||||
await vcsClient.ensureRepoExistsAsync({ nonInteractive: false });
|
||||
await vcsClient.ensureRepoExistsAsync();
|
||||
await vcsClient.makeShallowCopyAsync(tmpWorkingdir);
|
||||
await this.copyToOutputDirAsync(tmpWorkingdir, outputDirectory);
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,287 @@
|
||||
import { Flags } from '@oclif/core';
|
||||
import fs from 'fs-extra';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import fetch from 'node-fetch';
|
||||
import path from 'path';
|
||||
import { setTimeout } from 'timers/promises';
|
||||
import { z } from 'zod';
|
||||
|
||||
import EasCommand from '../../commandUtils/EasCommand';
|
||||
import Log from '../../log';
|
||||
import { AscApiClient, AscApiClientPostApi } from '../../submit/ios/AscApiClient';
|
||||
|
||||
export default class SubmitUploadToAsc extends EasCommand {
|
||||
static override hidden = true;
|
||||
|
||||
static override flags = {
|
||||
path: Flags.string({
|
||||
description: 'Path to the IPA file',
|
||||
required: true,
|
||||
}),
|
||||
key: Flags.string({
|
||||
description: 'Path to the ASC API Key JSON file',
|
||||
required: true,
|
||||
}),
|
||||
'app-id': Flags.string({
|
||||
description: 'App Store Connect App ID (e.g. 1491144534)',
|
||||
required: true,
|
||||
}),
|
||||
'bundle-version': Flags.string({
|
||||
description: 'CFBundleVersion (Build Version, e.g. 13)',
|
||||
required: true,
|
||||
}),
|
||||
'bundle-short-version': Flags.string({
|
||||
description: 'CFBundleShortVersionString (Marketing Version, e.g. 1.0.0)',
|
||||
required: true,
|
||||
}),
|
||||
};
|
||||
|
||||
async runAsync(): Promise<void> {
|
||||
const { flags } = await this.parse(SubmitUploadToAsc);
|
||||
|
||||
const ipaPath = path.resolve(flags.path);
|
||||
if (!(await fs.pathExists(ipaPath))) {
|
||||
throw new Error(`IPA file not found: ${ipaPath}`);
|
||||
}
|
||||
const fileSize = (await fs.stat(ipaPath)).size;
|
||||
const fileName = path.basename(ipaPath);
|
||||
|
||||
const keyPath = path.resolve(flags.key);
|
||||
if (!(await fs.pathExists(keyPath))) {
|
||||
throw new Error(`Key file not found: ${keyPath}`);
|
||||
}
|
||||
|
||||
const keyJson = await fs.readJson(keyPath);
|
||||
const apiKey = z
|
||||
.object({
|
||||
issuer_id: z.string(),
|
||||
key_id: z.string(),
|
||||
key: z.string(),
|
||||
})
|
||||
.parse(keyJson);
|
||||
|
||||
Log.log('Generating JWT...');
|
||||
const token = jwt.sign({}, apiKey.key, {
|
||||
algorithm: 'ES256',
|
||||
issuer: apiKey.issuer_id,
|
||||
expiresIn: '20m',
|
||||
audience: 'appstoreconnect-v1',
|
||||
header: {
|
||||
kid: apiKey.key_id,
|
||||
},
|
||||
});
|
||||
|
||||
const client = new AscApiClient({ token });
|
||||
|
||||
Log.log('Reading App information...');
|
||||
const appResponse = await client.getAsync(
|
||||
'/v1/apps/:id',
|
||||
{ 'fields[apps]': ['bundleId', 'name'] as const },
|
||||
{ id: flags['app-id'] }
|
||||
);
|
||||
Log.log(
|
||||
`Uploading Build to "${appResponse.data.attributes.name}" (${appResponse.data.attributes.bundleId})...`
|
||||
);
|
||||
|
||||
Log.log('Creating Build Upload...');
|
||||
const buildUploadResponse = await client.postAsync('/v1/buildUploads', {
|
||||
data: {
|
||||
type: 'buildUploads',
|
||||
attributes: {
|
||||
platform: 'IOS',
|
||||
cfBundleShortVersionString: flags['bundle-short-version'],
|
||||
cfBundleVersion: flags['bundle-version'],
|
||||
},
|
||||
relationships: {
|
||||
app: {
|
||||
data: {
|
||||
type: 'apps',
|
||||
id: flags['app-id'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const buildUploadId = buildUploadResponse.data.id;
|
||||
|
||||
Log.log(`Build Upload initialized (ID: ${buildUploadId}). Preparing IPA upload...`);
|
||||
const buildFileResponse = await client.postAsync('/v1/buildUploadFiles', {
|
||||
data: {
|
||||
type: 'buildUploadFiles',
|
||||
attributes: {
|
||||
assetType: 'ASSET',
|
||||
fileName,
|
||||
fileSize,
|
||||
uti: 'com.apple.ipa',
|
||||
},
|
||||
relationships: {
|
||||
buildUpload: {
|
||||
data: {
|
||||
type: 'buildUploads',
|
||||
id: buildUploadId,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Log.log(`IPA Upload initialized (ID: ${buildFileResponse.data.id}). Uploading IPA...`);
|
||||
await uploadChunksAsync({
|
||||
uploadOperations: buildFileResponse.data.attributes.uploadOperations,
|
||||
ipaPath,
|
||||
});
|
||||
|
||||
Log.log('Committing upload...');
|
||||
await client.patchAsync(
|
||||
`/v1/buildUploadFiles/:id`,
|
||||
{
|
||||
data: {
|
||||
type: 'buildUploadFiles',
|
||||
id: buildFileResponse.data.id,
|
||||
attributes: {
|
||||
uploaded: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: buildFileResponse.data.id,
|
||||
}
|
||||
);
|
||||
|
||||
Log.log('Checking upload file status...');
|
||||
const waitingForFileStartedAt = performance.now();
|
||||
while (performance.now() - waitingForFileStartedAt < 60 * 1000 /* 60 seconds */) {
|
||||
const buildFileStatusResponse = await client.getAsync(
|
||||
`/v1/buildUploadFiles/:id`,
|
||||
{ 'fields[buildUploadFiles]': ['assetDeliveryState'] },
|
||||
{ id: buildFileResponse.data.id }
|
||||
);
|
||||
|
||||
if (buildFileStatusResponse.data.attributes.assetDeliveryState.state === 'AWAITING_UPLOAD') {
|
||||
Log.log(
|
||||
`Waiting for file upload to finish processing... (state = ${buildFileStatusResponse.data.attributes.assetDeliveryState.state})`
|
||||
);
|
||||
await setTimeout(2000);
|
||||
continue;
|
||||
}
|
||||
|
||||
const { errors = [], warnings = [] } =
|
||||
buildFileStatusResponse.data.attributes.assetDeliveryState;
|
||||
if (warnings.length > 0) {
|
||||
Log.warn(
|
||||
`Warnings:\n- ${warnings.map(w => `${w.description} (${w.code})`).join('\n- ')}\n`
|
||||
);
|
||||
}
|
||||
if (errors.length > 0) {
|
||||
Log.error(`Errors:\n- ${errors.map(e => `${e.description} (${e.code})`).join('\n- ')}\n`);
|
||||
}
|
||||
|
||||
if (buildFileStatusResponse.data.attributes.assetDeliveryState.state === 'FAILED') {
|
||||
throw new Error(`File upload (ID: ${buildFileResponse.data.id}) failed.`);
|
||||
} else if (buildFileStatusResponse.data.attributes.assetDeliveryState.state === 'COMPLETE') {
|
||||
Log.log(`File upload (ID: ${buildFileResponse.data.id}) complete!`);
|
||||
} else if (
|
||||
buildFileStatusResponse.data.attributes.assetDeliveryState.state === 'UPLOAD_COMPLETE'
|
||||
) {
|
||||
Log.log(`File upload (ID: ${buildFileResponse.data.id}) finished!`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Log.log('Checking build upload status...');
|
||||
const waitingForBuildStartedAt = performance.now();
|
||||
while (performance.now() - waitingForBuildStartedAt < 60 * 1000 /* 60 seconds */) {
|
||||
const buildUploadStatusResponse = await client.getAsync(
|
||||
`/v1/buildUploads/:id`,
|
||||
{ 'fields[buildUploads]': ['state', 'build'], include: ['build'] },
|
||||
{ id: buildUploadId }
|
||||
);
|
||||
|
||||
if (
|
||||
buildUploadStatusResponse.data.attributes.state.state === 'AWAITING_UPLOAD' ||
|
||||
buildUploadStatusResponse.data.attributes.state.state === 'PROCESSING'
|
||||
) {
|
||||
Log.log(
|
||||
`Waiting for build upload to finish... (status = ${buildUploadStatusResponse.data.attributes.state.state})`
|
||||
);
|
||||
await setTimeout(2000);
|
||||
continue;
|
||||
}
|
||||
|
||||
Log.log('\n');
|
||||
|
||||
const {
|
||||
errors = [],
|
||||
warnings = [],
|
||||
infos = [],
|
||||
} = buildUploadStatusResponse.data.attributes.state;
|
||||
if (infos.length > 0) {
|
||||
Log.log(`Infos:\n- ${infos.map(i => `${i.description} (${i.code})`).join('\n- ')}\n`);
|
||||
}
|
||||
if (warnings.length > 0) {
|
||||
Log.warn(
|
||||
`Warnings:\n- ${warnings.map(w => `${w.description} (${w.code})`).join('\n- ')}\n`
|
||||
);
|
||||
}
|
||||
if (errors.length > 0) {
|
||||
Log.error(`Errors:\n- ${errors.map(e => `${e.description} (${e.code})`).join('\n- ')}\n`);
|
||||
}
|
||||
|
||||
if (buildUploadStatusResponse.data.attributes.state.state === 'FAILED') {
|
||||
throw new Error(`Build upload (ID: ${buildUploadId}) failed.`);
|
||||
} else if (buildUploadStatusResponse.data.attributes.state.state === 'COMPLETE') {
|
||||
Log.log(`Build upload (ID: ${buildUploadId}) complete!`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function uploadChunksAsync({
|
||||
uploadOperations,
|
||||
ipaPath,
|
||||
}: {
|
||||
uploadOperations: AscApiClientPostApi['/v1/buildUploadFiles']['response']['data']['attributes']['uploadOperations'];
|
||||
ipaPath: string;
|
||||
}): Promise<void> {
|
||||
const fd = await fs.open(ipaPath, 'r');
|
||||
try {
|
||||
const promises = uploadOperations.map(async (op, index) => {
|
||||
Log.log(
|
||||
` Uploading chunk ${index + 1}/${uploadOperations.length} (offset: ${op.offset}, length: ${
|
||||
op.length
|
||||
})...`
|
||||
);
|
||||
|
||||
const buffer = new Uint8Array(op.length);
|
||||
await fs.read(fd, buffer, 0, op.length, op.offset);
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
'Content-Type': 'application/octet-stream',
|
||||
};
|
||||
|
||||
for (const { name, value } of op.requestHeaders) {
|
||||
headers[name] = value;
|
||||
}
|
||||
|
||||
const response = await fetch(op.url, {
|
||||
method: op.method,
|
||||
headers,
|
||||
body: buffer,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const text = await response.text();
|
||||
throw new Error(
|
||||
`Failed to upload chunk ${index + 1}: ${response.status} ${response.statusText}\n${text}`
|
||||
);
|
||||
}
|
||||
Log.log(` Chunk ${index + 1}/${uploadOperations.length} uploaded.`);
|
||||
});
|
||||
|
||||
await Promise.all(promises);
|
||||
} finally {
|
||||
await fs.close(fd);
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,7 @@ export default class UpdateConfigure extends EasCommand {
|
||||
'💡 The following process will configure your project to use EAS Update. These changes only apply to your local project files and you can safely revert them at any time.'
|
||||
);
|
||||
|
||||
await vcsClient.ensureRepoExistsAsync({ nonInteractive: flags['non-interactive'] });
|
||||
await vcsClient.ensureRepoExistsAsync();
|
||||
|
||||
const easJsonAccessor = EasJsonAccessor.fromProjectPath(projectDir);
|
||||
const easJsonCliConfig: EasJson['cli'] =
|
||||
|
||||
@@ -240,7 +240,7 @@ export default class UpdatePublish extends EasCommand {
|
||||
enableJsonOutput();
|
||||
}
|
||||
|
||||
await vcsClient.ensureRepoExistsAsync({ nonInteractive });
|
||||
await vcsClient.ensureRepoExistsAsync();
|
||||
await ensureRepoIsCleanAsync(vcsClient, nonInteractive);
|
||||
|
||||
const {
|
||||
|
||||
@@ -5,7 +5,7 @@ import fg from 'fast-glob';
|
||||
import fs from 'fs-extra';
|
||||
import StreamZip from 'node-stream-zip';
|
||||
import path from 'path';
|
||||
import * as tar from 'tar';
|
||||
import tar from 'tar';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import { getBuildLogsUrl } from '../build/utils/url';
|
||||
|
||||
@@ -31,22 +31,7 @@ export async function selectAppleTeamOnAccountAsync(
|
||||
}
|
||||
): Promise<AppleTeamFragment> {
|
||||
if (paginatedQueryOptions.nonInteractive) {
|
||||
const teams = await AppleTeamQuery.getAllForAccountAsync(graphqlClient, {
|
||||
accountName,
|
||||
limit: paginatedQueryOptions.limit ?? TEAMS_LIMIT,
|
||||
offset: paginatedQueryOptions.offset,
|
||||
});
|
||||
if (teams.length === 0) {
|
||||
throw new Error(`No Apple teams found for account ${accountName}.`);
|
||||
}
|
||||
const teamList = teams
|
||||
.map(t =>
|
||||
t.appleTeamName ? `${t.appleTeamName} (${t.appleTeamIdentifier})` : t.appleTeamIdentifier
|
||||
)
|
||||
.join('\n ');
|
||||
throw new Error(
|
||||
`Unable to select an Apple team in non-interactive mode. Use the --apple-team-id flag to specify the team. Available Apple teams for account ${accountName}:\n ${teamList}`
|
||||
);
|
||||
throw new Error('Unable to select an Apple team in non-interactive mode.');
|
||||
} else {
|
||||
const selectedAppleTeam = await paginatedQueryWithSelectPromptAsync({
|
||||
limit: paginatedQueryOptions.limit ?? TEAMS_LIMIT,
|
||||
@@ -89,21 +74,7 @@ export async function selectAppleDeviceOnAppleTeamAsync(
|
||||
}
|
||||
): Promise<AppleDeviceFragment> {
|
||||
if (paginatedQueryOptions.nonInteractive) {
|
||||
const devices = await AppleDeviceQuery.getAllForAppleTeamAsync(graphqlClient, {
|
||||
accountName,
|
||||
appleTeamIdentifier,
|
||||
limit: paginatedQueryOptions.limit ?? DEVICES_LIMIT,
|
||||
offset: paginatedQueryOptions.offset,
|
||||
});
|
||||
if (devices.length === 0) {
|
||||
throw new Error(
|
||||
`No devices found on Apple team ${appleTeamIdentifier} for account ${accountName}.`
|
||||
);
|
||||
}
|
||||
const deviceList = devices.map(d => formatDeviceLabel(d)).join('\n ');
|
||||
throw new Error(
|
||||
`Unable to select an Apple device in non-interactive mode. Available devices on Apple team ${appleTeamIdentifier}:\n ${deviceList}`
|
||||
);
|
||||
throw new Error('Unable to select an Apple device in non-interactive mode.');
|
||||
} else {
|
||||
const selectedAppleDevice = await paginatedQueryWithSelectPromptAsync({
|
||||
limit: paginatedQueryOptions.limit ?? DEVICES_LIMIT,
|
||||
|
||||
@@ -41,13 +41,7 @@ export class ManageRollout implements EASUpdateAction<EASUpdateAction> {
|
||||
public async runAsync(ctx: EASUpdateContext): Promise<EASUpdateAction> {
|
||||
const { nonInteractive } = ctx;
|
||||
if (nonInteractive) {
|
||||
throw new Error(
|
||||
`Rollout selection cannot be run in non-interactive mode. Available actions: ${[
|
||||
ManageRolloutActions.EDIT,
|
||||
ManageRolloutActions.END,
|
||||
ManageRolloutActions.VIEW,
|
||||
].join(', ')}.`
|
||||
);
|
||||
throw new Error(`rollout selection cannot be run in non-interactive mode.`);
|
||||
}
|
||||
const channelObject = await this.getChannelObjectAsync(ctx);
|
||||
printRollout(channelObject);
|
||||
|
||||
@@ -52,20 +52,7 @@ export class SelectRuntime implements EASUpdateAction<string | null> {
|
||||
const { nonInteractive, graphqlClient, app } = ctx;
|
||||
const { projectId } = app;
|
||||
if (nonInteractive) {
|
||||
const runtimes = await this.getNewestRuntimeAsync(graphqlClient, {
|
||||
appId: projectId,
|
||||
branchName: this.branchInfo.name,
|
||||
anotherBranchIdToIntersectRuntimesBy: this.options.anotherBranchToIntersectRuntimesBy?.id,
|
||||
});
|
||||
if (runtimes.edges.length === 0) {
|
||||
throw new NonInteractiveError(
|
||||
`No ${this.printedType} versions found on branch "${this.branchInfo.name}".`
|
||||
);
|
||||
}
|
||||
const runtimeList = runtimes.edges.map(e => e.node.version).join('\n ');
|
||||
throw new NonInteractiveError(
|
||||
`Runtime selection cannot be run in non-interactive mode. Available ${this.printedType} versions on branch "${this.branchInfo.name}":\n ${runtimeList}`
|
||||
);
|
||||
throw new NonInteractiveError(`runtime selection cannot be run in non-interactive mode.`);
|
||||
}
|
||||
|
||||
const newestRuntimeConnection = await this.getNewestRuntimeAsync(graphqlClient, {
|
||||
|
||||
+5
-15
@@ -1,8 +1,9 @@
|
||||
import { bunyan } from '@expo/logger';
|
||||
import { asyncResult } from '@expo/results';
|
||||
import fetch from 'node-fetch';
|
||||
import { ZodError, z } from 'zod';
|
||||
|
||||
import Log from '../../log';
|
||||
|
||||
type ApiSchema = {
|
||||
[Path in string]: {
|
||||
path?: z.ZodType<Record<string, string>>;
|
||||
@@ -239,11 +240,9 @@ export type AscApiClientPatchApi = {
|
||||
export class AscApiClient {
|
||||
private readonly baseUrl = 'https://api.appstoreconnect.apple.com';
|
||||
private readonly token: string;
|
||||
private readonly logger?: bunyan;
|
||||
|
||||
constructor({ token, logger }: { token: string; logger?: bunyan }) {
|
||||
constructor({ token }: { token: string }) {
|
||||
this.token = token;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public async getAsync<TPath extends keyof typeof GetApi>(
|
||||
@@ -258,18 +257,9 @@ export class AscApiClient {
|
||||
effectivePath = effectivePath.replace(`:${key}`, String(value));
|
||||
}
|
||||
|
||||
const searchParams = new URLSearchParams();
|
||||
for (const [key, value] of Object.entries(body)) {
|
||||
if (Array.isArray(value)) {
|
||||
searchParams.set(key, value.join(','));
|
||||
} else {
|
||||
searchParams.set(key, String(value));
|
||||
}
|
||||
}
|
||||
|
||||
return await this.sendRequestAsync({
|
||||
method: 'GET',
|
||||
path: `${effectivePath}?${searchParams.toString()}`,
|
||||
path: `${effectivePath}?${new URLSearchParams(body).toString()}`,
|
||||
body,
|
||||
requestSchema: schema.request,
|
||||
responseSchema: schema.response,
|
||||
@@ -353,7 +343,7 @@ export class AscApiClient {
|
||||
|
||||
const json = await response.json();
|
||||
|
||||
this.logger?.debug(`Response from App Store Connect: ${JSON.stringify(json, null, 2)}`);
|
||||
Log.debug(`Response from App Store Connect: ${JSON.stringify(json, null, 2)}`);
|
||||
|
||||
const parsedResponse = await asyncResult((async () => responseSchema.parse(json))());
|
||||
if (!parsedResponse.ok) {
|
||||
-3
@@ -2,9 +2,6 @@ import nock from 'nock';
|
||||
|
||||
import { AscApiClient } from '../AscApiClient';
|
||||
|
||||
// nock needs real fetch implementation
|
||||
jest.unmock('node-fetch');
|
||||
|
||||
describe(AscApiClient, () => {
|
||||
const token = 'test-token';
|
||||
const client = new AscApiClient({ token });
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -57,7 +57,7 @@ describe('update queries', () => {
|
||||
limit: 50,
|
||||
},
|
||||
})
|
||||
).rejects.toThrowError(`No update groups found on branch "${branchName}".`);
|
||||
).rejects.toThrowError(`Unable to select an update in non-interactive mode.`);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -126,18 +126,7 @@ export async function selectRuntimeAndGetLatestUpdateGroupForEachPublishPlatform
|
||||
}
|
||||
): Promise<Record<UpdatePublishPlatform, UpdateFragment[] | undefined>> {
|
||||
if (paginatedQueryOptions.nonInteractive) {
|
||||
const runtimes = await RuntimeQuery.getRuntimesOnBranchAsync(graphqlClient, {
|
||||
appId: projectId,
|
||||
name: branchName,
|
||||
first: RUNTIME_VERSIONS_LIMIT,
|
||||
});
|
||||
if (runtimes.edges.length === 0) {
|
||||
throw new Error(`No runtime versions found on branch "${branchName}".`);
|
||||
}
|
||||
const runtimeList = runtimes.edges.map(e => e.node.version).join('\n ');
|
||||
throw new Error(
|
||||
`Unable to select a runtime in non-interactive mode. Available runtime versions on branch "${branchName}":\n ${runtimeList}`
|
||||
);
|
||||
throw new Error('Unable to select an update in non-interactive mode.');
|
||||
}
|
||||
|
||||
const runtimeVersion = await selectRuntimeOnBranchAsync(graphqlClient, {
|
||||
@@ -189,26 +178,7 @@ export async function selectUpdateGroupOnBranchAsync(
|
||||
}
|
||||
): Promise<UpdateFragment[]> {
|
||||
if (paginatedQueryOptions.nonInteractive) {
|
||||
const updateGroups = await queryUpdateGroupsOnBranchAsync(graphqlClient, {
|
||||
appId: projectId,
|
||||
branchName,
|
||||
limit: paginatedQueryOptions.limit ?? UPDATE_GROUPS_LIMIT,
|
||||
offset: paginatedQueryOptions.offset,
|
||||
});
|
||||
if (updateGroups.length === 0) {
|
||||
throw new Error(`No update groups found on branch "${branchName}".`);
|
||||
}
|
||||
const updateList = updateGroups
|
||||
.map(group => {
|
||||
const first = group[0];
|
||||
return first
|
||||
? `${first.group} (runtime: ${first.runtimeVersion}, message: ${first.message ?? 'N/A'})`
|
||||
: 'unknown';
|
||||
})
|
||||
.join('\n ');
|
||||
throw new Error(
|
||||
`Unable to select an update in non-interactive mode. Use the --group flag to specify the update group. Available update groups on branch "${branchName}":\n ${updateList}`
|
||||
);
|
||||
throw new Error('Unable to select an update in non-interactive mode.');
|
||||
}
|
||||
|
||||
const updateGroup = await paginatedQueryWithSelectPromptAsync({
|
||||
|
||||
@@ -4,8 +4,8 @@ import assert from 'assert';
|
||||
import chalk from 'chalk';
|
||||
import nullthrows from 'nullthrows';
|
||||
|
||||
import { fetchSessionSecretAndSsoUserAsync } from './fetchSessionSecretAndSsoUser';
|
||||
import { fetchSessionSecretAndUserAsync } from './fetchSessionSecretAndUser';
|
||||
import { fetchSessionSecretAndUserFromBrowserAuthFlowAsync } from './fetchSessionSecretAndUserFromBrowserAuthFlow';
|
||||
import { ApiV2Error } from '../ApiV2Error';
|
||||
import { AnalyticsWithOrchestration } from '../analytics/AnalyticsManager';
|
||||
import { ApiV2Client } from '../api';
|
||||
@@ -149,7 +149,6 @@ export default class SessionManager {
|
||||
nonInteractive = false,
|
||||
printNewLine = false,
|
||||
sso = false,
|
||||
browser = false,
|
||||
} = {}): Promise<void> {
|
||||
if (nonInteractive) {
|
||||
Errors.error(
|
||||
@@ -165,8 +164,8 @@ export default class SessionManager {
|
||||
Log.newLine();
|
||||
}
|
||||
|
||||
if (sso || browser) {
|
||||
await this.browserLoginAsync({ sso });
|
||||
if (sso) {
|
||||
await this.ssoLoginAsync();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -206,10 +205,8 @@ export default class SessionManager {
|
||||
}
|
||||
}
|
||||
|
||||
private async browserLoginAsync({ sso = false }): Promise<void> {
|
||||
const { sessionSecret, id, username } = await fetchSessionSecretAndUserFromBrowserAuthFlowAsync(
|
||||
{ sso }
|
||||
);
|
||||
private async ssoLoginAsync(): Promise<void> {
|
||||
const { sessionSecret, id, username } = await fetchSessionSecretAndSsoUserAsync();
|
||||
await this.setSessionAsync({
|
||||
sessionSecret,
|
||||
userId: id,
|
||||
|
||||
@@ -9,8 +9,8 @@ import Log from '../../log';
|
||||
import { promptAsync, selectAsync } from '../../prompts';
|
||||
import { getStateJsonPath } from '../../utils/paths';
|
||||
import SessionManager, { UserSecondFactorDeviceMethod } from '../SessionManager';
|
||||
import { fetchSessionSecretAndSsoUserAsync } from '../fetchSessionSecretAndSsoUser';
|
||||
import { fetchSessionSecretAndUserAsync } from '../fetchSessionSecretAndUser';
|
||||
import { fetchSessionSecretAndUserFromBrowserAuthFlowAsync } from '../fetchSessionSecretAndUserFromBrowserAuthFlow';
|
||||
|
||||
jest.mock('../../prompts');
|
||||
jest.mock('../../log');
|
||||
@@ -25,7 +25,7 @@ jest.mock('../../graphql/queries/UserQuery', () => ({
|
||||
},
|
||||
}));
|
||||
jest.mock('../fetchSessionSecretAndUser');
|
||||
jest.mock('../fetchSessionSecretAndUserFromBrowserAuthFlow');
|
||||
jest.mock('../fetchSessionSecretAndSsoUser');
|
||||
jest.mock('../../api');
|
||||
|
||||
const authStub: any = {
|
||||
@@ -156,15 +156,15 @@ describe(SessionManager, () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('browserLoginAsync', () => {
|
||||
it('saves user data to ~/.expo/state.json with sso', async () => {
|
||||
jest.mocked(fetchSessionSecretAndUserFromBrowserAuthFlowAsync).mockResolvedValue({
|
||||
describe('ssoLoginAsync', () => {
|
||||
it('saves user data to ~/.expo/state.json', async () => {
|
||||
jest.mocked(fetchSessionSecretAndSsoUserAsync).mockResolvedValue({
|
||||
sessionSecret: 'SESSION_SECRET',
|
||||
id: 'USER_ID',
|
||||
username: 'USERNAME',
|
||||
});
|
||||
const sessionManager = new SessionManager(analytics);
|
||||
await sessionManager['browserLoginAsync']({ sso: true });
|
||||
await sessionManager['ssoLoginAsync']();
|
||||
expect(await fs.readFile(getStateJsonPath(), 'utf8')).toMatchInlineSnapshot(`
|
||||
"{
|
||||
"auth": {
|
||||
@@ -176,31 +176,6 @@ describe(SessionManager, () => {
|
||||
}
|
||||
"
|
||||
`);
|
||||
expect(fetchSessionSecretAndUserFromBrowserAuthFlowAsync).toHaveBeenCalledWith({ sso: true });
|
||||
});
|
||||
|
||||
it('saves user data to ~/.expo/state.json without sso', async () => {
|
||||
jest.mocked(fetchSessionSecretAndUserFromBrowserAuthFlowAsync).mockResolvedValue({
|
||||
sessionSecret: 'SESSION_SECRET',
|
||||
id: 'USER_ID',
|
||||
username: 'USERNAME',
|
||||
});
|
||||
const sessionManager = new SessionManager(analytics);
|
||||
await sessionManager['browserLoginAsync']({ sso: false });
|
||||
expect(await fs.readFile(getStateJsonPath(), 'utf8')).toMatchInlineSnapshot(`
|
||||
"{
|
||||
"auth": {
|
||||
"sessionSecret": "SESSION_SECRET",
|
||||
"userId": "USER_ID",
|
||||
"username": "USERNAME",
|
||||
"currentConnection": "Browser-Flow-Authentication"
|
||||
}
|
||||
}
|
||||
"
|
||||
`);
|
||||
expect(fetchSessionSecretAndUserFromBrowserAuthFlowAsync).toHaveBeenCalledWith({
|
||||
sso: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -317,18 +292,7 @@ describe(SessionManager, () => {
|
||||
// SSO login
|
||||
await sessionManager.showLoginPromptAsync({ sso: true });
|
||||
expect(promptAsync).not.toHaveBeenCalled();
|
||||
expect(fetchSessionSecretAndUserFromBrowserAuthFlowAsync).toHaveBeenCalledWith({ sso: true });
|
||||
});
|
||||
|
||||
it('calls browser login if the browser flag is true', async () => {
|
||||
const sessionManager = new SessionManager(analytics);
|
||||
|
||||
// Browser login (not SSO)
|
||||
await sessionManager.showLoginPromptAsync({ browser: true });
|
||||
expect(promptAsync).not.toHaveBeenCalled();
|
||||
expect(fetchSessionSecretAndUserFromBrowserAuthFlowAsync).toHaveBeenCalledWith({
|
||||
sso: false,
|
||||
});
|
||||
expect(fetchSessionSecretAndSsoUserAsync).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
+51
-23
@@ -4,22 +4,53 @@ import http from 'http';
|
||||
import { Socket } from 'node:net';
|
||||
import querystring from 'querystring';
|
||||
|
||||
import { getExpoWebsiteBaseUrl } from '../api';
|
||||
import Log from '../log';
|
||||
|
||||
export async function getSessionUsingBrowserAuthFlowAsync({ sso = false }): Promise<string> {
|
||||
const successBody = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Expo SSO Login</title>
|
||||
<meta charset="utf-8">
|
||||
<style type="text/css">
|
||||
html {
|
||||
margin: 0;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #fff;
|
||||
font-family: Tahoma,Verdana;
|
||||
font-size: 16px;
|
||||
color: #000;
|
||||
max-width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: .5rem;
|
||||
margin: 1em;
|
||||
overflow-wrap: break-word
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
SSO login complete. You may now close this tab and return to the command prompt.
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
export async function getSessionUsingBrowserAuthFlowAsync({
|
||||
expoWebsiteUrl,
|
||||
}: {
|
||||
expoWebsiteUrl: string;
|
||||
}): Promise<string> {
|
||||
const scheme = 'http';
|
||||
const hostname = 'localhost';
|
||||
const path = '/auth/callback';
|
||||
|
||||
const expoWebsiteUrl = getExpoWebsiteBaseUrl();
|
||||
|
||||
const buildExpoLoginUrl = (port: number, sso: boolean): string => {
|
||||
const params = querystring.stringify({
|
||||
confirm_account: true,
|
||||
const buildExpoSsoLoginUrl = (port: number): string => {
|
||||
const data = {
|
||||
app_redirect_uri: `${scheme}://${hostname}:${port}${path}`,
|
||||
});
|
||||
return `${expoWebsiteUrl}${sso ? '/sso-login' : '/login'}?${params}`;
|
||||
};
|
||||
const params = querystring.stringify(data);
|
||||
return `${expoWebsiteUrl}/sso-login?${params}`;
|
||||
};
|
||||
|
||||
// Start server and begin auth flow
|
||||
@@ -29,19 +60,9 @@ export async function getSessionUsingBrowserAuthFlowAsync({ sso = false }): Prom
|
||||
|
||||
const server = http.createServer(
|
||||
(request: http.IncomingMessage, response: http.ServerResponse) => {
|
||||
const redirectAndCleanup = (result: 'success' | 'error'): void => {
|
||||
const redirectUrl = `${expoWebsiteUrl}/oauth/expo-cli?result=${result}`;
|
||||
response.writeHead(302, { Location: redirectUrl });
|
||||
response.end();
|
||||
server.close();
|
||||
for (const connection of connections) {
|
||||
connection.destroy();
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
if (!(request.method === 'GET' && request.url?.includes('/auth/callback'))) {
|
||||
throw new Error('Unexpected login response.');
|
||||
throw new Error('Unexpected SSO login response.');
|
||||
}
|
||||
const url = new URL(request.url, `http:${request.headers.host}`);
|
||||
const sessionSecret = url.searchParams.get('session_secret');
|
||||
@@ -50,10 +71,17 @@ export async function getSessionUsingBrowserAuthFlowAsync({ sso = false }): Prom
|
||||
throw new Error('Request missing session_secret search parameter.');
|
||||
}
|
||||
resolve(sessionSecret);
|
||||
redirectAndCleanup('success');
|
||||
response.writeHead(200, { 'Content-Type': 'text/html' });
|
||||
response.write(successBody);
|
||||
response.end();
|
||||
} catch (error) {
|
||||
redirectAndCleanup('error');
|
||||
reject(error);
|
||||
} finally {
|
||||
server.close();
|
||||
// Ensure that the server shuts down
|
||||
for (const connection of connections) {
|
||||
connection.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -67,7 +95,7 @@ export async function getSessionUsingBrowserAuthFlowAsync({ sso = false }): Prom
|
||||
'Server address and port should be set after listening has begun'
|
||||
);
|
||||
const port = address.port;
|
||||
const authorizeUrl = buildExpoLoginUrl(port, sso);
|
||||
const authorizeUrl = buildExpoSsoLoginUrl(port);
|
||||
Log.log(
|
||||
`If your browser doesn't automatically open, visit this link to log in: ${authorizeUrl}`
|
||||
);
|
||||
+6
-3
@@ -1,12 +1,15 @@
|
||||
import { getSessionUsingBrowserAuthFlowAsync } from './expoBrowserAuthFlowLauncher';
|
||||
import { getSessionUsingBrowserAuthFlowAsync } from './expoSsoLauncher';
|
||||
import { fetchUserAsync } from './fetchUser';
|
||||
import { getExpoWebsiteBaseUrl } from '../api';
|
||||
|
||||
export async function fetchSessionSecretAndUserFromBrowserAuthFlowAsync({ sso = false }): Promise<{
|
||||
export async function fetchSessionSecretAndSsoUserAsync(): Promise<{
|
||||
sessionSecret: string;
|
||||
id: string;
|
||||
username: string;
|
||||
}> {
|
||||
const sessionSecret = await getSessionUsingBrowserAuthFlowAsync({ sso });
|
||||
const sessionSecret = await getSessionUsingBrowserAuthFlowAsync({
|
||||
expoWebsiteUrl: getExpoWebsiteBaseUrl(),
|
||||
});
|
||||
|
||||
const userData = await fetchUserAsync({ sessionSecret });
|
||||
|
||||
@@ -31,9 +31,7 @@ export async function promptVariableTypeAsync(
|
||||
initialType?: EnvironmentSecretType
|
||||
): Promise<EnvironmentSecretType> {
|
||||
if (nonInteractive) {
|
||||
throw new Error(
|
||||
'The `--type` flag must be set when running in `--non-interactive` mode. Valid values: string, file.'
|
||||
);
|
||||
throw new Error('The `--type` flag must be set when running in `--non-interactive` mode.');
|
||||
}
|
||||
|
||||
const options = [
|
||||
@@ -91,7 +89,7 @@ export async function promptVariableVisibilityAsync(
|
||||
): Promise<EnvironmentVariableVisibility> {
|
||||
if (nonInteractive) {
|
||||
throw new Error(
|
||||
'The `--visibility` flag must be set when running in `--non-interactive` mode. Valid values: plaintext, sensitive, secret.'
|
||||
'The `--visibility` flag must be set when running in `--non-interactive` mode.'
|
||||
);
|
||||
}
|
||||
return await selectAsync('Select visibility:', [
|
||||
@@ -138,9 +136,7 @@ export async function promptVariableEnvironmentAsync({
|
||||
}: EnvironmentPromptArgs & { multiple?: boolean }): Promise<string[] | string> {
|
||||
if (nonInteractive) {
|
||||
throw new Error(
|
||||
`The \`--environment\` flag must be set when running in \`--non-interactive\` mode. Default environments: ${DEFAULT_ENVIRONMENTS.join(
|
||||
', '
|
||||
)}.`
|
||||
'The `--environment` flag must be set when running in `--non-interactive` mode.'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -255,27 +255,4 @@ describe('displayOverageWarning', () => {
|
||||
expect.objectContaining({ text: 'Upgrade your plan to continue service.' })
|
||||
);
|
||||
});
|
||||
|
||||
it('shows progress bar when usage is under 100%', () => {
|
||||
displayOverageWarning({
|
||||
percentUsed: 85,
|
||||
hasFreePlan: true,
|
||||
name: 'test-account',
|
||||
});
|
||||
|
||||
expect(mockWarn).toHaveBeenCalledWith(expect.stringMatching(/█+░+/));
|
||||
});
|
||||
|
||||
it('does not show progress bar when usage is at 100%', () => {
|
||||
displayOverageWarning({
|
||||
percentUsed: 100,
|
||||
hasFreePlan: true,
|
||||
name: 'test-account',
|
||||
});
|
||||
|
||||
expect(mockWarn).toHaveBeenCalledWith(
|
||||
expect.stringContaining("You've used 100% of your included build credits for this month.")
|
||||
);
|
||||
expect(mockWarn).not.toHaveBeenCalledWith(expect.stringMatching(/[█░]/));
|
||||
});
|
||||
});
|
||||
@@ -61,12 +61,10 @@ export function displayOverageWarning({
|
||||
hasFreePlan: boolean;
|
||||
name: string;
|
||||
}): void {
|
||||
const message = chalk.bold(
|
||||
`You've used ${percentUsed}% of your included build credits for this month.`
|
||||
Log.warn(
|
||||
chalk.bold(`You've used ${percentUsed}% of your included build credits for this month. `) +
|
||||
createProgressBar(percentUsed)
|
||||
);
|
||||
// Don't show progress bar at 100% - it's redundant when the limit is reached
|
||||
const progressBar = percentUsed < 100 ? ' ' + createProgressBar(percentUsed) : '';
|
||||
Log.warn(message + progressBar);
|
||||
|
||||
const billingUrl = `https://expo.dev/accounts/${name}/settings/billing`;
|
||||
const warning = hasFreePlan
|
||||
|
||||
@@ -31,11 +31,7 @@ export default class GitClient extends Client {
|
||||
this.requireCommit = options.requireCommit;
|
||||
}
|
||||
|
||||
public override async ensureRepoExistsAsync(options?: {
|
||||
nonInteractive?: boolean;
|
||||
}): Promise<void> {
|
||||
const nonInteractive = options?.nonInteractive ?? false;
|
||||
|
||||
public override async ensureRepoExistsAsync(): Promise<void> {
|
||||
try {
|
||||
if (!(await isGitInstalledAsync())) {
|
||||
Log.error(
|
||||
@@ -70,26 +66,11 @@ export default class GitClient extends Client {
|
||||
return;
|
||||
}
|
||||
|
||||
const cwd = process.cwd();
|
||||
const repoRoot = PackageManagerUtils.resolveWorkspaceRoot(cwd) ?? cwd;
|
||||
|
||||
if (nonInteractive) {
|
||||
Log.log(
|
||||
`No git repository found. Auto initializing in ${this.maybeCwdOverride ?? repoRoot}. ` +
|
||||
`Set ${chalk.bold('EAS_NO_VCS=1')} to skip.`
|
||||
);
|
||||
await spawnAsync('git', ['init'], { cwd: this.maybeCwdOverride ?? repoRoot });
|
||||
await this.commitAsync({
|
||||
commitAllFiles: true,
|
||||
commitMessage: 'Initial commit',
|
||||
nonInteractive: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Log.warn("It looks like you haven't initialized the git repository yet.");
|
||||
Log.warn('EAS requires you to use a git repository for your project.');
|
||||
|
||||
const cwd = process.cwd();
|
||||
const repoRoot = PackageManagerUtils.resolveWorkspaceRoot(cwd) ?? cwd;
|
||||
const confirmInit = await confirmAsync({
|
||||
message: `Would you like us to run 'git init' in ${
|
||||
this.maybeCwdOverride ?? repoRoot
|
||||
@@ -438,22 +419,16 @@ export default class GitClient extends Client {
|
||||
return;
|
||||
}
|
||||
|
||||
const missingConfig = [
|
||||
!usernameConfigured && 'username (user.name)',
|
||||
!emailConfigured && 'email address (user.email)',
|
||||
].filter(i => i);
|
||||
|
||||
Log.warn(`You need to configure Git with your ${missingConfig.join(' and ')}`);
|
||||
if (nonInteractive) {
|
||||
const configCommands = [
|
||||
!usernameConfigured && 'git config --global user.name "Your Name"',
|
||||
!emailConfigured && 'git config --global user.email "[email protected]"',
|
||||
Log.warn(
|
||||
`You need to configure Git with your ${[
|
||||
!usernameConfigured && 'username (user.name)',
|
||||
!emailConfigured && 'email address (user.email)',
|
||||
]
|
||||
.filter(i => i)
|
||||
.join(' && ');
|
||||
throw new Error(
|
||||
`Git ${missingConfig.join(' and ')} must be configured. Run: ${configCommands}`
|
||||
);
|
||||
.join(' and ')}`
|
||||
);
|
||||
if (nonInteractive) {
|
||||
throw new Error('Git cannot be configured automatically in non-interactive mode');
|
||||
}
|
||||
if (!usernameConfigured) {
|
||||
const { username } = await promptAsync({
|
||||
|
||||
@@ -14,7 +14,7 @@ export abstract class Client {
|
||||
|
||||
// (optional) ensureRepoExistsAsync should verify whether repository exists and tooling is installed
|
||||
// it's not required for minimal support, but lack of validation might cause the failure at a later stage.
|
||||
public async ensureRepoExistsAsync(_options?: { nonInteractive?: boolean }): Promise<void> {}
|
||||
public async ensureRepoExistsAsync(): Promise<void> {}
|
||||
|
||||
// (optional) checks whether commit is necessary before calling makeShallowCopyAsync
|
||||
//
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import type { Config } from '@jest/types';
|
||||
import type { Config } from 'jest';
|
||||
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import baseConfig from '../../jest/jest.shared.config';
|
||||
import baseConfig from '../../jest/jest.config';
|
||||
|
||||
const config: Config.InitialOptions = {
|
||||
const config: Config = {
|
||||
...baseConfig,
|
||||
rootDir: __dirname,
|
||||
roots: ['src', '__mocks__'],
|
||||
testRegex: '/__tests__/.*(test|spec)\\.[jt]sx?$',
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@expo/eas-json",
|
||||
"description": "A library for interacting with eas.json",
|
||||
"version": "17.0.0",
|
||||
"version": "16.30.0",
|
||||
"author": "Expo <[email protected]>",
|
||||
"bugs": "https://github.com/expo/eas-cli/issues",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "7.23.5",
|
||||
"@expo/eas-build-job": "17.0.0",
|
||||
"@expo/eas-build-job": "1.0.265",
|
||||
"chalk": "4.1.2",
|
||||
"env-string": "1.0.1",
|
||||
"fs-extra": "11.2.0",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"url": "https://github.com/expo/eas-cli.git",
|
||||
"directory": "packages/local-build-plugin"
|
||||
},
|
||||
"version": "17.0.0",
|
||||
"version": "1.0.272",
|
||||
"description": "Tool for running EAS compatible builds on a local machine.",
|
||||
"main": "dist/main.js",
|
||||
"files": [
|
||||
@@ -21,7 +21,6 @@
|
||||
"build": "tsc",
|
||||
"typecheck": "tsc",
|
||||
"prepack": "rm -rf dist && tsc -p tsconfig.build.json",
|
||||
"test": "jest --passWithNoTests",
|
||||
"clean": "rm -rf node_modules dist coverage *.tsbuildinfo"
|
||||
},
|
||||
"engines": {
|
||||
@@ -31,11 +30,11 @@
|
||||
"bugs": "https://github.com/expo/eas-cli/issues",
|
||||
"license": "BUSL-1.1",
|
||||
"dependencies": {
|
||||
"@expo/build-tools": "17.0.0",
|
||||
"@expo/eas-build-job": "17.0.0",
|
||||
"@expo/logger": "17.0.0",
|
||||
"@expo/build-tools": "1.0.272",
|
||||
"@expo/eas-build-job": "1.0.265",
|
||||
"@expo/logger": "1.0.260",
|
||||
"@expo/spawn-async": "^1.7.2",
|
||||
"@expo/turtle-spawn": "17.0.0",
|
||||
"@expo/turtle-spawn": "1.0.260",
|
||||
"bunyan": "^1.8.15",
|
||||
"chalk": "4.1.2",
|
||||
"env-paths": "^2.2.1",
|
||||
@@ -44,7 +43,7 @@
|
||||
"lodash": "^4.17.21",
|
||||
"nullthrows": "^1.1.1",
|
||||
"semver": "^7.6.2",
|
||||
"tar": "7.5.7",
|
||||
"tar": "^7.2.0",
|
||||
"uuid": "^9.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -57,5 +56,9 @@
|
||||
"jest": "^29.7.0",
|
||||
"ts-jest": "^29.1.4",
|
||||
"typescript": "^5.5.4"
|
||||
},
|
||||
"volta": {
|
||||
"node": "20.14.0",
|
||||
"yarn": "1.22.21"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
rootDir: 'src',
|
||||
testMatch: ['**/__tests__/*.test.ts'],
|
||||
clearMocks: true,
|
||||
setupFilesAfterEnv: ['<rootDir>/../jest/setup-tests.ts'],
|
||||
};
|
||||
@@ -1,14 +0,0 @@
|
||||
import type { Config } from '@jest/types';
|
||||
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import baseConfig from '../../jest/jest.shared.config';
|
||||
|
||||
const config: Config.InitialOptions = {
|
||||
...baseConfig,
|
||||
rootDir: 'src',
|
||||
testMatch: ['**/__tests__/*.test.ts'],
|
||||
clearMocks: true,
|
||||
setupFilesAfterEnv: ['<rootDir>/../jest/setup-tests.ts'],
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -5,7 +5,7 @@
|
||||
"url": "https://github.com/expo/eas-cli.git",
|
||||
"directory": "packages/logger"
|
||||
},
|
||||
"version": "17.0.0",
|
||||
"version": "1.0.260",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
@@ -17,8 +17,8 @@
|
||||
"build": "tsc",
|
||||
"typecheck": "tsc",
|
||||
"prepack": "rm -rf dist && tsc -p tsconfig.build.json",
|
||||
"test": "jest --config jest.config.ts --passWithNoTests",
|
||||
"test:watch": "jest --config jest.config.ts --watch",
|
||||
"test": "jest --config jest.config.js --passWithNoTests",
|
||||
"test:watch": "jest --config jest.config.js --watch",
|
||||
"clean": "rm -rf node_modules dist coverage *.tsbuildinfo"
|
||||
},
|
||||
"author": "Expo <[email protected]>",
|
||||
@@ -34,5 +34,9 @@
|
||||
"jest": "^29.7.0",
|
||||
"ts-jest": "^29.1.4",
|
||||
"typescript": "^5.5.4"
|
||||
},
|
||||
"volta": {
|
||||
"node": "20.14.0",
|
||||
"yarn": "1.22.21"
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,6 @@
|
||||
import type { Config } from '@jest/types';
|
||||
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import baseConfig from '../../jest/jest.shared.config';
|
||||
|
||||
const config: Config.InitialOptions = {
|
||||
...baseConfig,
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
rootDir: 'src',
|
||||
testMatch: ['**/__tests__/*-test.ts'],
|
||||
coverageReporters: ['json', 'lcov'],
|
||||
@@ -13,5 +9,3 @@ const config: Config.InitialOptions = {
|
||||
clearMocks: true,
|
||||
setupFilesAfterEnv: ['<rootDir>/../jest/setup-tests.ts'],
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -5,7 +5,7 @@
|
||||
"url": "https://github.com/expo/eas-cli.git",
|
||||
"directory": "packages/steps"
|
||||
},
|
||||
"version": "17.0.0",
|
||||
"version": "1.0.271",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
@@ -18,8 +18,8 @@
|
||||
"typecheck": "tsc",
|
||||
"prepack": "rm -rf dist && tsc --project tsconfig.build.json",
|
||||
"watch": "tsc --watch --preserveWatchOutput",
|
||||
"test": "jest --config jest.config.ts",
|
||||
"test:coverage": "jest --config jest.config.ts --coverage",
|
||||
"test": "jest --config jest.config.cjs",
|
||||
"test:coverage": "jest --config jest.config.cjs --coverage",
|
||||
"test:watch": "yarn test --watch",
|
||||
"clean": "rm -rf node_modules dist coverage *.tsbuildinfo"
|
||||
},
|
||||
@@ -43,8 +43,8 @@
|
||||
"node": ">=18"
|
||||
},
|
||||
"dependencies": {
|
||||
"@expo/eas-build-job": "17.0.0",
|
||||
"@expo/logger": "17.0.0",
|
||||
"@expo/eas-build-job": "1.0.265",
|
||||
"@expo/logger": "1.0.260",
|
||||
"@expo/spawn-async": "^1.7.2",
|
||||
"arg": "^5.0.2",
|
||||
"fs-extra": "^11.2.0",
|
||||
@@ -54,5 +54,9 @@
|
||||
"lodash.get": "^4.4.2",
|
||||
"uuid": "^9.0.1",
|
||||
"yaml": "^2.4.3"
|
||||
},
|
||||
"volta": {
|
||||
"node": "20.14.0",
|
||||
"yarn": "1.22.21"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
rootDir: 'src',
|
||||
testMatch: ['**/__tests__/*.test.ts'],
|
||||
clearMocks: true,
|
||||
setupFilesAfterEnv: ['<rootDir>/../jest/setup-tests.ts'],
|
||||
};
|
||||
@@ -1,14 +0,0 @@
|
||||
import type { Config } from '@jest/types';
|
||||
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import baseConfig from '../../jest/jest.shared.config';
|
||||
|
||||
const config: Config.InitialOptions = {
|
||||
...baseConfig,
|
||||
rootDir: 'src',
|
||||
testMatch: ['**/__tests__/*.test.ts'],
|
||||
clearMocks: true,
|
||||
setupFilesAfterEnv: ['<rootDir>/../jest/setup-tests.ts'],
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -5,7 +5,7 @@
|
||||
"url": "https://github.com/expo/eas-cli.git",
|
||||
"directory": "packages/template-file"
|
||||
},
|
||||
"version": "17.0.0",
|
||||
"version": "1.0.260",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
@@ -17,8 +17,8 @@
|
||||
"build": "tsc",
|
||||
"typecheck": "tsc",
|
||||
"prepack": "rm -rf dist && tsc -p tsconfig.build.json",
|
||||
"test": "jest --config jest.config.ts",
|
||||
"test:watch": "jest --config jest.config.ts --watch",
|
||||
"test": "jest --config jest.config.js",
|
||||
"test:watch": "jest --config jest.config.js --watch",
|
||||
"clean": "rm -rf node_modules dist coverage *.tsbuildinfo"
|
||||
},
|
||||
"author": "Expo <[email protected]>",
|
||||
@@ -35,5 +35,9 @@
|
||||
"jest": "^29.7.0",
|
||||
"ts-jest": "^29.1.4",
|
||||
"typescript": "^5.5.4"
|
||||
},
|
||||
"volta": {
|
||||
"node": "20.14.0",
|
||||
"yarn": "1.22.21"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
rootDir: 'src',
|
||||
testMatch: ['**/__tests__/*.test.ts'],
|
||||
clearMocks: true,
|
||||
setupFilesAfterEnv: ['<rootDir>/../jest/setup-tests.ts'],
|
||||
};
|
||||
@@ -1,14 +0,0 @@
|
||||
import type { Config } from '@jest/types';
|
||||
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import baseConfig from '../../jest/jest.shared.config';
|
||||
|
||||
const config: Config.InitialOptions = {
|
||||
...baseConfig,
|
||||
rootDir: 'src',
|
||||
testMatch: ['**/__tests__/*.test.ts'],
|
||||
clearMocks: true,
|
||||
setupFilesAfterEnv: ['<rootDir>/../jest/setup-tests.ts'],
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -5,7 +5,7 @@
|
||||
"url": "https://github.com/expo/eas-cli.git",
|
||||
"directory": "packages/turtle-spawn"
|
||||
},
|
||||
"version": "17.0.0",
|
||||
"version": "1.0.260",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
@@ -17,15 +17,15 @@
|
||||
"build": "tsc",
|
||||
"typecheck": "tsc",
|
||||
"prepack": "rm -rf dist && tsc -p tsconfig.build.json",
|
||||
"test": "jest --config jest.config.ts --passWithNoTests",
|
||||
"test:watch": "jest --config jest.config.ts --watch",
|
||||
"test": "jest --config jest.config.js --passWithNoTests",
|
||||
"test:watch": "jest --config jest.config.js --watch",
|
||||
"clean": "rm -rf node_modules dist coverage *.tsbuildinfo"
|
||||
},
|
||||
"author": "Expo <[email protected]>",
|
||||
"bugs": "https://github.com/expo/eas-cli/issues",
|
||||
"license": "BUSL-1.1",
|
||||
"dependencies": {
|
||||
"@expo/logger": "17.0.0",
|
||||
"@expo/logger": "1.0.260",
|
||||
"@expo/spawn-async": "^1.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -34,5 +34,9 @@
|
||||
"jest": "^29.7.0",
|
||||
"ts-jest": "^29.1.4",
|
||||
"typescript": "^5.5.4"
|
||||
},
|
||||
"volta": {
|
||||
"node": "20.14.0",
|
||||
"yarn": "1.22.21"
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,6 @@ jobs:
|
||||
steps:
|
||||
- uses: eas/checkout
|
||||
|
||||
- uses: eas/install_node_modules
|
||||
|
||||
- name: Build Android worker tarball
|
||||
run: ./package.sh worker-android.tar.gz android
|
||||
|
||||
@@ -35,8 +33,6 @@ jobs:
|
||||
steps:
|
||||
- uses: eas/checkout
|
||||
|
||||
- uses: eas/install_node_modules
|
||||
|
||||
- name: Build iOS worker tarball
|
||||
run: ./package.sh worker-ios.tar.gz ios
|
||||
|
||||
|
||||
@@ -5,3 +5,5 @@ export PORT="3005"
|
||||
export WORKER_PORT="3005"
|
||||
export WORKER_IP="localhost"
|
||||
export LOGGER_LEVEL="debug"
|
||||
|
||||
unset _VOLTA_TOOL_RECURSION
|
||||
+3
-9
@@ -1,10 +1,6 @@
|
||||
import type { Config } from '@jest/types';
|
||||
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import baseConfig from '../../jest/jest.shared.config';
|
||||
|
||||
const config: Config.InitialOptions = {
|
||||
...baseConfig,
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
rootDir: 'src',
|
||||
testMatch: ['**/__integration__/*.test.ts'],
|
||||
collectCoverage: true,
|
||||
@@ -17,5 +13,3 @@ const config: Config.InitialOptions = {
|
||||
// WebSocket cleanup timing) may keep handles open that prevent clean exit.
|
||||
forceExit: true,
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -1,14 +1,10 @@
|
||||
import type { Config } from '@jest/types';
|
||||
import type { Config } from 'jest';
|
||||
|
||||
// eslint-disable-next-line import/no-relative-packages
|
||||
import baseConfig from '../../jest/jest.shared.config';
|
||||
|
||||
const config: Config.InitialOptions = {
|
||||
...baseConfig,
|
||||
export default {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
rootDir: __dirname,
|
||||
testMatch: ['**/__unit__/*.test.ts'],
|
||||
clearMocks: true,
|
||||
setupFilesAfterEnv: ['./jest/unit-setup.ts'],
|
||||
};
|
||||
|
||||
export default config;
|
||||
} satisfies Config;
|
||||
@@ -9,10 +9,6 @@ process.env.WORKER_RUNTIME_CONFIG_BASE64 = 'eyAiaW1hZ2UiOiAiIiB9'; // { "image":
|
||||
process.env.__API_SERVER_URL = 'http://api.expo.test';
|
||||
process.env.PORT = '3015';
|
||||
|
||||
jest.mock('fs');
|
||||
jest.mock('fs/promises');
|
||||
jest.mock('node:fs', () => jest.requireMock('fs'));
|
||||
|
||||
// Always mock:
|
||||
jest.mock('@expo/build-tools', () => {
|
||||
return {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@expo/worker",
|
||||
"version": "17.0.0",
|
||||
"version": "16.32.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "yarn watch",
|
||||
@@ -13,8 +13,8 @@
|
||||
"test": "yarn test:unit",
|
||||
"test:unit": "./resources/jest --config jest.config.unit.ts",
|
||||
"test:unit:watch": "./resources/jest --config jest.config.unit.ts --watch",
|
||||
"test:integration": "./resources/jest --runInBand --config jest.config.integration.ts",
|
||||
"test:integration:watch": "./resources/jest --runInBand --config jest.config.integration.ts --watchAll",
|
||||
"test:integration": "./resources/jest --runInBand --config jest.config.integration.js",
|
||||
"test:integration:watch": "./resources/jest --runInBand --config jest.config.integration.js --watchAll",
|
||||
"typecheck": "tsc"
|
||||
},
|
||||
"engines": {
|
||||
@@ -22,18 +22,18 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/core": "7.24.7",
|
||||
"@expo/build-tools": "17.0.0",
|
||||
"@expo/build-tools": "1.0.272",
|
||||
"@expo/config-plugins": "8.0.8",
|
||||
"@expo/config-types": "52.0.1",
|
||||
"@expo/downloader": "17.0.0",
|
||||
"@expo/eas-build-job": "17.0.0",
|
||||
"@expo/logger": "17.0.0",
|
||||
"@expo/downloader": "1.0.260",
|
||||
"@expo/eas-build-job": "1.0.265",
|
||||
"@expo/logger": "1.0.260",
|
||||
"@expo/results": "1.0.0",
|
||||
"@expo/rudder-sdk-node": "1.1.1",
|
||||
"@expo/spawn-async": "1.7.2",
|
||||
"@expo/steps": "17.0.0",
|
||||
"@expo/template-file": "17.0.0",
|
||||
"@expo/turtle-spawn": "17.0.0",
|
||||
"@expo/steps": "1.0.271",
|
||||
"@expo/template-file": "1.0.260",
|
||||
"@expo/turtle-spawn": "1.0.260",
|
||||
"@hapi/boom": "10.0.1",
|
||||
"@sentry/node": "7.77.0",
|
||||
"check-disk-space": "3.4.0",
|
||||
@@ -50,7 +50,7 @@
|
||||
"node-os-utils": "1.3.7",
|
||||
"nullthrows": "1.1.1",
|
||||
"semver": "7.6.3",
|
||||
"tar": "7.5.7",
|
||||
"tar": "6.2.1",
|
||||
"uuid": "3.4.0",
|
||||
"ws": "8.18.0",
|
||||
"xml2js": "0.6.2",
|
||||
|
||||
@@ -33,16 +33,9 @@ copy_package() {
|
||||
dst=$2
|
||||
mkdir -p $dst
|
||||
cp "$src/package.json" "$dst/package.json"
|
||||
if [[ -f "$src/tsconfig.json" ]]; then
|
||||
cp "$src/tsconfig.json" "$dst/tsconfig.json"
|
||||
fi
|
||||
if [[ -f "$src/tsconfig.build.json" ]]; then
|
||||
cp "$src/tsconfig.build.json" "$dst/tsconfig.build.json"
|
||||
fi
|
||||
cp "$src/tsconfig.json" "$dst/tsconfig.json"
|
||||
cp "$src/tsconfig.build.json" "$dst/tsconfig.build.json"
|
||||
cp -r "$src/src" "$dst/src"
|
||||
if [[ -d "$src/bin" ]]; then
|
||||
cp -r "$src/bin" "$dst/bin"
|
||||
fi
|
||||
}
|
||||
|
||||
cp "$ROOT_DIR/yarn.lock" $target_root_dir
|
||||
@@ -50,16 +43,11 @@ cp "$ROOT_DIR/package.json" $target_root_dir
|
||||
cp "$ROOT_DIR/lerna.json" $target_root_dir
|
||||
|
||||
copy_package $WORKER_DIR $target_worker_dir
|
||||
while IFS= read -r package_dir; do
|
||||
package_name=$(basename "$package_dir")
|
||||
copy_package "$package_dir" "$target_root_dir/packages/$package_name"
|
||||
done <<< "$(yarn --silent lerna list --scope "@expo/worker" --include-dependencies --parseable --loglevel silent)"
|
||||
|
||||
|
||||
pushd $target_root_dir >/dev/null 2>&1
|
||||
yarn install --silent --frozen-lockfile
|
||||
yarn install --silent
|
||||
yarn build
|
||||
yarn install --silent --production=true --frozen-lockfile
|
||||
yarn install --silent --production=true
|
||||
rm -rf tsconfig.json tsconfig.build.json
|
||||
popd >/dev/null 2>&1
|
||||
|
||||
@@ -77,6 +65,7 @@ if [[ "$PLATFORM" == "ios" ]]; then
|
||||
mv expo-cocoapods-proxy-*.gem "$target_worker_dir/expo-cocoapods-proxy.gem"
|
||||
popd >/dev/null 2>&1
|
||||
fi
|
||||
rm -rf $target_root_dir/.volta/
|
||||
|
||||
# Create backward-compatible symlink for orchestrator
|
||||
# The orchestrator expects ./src/services/worker/dist/main.js
|
||||
|
||||
@@ -4,7 +4,7 @@ import { BuildJob } from '@expo/eas-build-job';
|
||||
import filesize from 'filesize';
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
import * as tar from 'tar';
|
||||
import tar from 'tar';
|
||||
|
||||
import config from './config';
|
||||
|
||||
@@ -87,7 +87,7 @@ export class GCSCacheManager implements CacheManager {
|
||||
this.skipCacheUpdate = true; // if restore failed we don't want to update cache with new values
|
||||
return;
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
await tar.extract(
|
||||
{
|
||||
file: archivePath,
|
||||
|
||||
@@ -3,18 +3,13 @@ import downloadFile from '@expo/downloader';
|
||||
import { Cache, Platform } from '@expo/eas-build-job';
|
||||
import { randomUUID } from 'crypto';
|
||||
import fs from 'fs-extra';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import { vol } from 'memfs';
|
||||
import { Readable } from 'stream';
|
||||
|
||||
// These tests use real fs and directories in os.tmpdir().
|
||||
// Something about tar v7 makes mocking fs with memfs problematic.
|
||||
// Mocking all variants of fs/node:fs/fs/promises does not help.
|
||||
// Last Codex research indicated it might be something related to fs-minipass
|
||||
// and fs.writev, mocking fs.writev did not help though.
|
||||
jest.unmock('fs');
|
||||
jest.unmock('node:fs');
|
||||
import { GCSCacheManager } from '../CacheManager';
|
||||
|
||||
jest.mock('fs');
|
||||
jest.mock('fs/promises');
|
||||
jest.mock('@expo/downloader', () => {
|
||||
return jest.fn();
|
||||
});
|
||||
@@ -28,67 +23,59 @@ jest.mock('../sentry', () => ({
|
||||
handleError: jest.fn(),
|
||||
}));
|
||||
|
||||
const { GCSCacheManager } = require('../CacheManager');
|
||||
|
||||
describe(GCSCacheManager, () => {
|
||||
let tmpDir: string;
|
||||
let outsideDir: string;
|
||||
beforeEach(async () => {
|
||||
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'eas-cli-test-'));
|
||||
outsideDir = await fs.mkdtemp(path.join(os.tmpdir(), 'eas-cli-outside-test-'));
|
||||
async function saveAndRestoreCacheAsync(
|
||||
setupBeforeSave: () => Promise<void> | void,
|
||||
setupBeforeRestore: () => Promise<void> | void,
|
||||
cacheConfig: Partial<Cache>
|
||||
): Promise<void> {
|
||||
await setupBeforeSave();
|
||||
const manager = new GCSCacheManager();
|
||||
const mockCtx = {
|
||||
logger: { info: jest.fn(), error: console.error },
|
||||
workingdir: '/projectRoot',
|
||||
buildDirectory: '/projectRoot/build',
|
||||
job: {
|
||||
platform: Platform.ANDROID,
|
||||
projectRootDirectory: '.',
|
||||
cache: cacheConfig,
|
||||
},
|
||||
} as any;
|
||||
let tarReadStream: Readable;
|
||||
jest.mocked(GCS.uploadWithSignedUrl).mockImplementation(async ({ srcGeneratorAsync }) => {
|
||||
const result = await srcGeneratorAsync();
|
||||
tarReadStream = result;
|
||||
return randomUUID();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await fs.rm(tmpDir, { recursive: true, force: true });
|
||||
await fs.rm(outsideDir, { recursive: true, force: true });
|
||||
await manager.saveCache(mockCtx);
|
||||
const chunks = [];
|
||||
for await (const chunk of tarReadStream!) {
|
||||
chunks.push(chunk);
|
||||
}
|
||||
const tarContent = Buffer.concat(chunks);
|
||||
vol.reset();
|
||||
await setupBeforeRestore();
|
||||
jest.mocked(downloadFile).mockImplementation(async (_url, archivePath: string) => {
|
||||
await fs.mkdirp(mockCtx.workingdir);
|
||||
await fs.writeFile(archivePath, tarContent);
|
||||
});
|
||||
await manager.restoreCache(mockCtx);
|
||||
}
|
||||
|
||||
describe(GCSCacheManager, () => {
|
||||
beforeEach(() => {
|
||||
vol.reset();
|
||||
});
|
||||
afterEach(() => {
|
||||
jest.mocked(GCS.uploadWithSignedUrl).mockReset();
|
||||
jest.mocked(downloadFile).mockReset();
|
||||
});
|
||||
|
||||
async function saveAndRestoreCacheAsync(
|
||||
setupBeforeSave: () => Promise<void> | void,
|
||||
setupBeforeRestore: () => Promise<void> | void,
|
||||
cacheConfig: Partial<Cache>
|
||||
): Promise<void> {
|
||||
await setupBeforeSave();
|
||||
const manager = new GCSCacheManager();
|
||||
const mockCtx = {
|
||||
logger: { info: jest.fn(), error: console.error },
|
||||
workingdir: tmpDir,
|
||||
buildDirectory: `${tmpDir}/build`,
|
||||
job: {
|
||||
platform: Platform.ANDROID,
|
||||
projectRootDirectory: '.',
|
||||
cache: cacheConfig,
|
||||
},
|
||||
} as any;
|
||||
let tarReadStream: Readable;
|
||||
jest.mocked(GCS.uploadWithSignedUrl).mockImplementation(async ({ srcGeneratorAsync }) => {
|
||||
const result = await srcGeneratorAsync();
|
||||
tarReadStream = result;
|
||||
return randomUUID();
|
||||
});
|
||||
|
||||
await manager.saveCache(mockCtx);
|
||||
const chunks = [];
|
||||
for await (const chunk of tarReadStream!) {
|
||||
chunks.push(chunk);
|
||||
}
|
||||
const tarContent = Buffer.concat(chunks);
|
||||
await fs.rm(tmpDir, { recursive: true, force: true });
|
||||
await fs.rm(outsideDir, { recursive: true, force: true });
|
||||
await setupBeforeRestore();
|
||||
jest.mocked(downloadFile).mockImplementation(async (_url, archivePath: string) => {
|
||||
await fs.mkdirp(mockCtx.workingdir);
|
||||
await fs.writeFile(archivePath, tarContent);
|
||||
});
|
||||
await manager.restoreCache(mockCtx);
|
||||
}
|
||||
|
||||
test('save and restore for a single file', async () => {
|
||||
await saveAndRestoreCacheAsync(
|
||||
() => {
|
||||
return fs.outputFile(path.join(tmpDir, 'build', 'index.ts'), 'index.ts');
|
||||
vol.fromJSON({
|
||||
'/projectRoot/build/index.ts': 'index.ts',
|
||||
});
|
||||
},
|
||||
() => {},
|
||||
{
|
||||
@@ -96,18 +83,18 @@ describe(GCSCacheManager, () => {
|
||||
}
|
||||
);
|
||||
|
||||
await expect(fs.readFile(path.join(tmpDir, 'build', 'index.ts'), 'utf8')).resolves.toBe(
|
||||
'index.ts'
|
||||
);
|
||||
await expect(fs.pathExists(path.join(tmpDir, 'cache-restore.tar.gz'))).resolves.toBe(true);
|
||||
expect(vol.toJSON()).toStrictEqual({
|
||||
'/projectRoot/build/index.ts': 'index.ts',
|
||||
'/projectRoot/cache-restore.tar.gz': expect.anything(),
|
||||
});
|
||||
});
|
||||
test('save and restore for a single directory', async () => {
|
||||
await saveAndRestoreCacheAsync(
|
||||
async () => {
|
||||
await Promise.all([
|
||||
fs.outputFile(path.join(tmpDir, 'build', 'src', 'index.ts'), 'index.ts'),
|
||||
fs.outputFile(path.join(tmpDir, 'build', 'src', 'main.ts'), 'index.ts'),
|
||||
]);
|
||||
() => {
|
||||
vol.fromJSON({
|
||||
'/projectRoot/build/src/index.ts': 'index.ts',
|
||||
'/projectRoot/build/src/main.ts': 'index.ts',
|
||||
});
|
||||
},
|
||||
() => {},
|
||||
{
|
||||
@@ -115,78 +102,73 @@ describe(GCSCacheManager, () => {
|
||||
}
|
||||
);
|
||||
|
||||
await expect(fs.readFile(path.join(tmpDir, 'build', 'src', 'index.ts'), 'utf8')).resolves.toBe(
|
||||
'index.ts'
|
||||
);
|
||||
await expect(fs.readFile(path.join(tmpDir, 'build', 'src', 'main.ts'), 'utf8')).resolves.toBe(
|
||||
'index.ts'
|
||||
);
|
||||
await expect(fs.pathExists(path.join(tmpDir, 'cache-restore.tar.gz'))).resolves.toBe(true);
|
||||
expect(vol.toJSON()).toStrictEqual({
|
||||
'/projectRoot/build/src/index.ts': 'index.ts',
|
||||
'/projectRoot/build/src/main.ts': 'index.ts',
|
||||
'/projectRoot/cache-restore.tar.gz': expect.anything(),
|
||||
});
|
||||
});
|
||||
test('save and restore for a single directory outside of the project structure', async () => {
|
||||
await saveAndRestoreCacheAsync(
|
||||
async () => {
|
||||
await Promise.all([
|
||||
fs.outputFile(path.join(tmpDir, 'build', 'src', 'index.ts'), 'index.ts'),
|
||||
fs.outputFile(path.join(outsideDir, 'build', 'src', 'index.ts'), 'index.ts'),
|
||||
]);
|
||||
() => {
|
||||
vol.fromJSON({
|
||||
'/projectRoot/build/src/index.ts': 'index.ts',
|
||||
'/outsideProjectRoot/build/src/index.ts': 'index.ts',
|
||||
});
|
||||
},
|
||||
() => {},
|
||||
{
|
||||
paths: [path.join(outsideDir, 'build')],
|
||||
paths: ['/outsideProjectRoot/build'],
|
||||
}
|
||||
);
|
||||
|
||||
await expect(
|
||||
fs.readFile(path.join(outsideDir, 'build', 'src', 'index.ts'), 'utf8')
|
||||
).resolves.toBe('index.ts');
|
||||
await expect(fs.pathExists(path.join(tmpDir, 'build', 'src', 'index.ts'))).resolves.toBe(false);
|
||||
await expect(fs.pathExists(path.join(tmpDir, 'cache-restore.tar.gz'))).resolves.toBe(true);
|
||||
expect(vol.toJSON()).toStrictEqual({
|
||||
'/outsideProjectRoot/build/src/index.ts': 'index.ts',
|
||||
'/projectRoot/cache-restore.tar.gz': expect.anything(),
|
||||
});
|
||||
});
|
||||
test('that save and restore does not override existing files', async () => {
|
||||
await saveAndRestoreCacheAsync(
|
||||
async () => {
|
||||
await Promise.all([
|
||||
fs.outputFile(path.join(tmpDir, 'build', 'src', 'index.ts'), 'index.ts'),
|
||||
fs.outputFile(path.join(tmpDir, 'build', 'src', 'main'), 'index.ts'),
|
||||
]);
|
||||
() => {
|
||||
vol.fromJSON({
|
||||
'/projectRoot/build/src/index.ts': 'index.ts',
|
||||
'/projectRoot/build/src/main': 'index.ts',
|
||||
});
|
||||
},
|
||||
() => {
|
||||
return fs.outputFile(path.join(tmpDir, 'build', 'src', 'index.ts'), 'index2.ts');
|
||||
vol.fromJSON({
|
||||
'/projectRoot/build/src/index.ts': 'index2.ts',
|
||||
});
|
||||
},
|
||||
{
|
||||
paths: ['src'],
|
||||
}
|
||||
);
|
||||
|
||||
await expect(fs.readFile(path.join(tmpDir, 'build', 'src', 'index.ts'), 'utf8')).resolves.toBe(
|
||||
'index2.ts'
|
||||
);
|
||||
await expect(fs.readFile(path.join(tmpDir, 'build', 'src', 'main'), 'utf8')).resolves.toBe(
|
||||
'index.ts'
|
||||
);
|
||||
await expect(fs.pathExists(path.join(tmpDir, 'cache-restore.tar.gz'))).resolves.toBe(true);
|
||||
expect(vol.toJSON()).toStrictEqual({
|
||||
'/projectRoot/build/src/index.ts': 'index2.ts',
|
||||
'/projectRoot/build/src/main': 'index.ts',
|
||||
'/projectRoot/cache-restore.tar.gz': expect.anything(),
|
||||
});
|
||||
});
|
||||
test('save and restore for multiple locations', async () => {
|
||||
await saveAndRestoreCacheAsync(
|
||||
async () => {
|
||||
await Promise.all([
|
||||
fs.outputFile(path.join(tmpDir, 'build', 'src', 'index.ts'), 'index.ts'),
|
||||
fs.outputFile(path.join(outsideDir, 'build', 'src', 'index.ts'), 'index.ts'),
|
||||
]);
|
||||
() => {
|
||||
vol.fromJSON({
|
||||
'/projectRoot/build/src/index.ts': 'index.ts',
|
||||
'/outsideProjectRoot/build/src/index.ts': 'index.ts',
|
||||
});
|
||||
},
|
||||
() => {},
|
||||
{
|
||||
paths: ['src', path.join(outsideDir, 'build')],
|
||||
paths: ['src', '/outsideProjectRoot/build'],
|
||||
}
|
||||
);
|
||||
|
||||
await expect(fs.readFile(path.join(tmpDir, 'build', 'src', 'index.ts'), 'utf8')).resolves.toBe(
|
||||
'index.ts'
|
||||
);
|
||||
await expect(
|
||||
fs.readFile(path.join(outsideDir, 'build', 'src', 'index.ts'), 'utf8')
|
||||
).resolves.toBe('index.ts');
|
||||
await expect(fs.pathExists(path.join(tmpDir, 'cache-restore.tar.gz'))).resolves.toBe(true);
|
||||
expect(vol.toJSON()).toStrictEqual({
|
||||
'/outsideProjectRoot/build/src/index.ts': 'index.ts',
|
||||
'/projectRoot/build/src/index.ts': 'index.ts',
|
||||
'/projectRoot/cache-restore.tar.gz': expect.anything(),
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -5,7 +5,7 @@ import { asyncResult } from '@expo/results';
|
||||
import fs from 'fs-extra';
|
||||
import nullthrows from 'nullthrows';
|
||||
import path from 'path';
|
||||
import * as tar from 'tar';
|
||||
import tar from 'tar';
|
||||
import { z } from 'zod';
|
||||
|
||||
import config from './config';
|
||||
|
||||
@@ -4843,6 +4843,13 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/[email protected]":
|
||||
version "8.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#56958cb2d80f6d74352bd2e501a018e2506a8a84"
|
||||
integrity sha512-rNAPdomlIUX0i0cg2+I+Q1wOUr531zHBQ+cV/28PJ39bSPKjahatZZ2LMuhiguETkCgLVzfruw/ZvNMNkKoSzw==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/keygrip@*":
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/@types/keygrip/-/keygrip-1.0.6.tgz#1749535181a2a9b02ac04a797550a8787345b740"
|
||||
@@ -6316,7 +6323,7 @@ [email protected]:
|
||||
dependencies:
|
||||
node-int64 "^0.4.0"
|
||||
|
||||
buffer-equal-constant-time@^1.0.1:
|
||||
[email protected], buffer-equal-constant-time@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819"
|
||||
integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==
|
||||
@@ -11498,11 +11505,6 @@ join-component@^1.1.0:
|
||||
resolved "https://registry.yarnpkg.com/join-component/-/join-component-1.1.0.tgz#b8417b750661a392bee2c2537c68b2a9d4977cd5"
|
||||
integrity sha1-uEF7dQZho5K+4sJTfGiyqdSXfNU=
|
||||
|
||||
[email protected]:
|
||||
version "5.10.0"
|
||||
resolved "https://registry.yarnpkg.com/jose/-/jose-5.10.0.tgz#c37346a099d6467c401351a9a0c2161e0f52c4be"
|
||||
integrity sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==
|
||||
|
||||
jose@^5.0.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/jose/-/jose-5.2.0.tgz#d0ffd7f7e31253f633eefb190a930cd14a916995"
|
||||
@@ -11688,6 +11690,16 @@ jsonparse@^1.2.0, jsonparse@^1.3.1:
|
||||
resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
|
||||
integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=
|
||||
|
||||
[email protected]:
|
||||
version "9.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz#d0faf9ba1cc3a56255fe49c0961a67e520c1926d"
|
||||
integrity sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==
|
||||
dependencies:
|
||||
jws "^3.2.2"
|
||||
lodash "^4.17.21"
|
||||
ms "^2.1.1"
|
||||
semver "^7.3.8"
|
||||
|
||||
"jsx-ast-utils@^2.4.1 || ^3.0.0":
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz#41108d2cec408c3453c1bbe8a4aae9e1e2bd8f82"
|
||||
@@ -11716,6 +11728,15 @@ just-diff@^6.0.0:
|
||||
resolved "https://registry.yarnpkg.com/just-diff/-/just-diff-6.0.2.tgz#03b65908543ac0521caf6d8eb85035f7d27ea285"
|
||||
integrity sha512-S59eriX5u3/QhMNq3v/gm8Kd0w8OS6Tz2FS1NG4blv+z0MuQcBRJyFWjdovM0Rad4/P4aUPFtnkNjMjyMlMSYA==
|
||||
|
||||
jwa@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a"
|
||||
integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==
|
||||
dependencies:
|
||||
buffer-equal-constant-time "1.0.1"
|
||||
ecdsa-sig-formatter "1.0.11"
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
jwa@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/jwa/-/jwa-2.0.1.tgz#bf8176d1ad0cd72e0f3f58338595a13e110bc804"
|
||||
@@ -11725,6 +11746,14 @@ jwa@^2.0.0:
|
||||
ecdsa-sig-formatter "1.0.11"
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
jws@^3.2.2:
|
||||
version "3.2.2"
|
||||
resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304"
|
||||
integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==
|
||||
dependencies:
|
||||
jwa "^1.4.1"
|
||||
safe-buffer "^5.0.1"
|
||||
|
||||
jws@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/jws/-/jws-4.0.0.tgz#2d4e8cf6a318ffaa12615e9dec7e86e6c97310f4"
|
||||
@@ -16296,18 +16325,7 @@ [email protected], tar@^6.0.2, tar@^6.1.0, tar@^6.1.11, tar@^6.1.2:
|
||||
mkdirp "^1.0.3"
|
||||
yallist "^4.0.0"
|
||||
|
||||
tar@7.5.7:
|
||||
version "7.5.7"
|
||||
resolved "https://registry.yarnpkg.com/tar/-/tar-7.5.7.tgz#adf99774008ba1c89819f15dbd6019c630539405"
|
||||
integrity sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==
|
||||
dependencies:
|
||||
"@isaacs/fs-minipass" "^4.0.0"
|
||||
chownr "^3.0.0"
|
||||
minipass "^7.1.2"
|
||||
minizlib "^3.1.0"
|
||||
yallist "^5.0.0"
|
||||
|
||||
tar@^7.4.3:
|
||||
tar@^7.2.0, tar@^7.4.3:
|
||||
version "7.5.2"
|
||||
resolved "https://registry.yarnpkg.com/tar/-/tar-7.5.2.tgz#115c061495ec51ff3c6745ff8f6d0871c5b1dedc"
|
||||
integrity sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==
|
||||
|
||||
Reference in new issue
Block a user