mirror of
https://github.com/expo/eas-cli.git
synced 2026-11-15 03:38:08 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc62d22816 | ||
|
|
258c625611 | ||
|
|
e84340774d | ||
|
|
fbc23f7a7d | ||
|
|
97255ec90d | ||
|
|
cfccc87b82 | ||
|
|
09b4f8367e | ||
|
|
45481f9758 | ||
|
|
1119008317 | ||
|
|
123a0c1b7e | ||
|
|
2f21fa62b1 | ||
|
|
8ad449c6b7 | ||
|
|
fe8ec50806 | ||
|
|
86cefeb259 | ||
|
|
034e0a1e7f | ||
|
|
a6b776915f | ||
|
|
4ae52d0e3d | ||
|
|
f62720ef5a | ||
|
|
af09aaedb3 |
No files matched your search
@@ -0,0 +1,64 @@
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
staging_only:
|
||||
type: boolean
|
||||
required: true
|
||||
default: false
|
||||
description: "Only move the latest-eas-build-staging tag, not the latest-eas-build tag"
|
||||
version:
|
||||
type: string
|
||||
required: true
|
||||
description: "Version number to move the tag to"
|
||||
dry_run:
|
||||
type: boolean
|
||||
required: true
|
||||
default: true
|
||||
description: "Run the workflow in dry run mode, without making any NPM changes"
|
||||
|
||||
name: Move NPM tags used by EAS builds and workflows
|
||||
|
||||
jobs:
|
||||
move-tag:
|
||||
name: Move NPM tags used by EAS builds and workflows
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.EXPO_BOT_PAT }}
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }}
|
||||
INPUT_VERSION: ${{ github.event.inputs.version }}
|
||||
INPUT_DRY_RUN: ${{ github.event.inputs.dry_run }}
|
||||
INPUT_STAGING_ONLY: ${{ github.event.inputs.staging_only }}
|
||||
steps:
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
registry-url: "https://registry.npmjs.org/"
|
||||
scope: "expo"
|
||||
node-version: 22
|
||||
- name: Resolve version (fails if the version does not exist)
|
||||
run: |
|
||||
set -o pipefail
|
||||
npm pack --dry-run eas-cli@$INPUT_VERSION
|
||||
- name: Add latest-eas-build-staging tag
|
||||
run: |
|
||||
cmd="npm dist-tag add eas-cli@$INPUT_VERSION latest-eas-build-staging"
|
||||
if [[ "$INPUT_DRY_RUN" == "true" ]]; then
|
||||
echo "Running in dry run mode, skipping version check"
|
||||
echo "cmd = $cmd"
|
||||
exit 0
|
||||
fi
|
||||
echo //registry.npmjs.org/:_authToken=$NODE_AUTH_TOKEN > ~/.npmrc
|
||||
$cmd
|
||||
- name: Add latest-eas-build tag
|
||||
run: |
|
||||
cmd="npm dist-tag add eas-cli@$INPUT_VERSION latest-eas-build"
|
||||
if [[ "$INPUT_DRY_RUN" == "true" ]]; then
|
||||
echo "Running in dry run mode, skipping version check"
|
||||
echo "cmd = $cmd"
|
||||
exit 0
|
||||
fi
|
||||
if [[ "$INPUT_STAGING_ONLY" == "true" ]]; then
|
||||
echo "Only moving the staging tag, skipping the production tag"
|
||||
exit 0
|
||||
fi
|
||||
echo //registry.npmjs.org/:_authToken=$NODE_AUTH_TOKEN > ~/.npmrc
|
||||
$cmd
|
||||
+40
-2
@@ -8,14 +8,52 @@ This is the log of notable changes to EAS CLI and related packages.
|
||||
|
||||
### 🎉 New features
|
||||
|
||||
- New command `workflow:status`. ([#3242](https://github.com/expo/eas-cli/pull/3242) by [@douglowder](https://github.com/douglowder))
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- `eas:new` cleanup (remove `hidden` tag, fix README error, output cleanup). ([#3243](https://github.com/expo/eas-cli/pull/3243) by [@mackenco](https://github.com/mackenco))
|
||||
|
||||
## [16.25.1](https://github.com/expo/eas-cli/releases/tag/v16.25.1) - 2025-10-28
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Remove preview label from EAS Hosting commands ([#3241](https://github.com/expo/eas-cli/pull/3241) by [@kitten](https://github.com/kitten))
|
||||
|
||||
## [16.25.0](https://github.com/expo/eas-cli/releases/tag/v16.25.0) - 2025-10-27
|
||||
|
||||
### 🎉 New features
|
||||
|
||||
- `eas:new` command changes (project name prompt, output cleanup, additional project files, additional prompts). ([#3235](https://github.com/expo/eas-cli/pull/3235) by [@mackenco](https://github.com/mackenco))
|
||||
- `eas:build` command displays a warning when account is near it's build limit. ([#3236](https://github.com/expo/eas-cli/pull/3236) by [@mackenco](https://github.com/mackenco))
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
- workflow:run can use --wait and --json together. ([#3239](https://github.com/expo/eas-cli/pull/3239) by [@douglowder](https://github.com/douglowder))
|
||||
- Add missing env for local builds with latest plugin. ([#3237](https://github.com/expo/eas-cli/pull/3237) by [@douglowder](https://github.com/douglowder))
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Document the default values for `track` and `releaseStatus`. ([#3229](https://github.com/expo/eas-cli/pull/3229) by [@kadikraman](https://github.com/kadikraman))
|
||||
|
||||
## [16.24.1](https://github.com/expo/eas-cli/releases/tag/v16.24.1) - 2025-10-19
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
- Revert change in ora version. ([#3231](https://github.com/expo/eas-cli/pull/3231) by [@douglowder](https://github.com/douglowder))
|
||||
|
||||
## [16.24.0](https://github.com/expo/eas-cli/releases/tag/v16.24.0) - 2025-10-19
|
||||
|
||||
### 🎉 New features
|
||||
|
||||
- workflow:run --wait shows periodic job and step status updates. ([#3227](https://github.com/expo/eas-cli/pull/3227) by [@douglowder](https://github.com/douglowder))
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
- workflow:logs should show logs from build and repack jobs. ([#3226](https://github.com/expo/eas-cli/pull/3226) by [@douglowder](https://github.com/douglowder))
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
## [16.23.1](https://github.com/expo/eas-cli/releases/tag/v16.23.1) - 2025-10-16
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"npmClient": "yarn",
|
||||
"version": "16.24.0",
|
||||
"version": "16.26.0",
|
||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json"
|
||||
}
|
||||
+162
-87
@@ -120,10 +120,12 @@ eas --help COMMAND
|
||||
* [`eas metadata:lint`](#eas-metadatalint)
|
||||
* [`eas metadata:pull`](#eas-metadatapull)
|
||||
* [`eas metadata:push`](#eas-metadatapush)
|
||||
* [`eas new [PATH]`](#eas-new-path)
|
||||
* [`eas onboarding [TARGET_PROJECT_DIRECTORY]`](#eas-onboarding-target_project_directory)
|
||||
* [`eas open`](#eas-open)
|
||||
* [`eas project:info`](#eas-projectinfo)
|
||||
* [`eas project:init`](#eas-projectinit)
|
||||
* [`eas project:new [PATH]`](#eas-projectnew-path)
|
||||
* [`eas project:onboarding [TARGET_PROJECT_DIRECTORY]`](#eas-projectonboarding-target_project_directory)
|
||||
* [`eas submit`](#eas-submit)
|
||||
* [`eas update`](#eas-update)
|
||||
@@ -152,6 +154,7 @@ eas --help COMMAND
|
||||
* [`eas workflow:logs [ID]`](#eas-workflowlogs-id)
|
||||
* [`eas workflow:run [FILE]`](#eas-workflowrun-file)
|
||||
* [`eas workflow:runs`](#eas-workflowruns)
|
||||
* [`eas workflow:status [WORKFLOW_RUN_ID]`](#eas-workflowstatus-workflow_run_id)
|
||||
* [`eas workflow:validate PATH`](#eas-workflowvalidate-path)
|
||||
* [`eas workflow:view [ID]`](#eas-workflowview-id)
|
||||
|
||||
@@ -173,7 +176,7 @@ ALIASES
|
||||
$ eas login
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/account/login.ts)_
|
||||
|
||||
## `eas account:logout`
|
||||
|
||||
@@ -190,7 +193,7 @@ ALIASES
|
||||
$ eas logout
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/account/logout.ts)_
|
||||
|
||||
## `eas account:view`
|
||||
|
||||
@@ -207,7 +210,7 @@ ALIASES
|
||||
$ eas whoami
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/account/view.ts)_
|
||||
|
||||
## `eas analytics [STATUS]`
|
||||
|
||||
@@ -221,7 +224,7 @@ DESCRIPTION
|
||||
display or change analytics settings
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/analytics.ts)_
|
||||
|
||||
## `eas autocomplete [SHELL]`
|
||||
|
||||
@@ -273,7 +276,7 @@ DESCRIPTION
|
||||
create a branch
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/branch/create.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/branch/create.ts)_
|
||||
|
||||
## `eas branch:delete [NAME]`
|
||||
|
||||
@@ -294,7 +297,7 @@ DESCRIPTION
|
||||
delete a branch
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/branch/delete.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/branch/delete.ts)_
|
||||
|
||||
## `eas branch:list`
|
||||
|
||||
@@ -314,7 +317,7 @@ DESCRIPTION
|
||||
list all branches
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/branch/list.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/branch/list.ts)_
|
||||
|
||||
## `eas branch:rename`
|
||||
|
||||
@@ -334,7 +337,7 @@ DESCRIPTION
|
||||
rename a branch
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/branch/rename.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/branch/rename.ts)_
|
||||
|
||||
## `eas branch:view [NAME]`
|
||||
|
||||
@@ -357,7 +360,7 @@ DESCRIPTION
|
||||
view a branch
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/branch/view.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/branch/view.ts)_
|
||||
|
||||
## `eas build`
|
||||
|
||||
@@ -398,7 +401,7 @@ DESCRIPTION
|
||||
start a build
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/build/index.ts)_
|
||||
|
||||
## `eas build:cancel [BUILD_ID]`
|
||||
|
||||
@@ -417,7 +420,7 @@ DESCRIPTION
|
||||
cancel a build
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/build/cancel.ts)_
|
||||
|
||||
## `eas build:configure`
|
||||
|
||||
@@ -434,7 +437,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/v16.24.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.26.0/packages/eas-cli/src/commands/build/configure.ts)_
|
||||
|
||||
## `eas build:delete [BUILD_ID]`
|
||||
|
||||
@@ -453,7 +456,7 @@ DESCRIPTION
|
||||
delete a build
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/delete.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/build/delete.ts)_
|
||||
|
||||
## `eas build:dev`
|
||||
|
||||
@@ -473,7 +476,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/v16.24.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.26.0/packages/eas-cli/src/commands/build/dev.ts)_
|
||||
|
||||
## `eas build:download`
|
||||
|
||||
@@ -494,7 +497,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/v16.24.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.26.0/packages/eas-cli/src/commands/build/download.ts)_
|
||||
|
||||
## `eas build:inspect`
|
||||
|
||||
@@ -529,7 +532,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/v16.24.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.26.0/packages/eas-cli/src/commands/build/inspect.ts)_
|
||||
|
||||
## `eas build:list`
|
||||
|
||||
@@ -581,7 +584,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/v16.24.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.26.0/packages/eas-cli/src/commands/build/list.ts)_
|
||||
|
||||
## `eas build:resign`
|
||||
|
||||
@@ -610,7 +613,7 @@ DESCRIPTION
|
||||
re-sign a build archive
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/build/resign.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/build/resign.ts)_
|
||||
|
||||
## `eas build:run`
|
||||
|
||||
@@ -636,7 +639,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/v16.24.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.26.0/packages/eas-cli/src/commands/build/run.ts)_
|
||||
|
||||
## `eas build:submit`
|
||||
|
||||
@@ -690,7 +693,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/v16.24.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.26.0/packages/eas-cli/src/commands/build/version/get.ts)_
|
||||
|
||||
## `eas build:version:set`
|
||||
|
||||
@@ -709,7 +712,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/v16.24.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.26.0/packages/eas-cli/src/commands/build/version/set.ts)_
|
||||
|
||||
## `eas build:version:sync`
|
||||
|
||||
@@ -728,7 +731,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/v16.24.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.26.0/packages/eas-cli/src/commands/build/version/sync.ts)_
|
||||
|
||||
## `eas build:view [BUILD_ID]`
|
||||
|
||||
@@ -745,7 +748,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/v16.24.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.26.0/packages/eas-cli/src/commands/build/view.ts)_
|
||||
|
||||
## `eas channel:create [NAME]`
|
||||
|
||||
@@ -766,7 +769,7 @@ DESCRIPTION
|
||||
create a channel
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/channel/create.ts)_
|
||||
|
||||
## `eas channel:delete [NAME]`
|
||||
|
||||
@@ -787,7 +790,7 @@ DESCRIPTION
|
||||
Delete a channel
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/channel/delete.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/channel/delete.ts)_
|
||||
|
||||
## `eas channel:edit [NAME]`
|
||||
|
||||
@@ -809,7 +812,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/v16.24.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.26.0/packages/eas-cli/src/commands/channel/edit.ts)_
|
||||
|
||||
## `eas channel:list`
|
||||
|
||||
@@ -829,7 +832,7 @@ DESCRIPTION
|
||||
list all channels
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/channel/list.ts)_
|
||||
|
||||
## `eas channel:pause [NAME]`
|
||||
|
||||
@@ -851,7 +854,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/v16.24.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.26.0/packages/eas-cli/src/commands/channel/pause.ts)_
|
||||
|
||||
## `eas channel:resume [NAME]`
|
||||
|
||||
@@ -873,7 +876,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/v16.24.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.26.0/packages/eas-cli/src/commands/channel/resume.ts)_
|
||||
|
||||
## `eas channel:rollout [CHANNEL]`
|
||||
|
||||
@@ -906,7 +909,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/v16.24.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.26.0/packages/eas-cli/src/commands/channel/rollout.ts)_
|
||||
|
||||
## `eas channel:view [NAME]`
|
||||
|
||||
@@ -929,7 +932,7 @@ DESCRIPTION
|
||||
view a channel
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/channel/view.ts)_
|
||||
|
||||
## `eas config`
|
||||
|
||||
@@ -950,7 +953,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/v16.24.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.26.0/packages/eas-cli/src/commands/config.ts)_
|
||||
|
||||
## `eas credentials`
|
||||
|
||||
@@ -967,7 +970,7 @@ DESCRIPTION
|
||||
manage credentials
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/credentials/index.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/credentials/index.ts)_
|
||||
|
||||
## `eas credentials:configure-build`
|
||||
|
||||
@@ -985,7 +988,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/v16.24.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.26.0/packages/eas-cli/src/commands/credentials/configure-build.ts)_
|
||||
|
||||
## `eas deploy [options]`
|
||||
|
||||
@@ -1013,7 +1016,7 @@ ALIASES
|
||||
$ eas worker:deploy
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/deploy/index.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/deploy/index.ts)_
|
||||
|
||||
## `eas deploy:alias`
|
||||
|
||||
@@ -1038,7 +1041,7 @@ ALIASES
|
||||
$ eas deploy:promote
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/deploy/alias/index.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/deploy/alias/index.ts)_
|
||||
|
||||
## `eas deploy:alias:delete [ALIAS_NAME]`
|
||||
|
||||
@@ -1059,7 +1062,7 @@ ALIASES
|
||||
$ eas worker:alias:delete
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/deploy/alias/delete.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/deploy/alias/delete.ts)_
|
||||
|
||||
## `eas deploy:delete [DEPLOYMENT_ID]`
|
||||
|
||||
@@ -1080,7 +1083,7 @@ ALIASES
|
||||
$ eas worker:delete
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/deploy/delete.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/deploy/delete.ts)_
|
||||
|
||||
## `eas deploy:promote`
|
||||
|
||||
@@ -1117,7 +1120,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/v16.24.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.26.0/packages/eas-cli/src/commands/device/create.ts)_
|
||||
|
||||
## `eas device:delete`
|
||||
|
||||
@@ -1137,7 +1140,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/v16.24.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.26.0/packages/eas-cli/src/commands/device/delete.ts)_
|
||||
|
||||
## `eas device:list`
|
||||
|
||||
@@ -1158,7 +1161,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/v16.24.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.26.0/packages/eas-cli/src/commands/device/list.ts)_
|
||||
|
||||
## `eas device:rename`
|
||||
|
||||
@@ -1179,7 +1182,7 @@ DESCRIPTION
|
||||
rename a registered device
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/device/rename.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/device/rename.ts)_
|
||||
|
||||
## `eas device:view [UDID]`
|
||||
|
||||
@@ -1193,7 +1196,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/v16.24.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.26.0/packages/eas-cli/src/commands/device/view.ts)_
|
||||
|
||||
## `eas diagnostics`
|
||||
|
||||
@@ -1207,7 +1210,7 @@ DESCRIPTION
|
||||
display environment info
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/diagnostics.ts)_
|
||||
|
||||
## `eas env:create [ENVIRONMENT]`
|
||||
|
||||
@@ -1237,7 +1240,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/v16.24.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.26.0/packages/eas-cli/src/commands/env/create.ts)_
|
||||
|
||||
## `eas env:delete [ENVIRONMENT]`
|
||||
|
||||
@@ -1262,7 +1265,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/v16.24.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.26.0/packages/eas-cli/src/commands/env/delete.ts)_
|
||||
|
||||
## `eas env:exec ENVIRONMENT BASH_COMMAND`
|
||||
|
||||
@@ -1284,7 +1287,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/v16.24.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.26.0/packages/eas-cli/src/commands/env/exec.ts)_
|
||||
|
||||
## `eas env:get [ENVIRONMENT]`
|
||||
|
||||
@@ -1309,7 +1312,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/v16.24.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.26.0/packages/eas-cli/src/commands/env/get.ts)_
|
||||
|
||||
## `eas env:list [ENVIRONMENT]`
|
||||
|
||||
@@ -1335,7 +1338,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/v16.24.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.26.0/packages/eas-cli/src/commands/env/list.ts)_
|
||||
|
||||
## `eas env:pull [ENVIRONMENT]`
|
||||
|
||||
@@ -1357,7 +1360,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/v16.24.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.26.0/packages/eas-cli/src/commands/env/pull.ts)_
|
||||
|
||||
## `eas env:push [ENVIRONMENT]`
|
||||
|
||||
@@ -1379,7 +1382,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/v16.24.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.26.0/packages/eas-cli/src/commands/env/push.ts)_
|
||||
|
||||
## `eas env:update [ENVIRONMENT]`
|
||||
|
||||
@@ -1411,7 +1414,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/v16.24.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.26.0/packages/eas-cli/src/commands/env/update.ts)_
|
||||
|
||||
## `eas fingerprint:compare [HASH1] [HASH2]`
|
||||
|
||||
@@ -1455,7 +1458,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/v16.24.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.26.0/packages/eas-cli/src/commands/fingerprint/compare.ts)_
|
||||
|
||||
## `eas fingerprint:generate`
|
||||
|
||||
@@ -1485,7 +1488,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/v16.24.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.26.0/packages/eas-cli/src/commands/fingerprint/generate.ts)_
|
||||
|
||||
## `eas help [COMMAND]`
|
||||
|
||||
@@ -1593,7 +1596,7 @@ DESCRIPTION
|
||||
validate the local store configuration
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/metadata/lint.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/metadata/lint.ts)_
|
||||
|
||||
## `eas metadata:pull`
|
||||
|
||||
@@ -1610,7 +1613,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/v16.24.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.26.0/packages/eas-cli/src/commands/metadata/pull.ts)_
|
||||
|
||||
## `eas metadata:push`
|
||||
|
||||
@@ -1627,7 +1630,28 @@ 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/v16.24.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.26.0/packages/eas-cli/src/commands/metadata/push.ts)_
|
||||
|
||||
## `eas new [PATH]`
|
||||
|
||||
Create a new project configured with Expo Application Services (EAS)
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ eas new [PATH] [-p bun|npm|pnpm|yarn]
|
||||
|
||||
ARGUMENTS
|
||||
PATH Path to create the project (defaults to current directory)
|
||||
|
||||
FLAGS
|
||||
-p, --package-manager=(bun|npm|pnpm|yarn) [default: npm] Package manager to use for installing dependencies
|
||||
|
||||
DESCRIPTION
|
||||
Create a new project configured with Expo Application Services (EAS)
|
||||
|
||||
ALIASES
|
||||
$ eas new
|
||||
```
|
||||
|
||||
## `eas onboarding [TARGET_PROJECT_DIRECTORY]`
|
||||
|
||||
@@ -1657,7 +1681,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/v16.24.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.26.0/packages/eas-cli/src/commands/open.ts)_
|
||||
|
||||
## `eas project:info`
|
||||
|
||||
@@ -1671,7 +1695,7 @@ DESCRIPTION
|
||||
information about the current project
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/project/info.ts)_
|
||||
|
||||
## `eas project:init`
|
||||
|
||||
@@ -1694,7 +1718,30 @@ ALIASES
|
||||
$ eas init
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/project/init.ts)_
|
||||
|
||||
## `eas project:new [PATH]`
|
||||
|
||||
Create a new project configured with Expo Application Services (EAS)
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ eas project:new [PATH] [-p bun|npm|pnpm|yarn]
|
||||
|
||||
ARGUMENTS
|
||||
PATH Path to create the project (defaults to current directory)
|
||||
|
||||
FLAGS
|
||||
-p, --package-manager=(bun|npm|pnpm|yarn) [default: npm] Package manager to use for installing dependencies
|
||||
|
||||
DESCRIPTION
|
||||
Create a new project configured with Expo Application Services (EAS)
|
||||
|
||||
ALIASES
|
||||
$ eas new
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/project/new.ts](https://github.com/expo/eas-cli/blob/v16.26.0/packages/eas-cli/src/commands/project/new.ts)_
|
||||
|
||||
## `eas project:onboarding [TARGET_PROJECT_DIRECTORY]`
|
||||
|
||||
@@ -1712,7 +1759,7 @@ ALIASES
|
||||
$ eas onboarding
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/project/onboarding.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/project/onboarding.ts)_
|
||||
|
||||
## `eas submit`
|
||||
|
||||
@@ -1747,7 +1794,7 @@ ALIASES
|
||||
$ eas build:submit
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/submit.ts)_
|
||||
|
||||
## `eas update`
|
||||
|
||||
@@ -1787,7 +1834,7 @@ DESCRIPTION
|
||||
publish an update group
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/update/index.ts)_
|
||||
|
||||
## `eas update:configure`
|
||||
|
||||
@@ -1807,7 +1854,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/v16.24.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.26.0/packages/eas-cli/src/commands/update/configure.ts)_
|
||||
|
||||
## `eas update:delete GROUPID`
|
||||
|
||||
@@ -1828,7 +1875,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/v16.24.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.26.0/packages/eas-cli/src/commands/update/delete.ts)_
|
||||
|
||||
## `eas update:edit [GROUPID]`
|
||||
|
||||
@@ -1852,7 +1899,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/v16.24.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.26.0/packages/eas-cli/src/commands/update/edit.ts)_
|
||||
|
||||
## `eas update:list`
|
||||
|
||||
@@ -1874,7 +1921,7 @@ DESCRIPTION
|
||||
view the recent updates
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/update/list.ts)_
|
||||
|
||||
## `eas update:republish`
|
||||
|
||||
@@ -1910,7 +1957,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/v16.24.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.26.0/packages/eas-cli/src/commands/update/republish.ts)_
|
||||
|
||||
## `eas update:revert-update-rollout`
|
||||
|
||||
@@ -1937,7 +1984,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/v16.24.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.26.0/packages/eas-cli/src/commands/update/revert-update-rollout.ts)_
|
||||
|
||||
## `eas update:roll-back-to-embedded`
|
||||
|
||||
@@ -1965,7 +2012,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/v16.24.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.26.0/packages/eas-cli/src/commands/update/roll-back-to-embedded.ts)_
|
||||
|
||||
## `eas update:rollback`
|
||||
|
||||
@@ -1986,7 +2033,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/v16.24.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.26.0/packages/eas-cli/src/commands/update/rollback.ts)_
|
||||
|
||||
## `eas update:view GROUPID`
|
||||
|
||||
@@ -2006,7 +2053,7 @@ DESCRIPTION
|
||||
update group details
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/update/view.ts)_
|
||||
|
||||
## `eas upload`
|
||||
|
||||
@@ -2027,7 +2074,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/v16.24.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.26.0/packages/eas-cli/src/commands/upload.ts)_
|
||||
|
||||
## `eas webhook:create`
|
||||
|
||||
@@ -2048,7 +2095,7 @@ DESCRIPTION
|
||||
create a webhook
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/webhook/create.ts)_
|
||||
|
||||
## `eas webhook:delete [ID]`
|
||||
|
||||
@@ -2068,7 +2115,7 @@ DESCRIPTION
|
||||
delete a webhook
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/webhook/delete.ts)_
|
||||
|
||||
## `eas webhook:list`
|
||||
|
||||
@@ -2086,7 +2133,7 @@ DESCRIPTION
|
||||
list webhooks
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/webhook/list.ts)_
|
||||
|
||||
## `eas webhook:update`
|
||||
|
||||
@@ -2108,7 +2155,7 @@ DESCRIPTION
|
||||
update a webhook
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/webhook/update.ts)_
|
||||
|
||||
## `eas webhook:view ID`
|
||||
|
||||
@@ -2125,7 +2172,7 @@ DESCRIPTION
|
||||
view a webhook
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/webhook/view.ts)_
|
||||
|
||||
## `eas whoami`
|
||||
|
||||
@@ -2245,7 +2292,7 @@ DESCRIPTION
|
||||
to cancel.
|
||||
```
|
||||
|
||||
_See code: [packages/eas-cli/src/commands/workflow/cancel.ts](https://github.com/expo/eas-cli/blob/v16.24.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.26.0/packages/eas-cli/src/commands/workflow/cancel.ts)_
|
||||
|
||||
## `eas workflow:create [NAME]`
|
||||
|
||||
@@ -2265,7 +2312,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/v16.24.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.26.0/packages/eas-cli/src/commands/workflow/create.ts)_
|
||||
|
||||
## `eas workflow:logs [ID]`
|
||||
|
||||
@@ -2289,7 +2336,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/v16.24.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.26.0/packages/eas-cli/src/commands/workflow/logs.ts)_
|
||||
|
||||
## `eas workflow:run [FILE]`
|
||||
|
||||
@@ -2307,7 +2354,7 @@ FLAGS
|
||||
--json Enable JSON output, non-JSON messages will be printed to stderr.
|
||||
--non-interactive Run the command in non-interactive mode.
|
||||
--ref=<value> Git reference to run the workflow on
|
||||
--[no-]wait Wait for workflow run to complete. Defaults to false. Cannot be used with the --json flag.
|
||||
--[no-]wait Wait for workflow run to complete. Defaults to false.
|
||||
|
||||
DESCRIPTION
|
||||
run an EAS workflow. The entire local project directory will be packaged and uploaded to EAS servers for the workflow
|
||||
@@ -2324,12 +2371,12 @@ FLAG DESCRIPTIONS
|
||||
When this flag is used, the local project is not uploaded; instead, the workflow is run from the exact state of the
|
||||
project at the chosen reference.
|
||||
|
||||
--[no-]wait Wait for workflow run to complete. Defaults to false. Cannot be used with the --json flag.
|
||||
--[no-]wait Wait for workflow run to complete. Defaults to false.
|
||||
|
||||
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/v16.24.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.26.0/packages/eas-cli/src/commands/workflow/run.ts)_
|
||||
|
||||
## `eas workflow:runs`
|
||||
|
||||
@@ -2354,7 +2401,35 @@ 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/v16.24.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.26.0/packages/eas-cli/src/commands/workflow/runs.ts)_
|
||||
|
||||
## `eas workflow:status [WORKFLOW_RUN_ID]`
|
||||
|
||||
show the status of an existing workflow run. If no run ID is provided, you will be prompted to select from recent workflow runs for the current project.
|
||||
|
||||
```
|
||||
USAGE
|
||||
$ eas workflow:status [WORKFLOW_RUN_ID] [--non-interactive] [--wait] [--json]
|
||||
|
||||
ARGUMENTS
|
||||
WORKFLOW_RUN_ID A workflow run ID.
|
||||
|
||||
FLAGS
|
||||
--json Enable JSON output, non-JSON messages will be printed to stderr.
|
||||
--non-interactive Run the command in non-interactive mode.
|
||||
--[no-]wait Wait for workflow run to complete. Defaults to false.
|
||||
|
||||
DESCRIPTION
|
||||
show the status of an existing workflow run. If no run ID is provided, you will be prompted to select from recent
|
||||
workflow runs for the current project.
|
||||
|
||||
FLAG DESCRIPTIONS
|
||||
--[no-]wait Wait for workflow run to complete. Defaults to false.
|
||||
|
||||
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/v16.26.0/packages/eas-cli/src/commands/workflow/status.ts)_
|
||||
|
||||
## `eas workflow:validate PATH`
|
||||
|
||||
@@ -2374,7 +2449,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/v16.24.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.26.0/packages/eas-cli/src/commands/workflow/validate.ts)_
|
||||
|
||||
## `eas workflow:view [ID]`
|
||||
|
||||
@@ -2396,5 +2471,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/v16.24.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.26.0/packages/eas-cli/src/commands/workflow/view.ts)_
|
||||
<!-- commandsstop -->
|
||||
Generated
+12
@@ -64680,6 +64680,18 @@
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "finalizedAt",
|
||||
"description": null,
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "DateTime",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "gitCommitHash",
|
||||
"description": null,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "eas-cli",
|
||||
"description": "EAS command line tool",
|
||||
"version": "16.24.0",
|
||||
"version": "16.26.0",
|
||||
"author": "Expo <[email protected]>",
|
||||
"bin": {
|
||||
"eas": "./bin/run"
|
||||
@@ -12,8 +12,8 @@
|
||||
"@expo/code-signing-certificates": "0.0.5",
|
||||
"@expo/config": "10.0.6",
|
||||
"@expo/config-plugins": "9.0.12",
|
||||
"@expo/eas-build-job": "1.0.239",
|
||||
"@expo/eas-json": "16.23.0",
|
||||
"@expo/eas-build-job": "1.0.243",
|
||||
"@expo/eas-json": "16.25.0",
|
||||
"@expo/env": "^1.0.0",
|
||||
"@expo/json-file": "8.3.3",
|
||||
"@expo/logger": "1.0.221",
|
||||
@@ -71,7 +71,7 @@
|
||||
"node-forge": "1.3.1",
|
||||
"node-stream-zip": "1.15.0",
|
||||
"nullthrows": "1.1.1",
|
||||
"ora": "9.0.0",
|
||||
"ora": "5.1.0",
|
||||
"pkg-dir": "4.2.0",
|
||||
"pngjs": "7.0.0",
|
||||
"promise-limit": "2.7.0",
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { Job, Metadata } from '@expo/eas-build-job';
|
||||
import { Job, Metadata, version } from '@expo/eas-build-job';
|
||||
import spawnAsync from '@expo/spawn-async';
|
||||
import { ChildProcess } from 'child_process';
|
||||
import semver from 'semver';
|
||||
|
||||
import { getExpoApiBaseUrl } from '../api';
|
||||
import Log from '../log';
|
||||
import { ora } from '../ora';
|
||||
|
||||
const PLUGIN_PACKAGE_NAME = 'eas-cli-local-build-plugin';
|
||||
const PLUGIN_PACKAGE_VERSION = '1.0.171';
|
||||
const PLUGIN_PACKAGE_VERSION = version; // should match version of @expo/eas-build-job
|
||||
|
||||
export enum LocalBuildMode {
|
||||
/**
|
||||
@@ -60,6 +61,7 @@ export async function runLocalBuildAsync(
|
||||
...env,
|
||||
...process.env,
|
||||
EAS_LOCAL_BUILD_WORKINGDIR: options.workingdir ?? process.env.EAS_LOCAL_BUILD_WORKINGDIR,
|
||||
__API_SERVER_URL: getExpoApiBaseUrl(),
|
||||
...(options.skipCleanup || options.skipNativeBuild
|
||||
? { EAS_LOCAL_BUILD_SKIP_CLEANUP: '1' }
|
||||
: {}),
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { LogSpy } from './testUtils';
|
||||
import { canAccessRepositoryUsingSshAsync, runGitCloneAsync } from '../../../onboarding/git';
|
||||
import { installDependenciesAsync } from '../../../onboarding/installDependencies';
|
||||
import { runCommandAsync } from '../../../onboarding/runCommand';
|
||||
@@ -11,23 +10,14 @@ import {
|
||||
jest.mock('../../../onboarding/git');
|
||||
jest.mock('../../../onboarding/runCommand');
|
||||
jest.mock('../../../onboarding/installDependencies');
|
||||
jest.mock('../../../ora');
|
||||
jest.mock('fs-extra');
|
||||
|
||||
describe('commands', () => {
|
||||
let logSpy: LogSpy;
|
||||
|
||||
beforeAll(() => {
|
||||
logSpy = new LogSpy('log');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
logSpy.restore();
|
||||
});
|
||||
|
||||
describe('cloneTemplateAsync', () => {
|
||||
it('should clone the template project with ssh', async () => {
|
||||
const targetProjectDir = '/test/target-project';
|
||||
@@ -40,13 +30,12 @@ describe('commands', () => {
|
||||
|
||||
const result = await cloneTemplateAsync(targetProjectDir);
|
||||
|
||||
logSpy.expectLogToContain(`📂 Cloning the project to ${targetProjectDir}`);
|
||||
|
||||
expect(runGitCloneAsync).toHaveBeenCalledWith({
|
||||
githubUsername: 'expo',
|
||||
githubRepositoryName: 'expo-template-default',
|
||||
targetProjectDir,
|
||||
cloneMethod: 'ssh',
|
||||
showOutput: false,
|
||||
});
|
||||
|
||||
expect(result).toBe(finalTargetProjectDir);
|
||||
@@ -63,13 +52,12 @@ describe('commands', () => {
|
||||
|
||||
const result = await cloneTemplateAsync(targetProjectDir);
|
||||
|
||||
logSpy.expectLogToContain(`📂 Cloning the project to ${targetProjectDir}`);
|
||||
|
||||
expect(runGitCloneAsync).toHaveBeenCalledWith({
|
||||
githubUsername: 'expo',
|
||||
githubRepositoryName: 'expo-template-default',
|
||||
targetProjectDir,
|
||||
cloneMethod: 'https',
|
||||
showOutput: false,
|
||||
});
|
||||
|
||||
expect(result).toBe(finalTargetProjectDir);
|
||||
@@ -96,6 +84,7 @@ describe('commands', () => {
|
||||
command: 'npx',
|
||||
args: ['expo', 'install', 'expo-updates'],
|
||||
showOutput: false,
|
||||
showSpinner: false,
|
||||
});
|
||||
|
||||
expect(runCommandAsync).toHaveBeenCalledWith({
|
||||
@@ -103,6 +92,7 @@ describe('commands', () => {
|
||||
command: 'npx',
|
||||
args: ['expo', 'install', '@expo/metro-runtime'],
|
||||
showOutput: false,
|
||||
showSpinner: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -118,6 +108,7 @@ describe('commands', () => {
|
||||
args: ['init'],
|
||||
cwd: projectDir,
|
||||
showOutput: false,
|
||||
showSpinner: false,
|
||||
});
|
||||
|
||||
expect(runCommandAsync).toHaveBeenCalledWith({
|
||||
@@ -125,6 +116,7 @@ describe('commands', () => {
|
||||
args: ['add', '.'],
|
||||
cwd: projectDir,
|
||||
showOutput: false,
|
||||
showSpinner: false,
|
||||
});
|
||||
|
||||
expect(runCommandAsync).toHaveBeenCalledWith({
|
||||
@@ -132,6 +124,7 @@ describe('commands', () => {
|
||||
args: ['commit', '-m', 'Initial commit'],
|
||||
cwd: projectDir,
|
||||
showOutput: false,
|
||||
showSpinner: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,7 +8,6 @@ import { promptAsync } from '../../../prompts';
|
||||
import {
|
||||
findAvailableProjectNameAsync,
|
||||
generateProjectConfigAsync,
|
||||
generateProjectNameVariations,
|
||||
getAccountChoices,
|
||||
promptForProjectAccountAsync,
|
||||
} from '../configs';
|
||||
@@ -17,6 +16,9 @@ jest.mock('../../../prompts');
|
||||
jest.mock('../../../log');
|
||||
jest.mock('fs-extra');
|
||||
jest.mock('../../../project/fetchOrCreateProjectIDForWriteToConfigWithConfirmationAsync');
|
||||
jest.mock('../utils', () => ({
|
||||
printDirectory: jest.fn((dir: string) => dir),
|
||||
}));
|
||||
|
||||
describe('configs', () => {
|
||||
let logSpy: LogSpy;
|
||||
@@ -53,49 +55,53 @@ describe('configs', () => {
|
||||
};
|
||||
|
||||
describe('when no path is provided', () => {
|
||||
it('should generate name and directory when base name is available', async () => {
|
||||
it('should prompt for project name with default value', async () => {
|
||||
(fs.pathExists as jest.Mock).mockResolvedValue(false);
|
||||
jest.mocked(findProjectIdByAccountNameAndSlugNullableAsync).mockResolvedValue(null);
|
||||
mockUserInput({ name: 'expo-project' });
|
||||
|
||||
const result = await generateProjectConfigAsync(jester, undefined, mockOptions);
|
||||
const result = await generateProjectConfigAsync(undefined, mockOptions);
|
||||
|
||||
expect(result).toEqual({
|
||||
projectName: 'new-expo-project',
|
||||
projectDirectory: expect.stringContaining('/new-expo-project'),
|
||||
projectName: 'expo-project',
|
||||
projectDirectory: expect.stringContaining('/expo-project'),
|
||||
});
|
||||
logSpy.expectLogToContain('Using project name: new-expo-project');
|
||||
expectPromptToHaveMessage('What would you like to name your project?');
|
||||
expect(promptAsync).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
initial: 'expo-project',
|
||||
})
|
||||
);
|
||||
logSpy.expectLogToContain('Using project name: expo-project');
|
||||
});
|
||||
|
||||
it('should use username-date when base name exists', async () => {
|
||||
(fs.pathExists as jest.Mock)
|
||||
.mockResolvedValueOnce(true) // base name exists
|
||||
.mockResolvedValueOnce(false); // username-date doesn't exist
|
||||
it('should prompt and use custom name entered by user', async () => {
|
||||
(fs.pathExists as jest.Mock).mockResolvedValue(false);
|
||||
jest.mocked(findProjectIdByAccountNameAndSlugNullableAsync).mockResolvedValue(null);
|
||||
mockUserInput({ name: 'user-custom-name' });
|
||||
|
||||
const result = await generateProjectConfigAsync(jester, undefined, mockOptions);
|
||||
const result = await generateProjectConfigAsync(undefined, mockOptions);
|
||||
|
||||
expect(result).toEqual({
|
||||
projectName: expect.stringMatching(/^new-expo-project-jester-\d{4}-\d{2}-\d{2}$/),
|
||||
projectDirectory: expect.stringContaining(result.projectName),
|
||||
projectName: 'user-custom-name',
|
||||
projectDirectory: expect.stringContaining('/user-custom-name'),
|
||||
});
|
||||
logSpy.expectLogToContain('Using alternate project name:');
|
||||
expectPromptToHaveMessage('What would you like to name your project?');
|
||||
logSpy.expectLogToContain('Using project name: user-custom-name');
|
||||
});
|
||||
|
||||
it('should use username-date-shortID when base name and username-date exist', async () => {
|
||||
(fs.pathExists as jest.Mock)
|
||||
.mockResolvedValueOnce(true) // base name exists
|
||||
.mockResolvedValueOnce(true); // username-date exists
|
||||
it('should use shortid when prompted name exists', async () => {
|
||||
(fs.pathExists as jest.Mock).mockResolvedValue(true); // base name exists
|
||||
jest.mocked(findProjectIdByAccountNameAndSlugNullableAsync).mockResolvedValue(null);
|
||||
mockUserInput({ name: 'existing-project' });
|
||||
|
||||
const result = await generateProjectConfigAsync(jester, undefined, mockOptions);
|
||||
const result = await generateProjectConfigAsync(undefined, mockOptions);
|
||||
|
||||
expect(result).toEqual({
|
||||
projectName: expect.stringMatching(
|
||||
/^new-expo-project-jester-\d{4}-\d{2}-\d{2}-[a-zA-Z0-9_-]{6}$/
|
||||
),
|
||||
projectName: expect.stringMatching(/^existing-project-[a-zA-Z0-9_-]{6}$/),
|
||||
projectDirectory: expect.stringContaining(result.projectName),
|
||||
});
|
||||
logSpy.expectLogToContain('Using alternate project name:');
|
||||
logSpy.expectLogToContain('Using project name:');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -104,12 +110,13 @@ describe('configs', () => {
|
||||
(fs.pathExists as jest.Mock).mockResolvedValue(false);
|
||||
jest.mocked(findProjectIdByAccountNameAndSlugNullableAsync).mockResolvedValue(null);
|
||||
const absolutePath = '/absolute/path/to/my-project';
|
||||
const result = await generateProjectConfigAsync(jester, absolutePath, mockOptions);
|
||||
const result = await generateProjectConfigAsync(absolutePath, mockOptions);
|
||||
|
||||
expect(result).toEqual({
|
||||
projectName: 'my-project',
|
||||
projectDirectory: absolutePath,
|
||||
});
|
||||
expect(promptAsync).not.toHaveBeenCalled();
|
||||
logSpy.expectLogToContain('Using project directory:');
|
||||
});
|
||||
|
||||
@@ -117,12 +124,13 @@ describe('configs', () => {
|
||||
(fs.pathExists as jest.Mock).mockResolvedValue(false);
|
||||
jest.mocked(findProjectIdByAccountNameAndSlugNullableAsync).mockResolvedValue(null);
|
||||
const relativePath = 'some/relative/my-app';
|
||||
const result = await generateProjectConfigAsync(jester, relativePath, mockOptions);
|
||||
const result = await generateProjectConfigAsync(relativePath, mockOptions);
|
||||
|
||||
expect(result).toEqual({
|
||||
projectName: 'my-app',
|
||||
projectDirectory: expect.stringContaining('some/relative/my-app'),
|
||||
});
|
||||
expect(promptAsync).not.toHaveBeenCalled();
|
||||
logSpy.expectLogToContain('Using project directory:');
|
||||
});
|
||||
});
|
||||
@@ -165,19 +173,6 @@ describe('configs', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('generateProjectNameVariations', () => {
|
||||
it('should generate name variations', () => {
|
||||
const baseName = 'my-project';
|
||||
const result = generateProjectNameVariations(jester, baseName);
|
||||
|
||||
expect(result).toEqual([
|
||||
'my-project',
|
||||
expect.stringMatching(/^my-project-jester-\d{4}-\d{2}-\d{2}$/),
|
||||
expect.stringMatching(/^my-project-jester-\d{4}-\d{2}-\d{2}-[a-zA-Z0-9_-]{6}$/),
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('findAvailableProjectNameAsync', () => {
|
||||
const mockGraphqlClient = {} as ExpoGraphqlClient;
|
||||
const mockOptions = {
|
||||
@@ -189,12 +184,7 @@ describe('configs', () => {
|
||||
(fs.pathExists as jest.Mock).mockResolvedValue(false);
|
||||
jest.mocked(findProjectIdByAccountNameAndSlugNullableAsync).mockResolvedValue(null);
|
||||
|
||||
const result = await findAvailableProjectNameAsync(
|
||||
jester,
|
||||
'test-project',
|
||||
'/base/path',
|
||||
mockOptions
|
||||
);
|
||||
const result = await findAvailableProjectNameAsync('test-project', '/base/path', mockOptions);
|
||||
|
||||
expect(result).toEqual({
|
||||
projectName: 'test-project',
|
||||
@@ -208,63 +198,48 @@ describe('configs', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should try alternatives when first name exists locally', async () => {
|
||||
(fs.pathExists as jest.Mock)
|
||||
.mockResolvedValueOnce(true) // First exists
|
||||
.mockResolvedValueOnce(false); // Second available
|
||||
it('should use shortid variant when base name exists locally', async () => {
|
||||
(fs.pathExists as jest.Mock).mockResolvedValue(true); // Base name exists locally
|
||||
jest.mocked(findProjectIdByAccountNameAndSlugNullableAsync).mockResolvedValue(null);
|
||||
|
||||
const result = await findAvailableProjectNameAsync(
|
||||
jester,
|
||||
'test-project',
|
||||
'/base/path',
|
||||
mockOptions
|
||||
);
|
||||
const result = await findAvailableProjectNameAsync('test-project', '/base/path', mockOptions);
|
||||
|
||||
expect(result).toEqual({
|
||||
projectName: expect.stringMatching(/^test-project-jester-\d{4}-\d{2}-\d{2}$/),
|
||||
projectDirectory: expect.stringContaining('/base/path/test-project-jester-'),
|
||||
projectName: expect.stringMatching(/^test-project-[a-zA-Z0-9_-]{6}$/),
|
||||
projectDirectory: expect.stringContaining('/base/path/test-project-'),
|
||||
});
|
||||
expect(fs.pathExists).toHaveBeenCalledTimes(2);
|
||||
expect(fs.pathExists).toHaveBeenCalledTimes(1);
|
||||
expect(fs.pathExists).toHaveBeenCalledWith('/base/path/test-project');
|
||||
});
|
||||
|
||||
it('should skip name if local is available but remote exists', async () => {
|
||||
it('should use shortid variant when base name exists remotely', async () => {
|
||||
(fs.pathExists as jest.Mock).mockResolvedValue(false);
|
||||
jest
|
||||
.mocked(findProjectIdByAccountNameAndSlugNullableAsync)
|
||||
.mockResolvedValueOnce('project-id') // First name exists remotely
|
||||
.mockResolvedValueOnce(null); // Second available remotely
|
||||
jest.mocked(findProjectIdByAccountNameAndSlugNullableAsync).mockResolvedValue('project-id'); // Base name exists remotely
|
||||
|
||||
const result = await findAvailableProjectNameAsync(
|
||||
jester,
|
||||
'test-project',
|
||||
'/base/path',
|
||||
mockOptions
|
||||
);
|
||||
const result = await findAvailableProjectNameAsync('test-project', '/base/path', mockOptions);
|
||||
|
||||
expect(result).toEqual({
|
||||
projectName: expect.stringMatching(/^test-project-jester-\d{4}-\d{2}-\d{2}$/),
|
||||
projectDirectory: expect.stringContaining('/base/path/test-project-jester-'),
|
||||
projectName: expect.stringMatching(/^test-project-[a-zA-Z0-9_-]{6}$/),
|
||||
projectDirectory: expect.stringContaining('/base/path/test-project-'),
|
||||
});
|
||||
expect(findProjectIdByAccountNameAndSlugNullableAsync).toHaveBeenCalledTimes(2);
|
||||
expect(findProjectIdByAccountNameAndSlugNullableAsync).toHaveBeenCalledTimes(1);
|
||||
expect(findProjectIdByAccountNameAndSlugNullableAsync).toHaveBeenCalledWith(
|
||||
mockGraphqlClient,
|
||||
'jester',
|
||||
'test-project'
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw error when all variations taken', async () => {
|
||||
it('should use shortid variant when base name is taken both locally and remotely', async () => {
|
||||
(fs.pathExists as jest.Mock).mockResolvedValue(true);
|
||||
jest.mocked(findProjectIdByAccountNameAndSlugNullableAsync).mockResolvedValue('project-id');
|
||||
|
||||
await expect(
|
||||
findAvailableProjectNameAsync(jester, 'test-project', '/base/path', mockOptions)
|
||||
).rejects.toThrow('Unable to find a unique project name');
|
||||
});
|
||||
const result = await findAvailableProjectNameAsync('test-project', '/base/path', mockOptions);
|
||||
|
||||
it('should log when using alternative name', async () => {
|
||||
(fs.pathExists as jest.Mock).mockResolvedValueOnce(true).mockResolvedValueOnce(false);
|
||||
jest.mocked(findProjectIdByAccountNameAndSlugNullableAsync).mockResolvedValue(null);
|
||||
|
||||
await findAvailableProjectNameAsync(jester, 'test-project', '/base/path', mockOptions);
|
||||
|
||||
logSpy.expectLogToContain('Using alternate project name:');
|
||||
expect(result).toEqual({
|
||||
projectName: expect.stringMatching(/^test-project-[a-zA-Z0-9_-]{6}$/),
|
||||
projectDirectory: expect.stringContaining('/base/path/test-project-'),
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,7 +1,6 @@
|
||||
import { ExpoConfig } from '@expo/config';
|
||||
import fs from 'fs-extra';
|
||||
|
||||
import { LogSpy } from './testUtils';
|
||||
import { getEASUpdateURL } from '../../../api';
|
||||
import { AppFragment } from '../../../graphql/generated';
|
||||
import { easCliVersion } from '../../../utils/easCli';
|
||||
@@ -18,12 +17,6 @@ jest.mock('../../../api');
|
||||
jest.mock('fs-extra');
|
||||
|
||||
describe('projectFiles', () => {
|
||||
let logSpy: LogSpy;
|
||||
|
||||
beforeAll(() => {
|
||||
logSpy = new LogSpy('withTick');
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
|
||||
@@ -33,10 +26,7 @@ describe('projectFiles', () => {
|
||||
jest.mocked(fs.copy).mockImplementation(() => Promise.resolve());
|
||||
jest.mocked(fs.remove).mockImplementation(() => Promise.resolve());
|
||||
jest.mocked(fs.readFile).mockImplementation(() => Promise.resolve(''));
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
logSpy.restore();
|
||||
jest.mocked(fs.symlink).mockImplementation(() => Promise.resolve());
|
||||
});
|
||||
|
||||
describe('cleanAndPrefix', () => {
|
||||
@@ -128,8 +118,6 @@ describe('projectFiles', () => {
|
||||
expect(fs.writeJson).toHaveBeenCalledWith(`${projectDir}/app.json`, expectedConfig, {
|
||||
spaces: 2,
|
||||
});
|
||||
|
||||
logSpy.expectLogToContain('Generated app.json');
|
||||
});
|
||||
|
||||
it('should handle invalid characters in the bundle identifier', async () => {
|
||||
@@ -247,8 +235,6 @@ describe('projectFiles', () => {
|
||||
expect(fs.writeJson).toHaveBeenCalledWith(`${projectDir}/eas.json`, expectedEasConfig, {
|
||||
spaces: 2,
|
||||
});
|
||||
|
||||
logSpy.expectLogToContain('Generated eas.json');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -265,7 +251,7 @@ describe('projectFiles', () => {
|
||||
name: 'test-app',
|
||||
version: '1.0.0',
|
||||
scripts: {
|
||||
preview: 'npx eas-cli@latest workflow:run publish-preview-update.yml',
|
||||
draft: 'npx eas-cli@latest workflow:run create-draft.yml',
|
||||
'development-builds': 'npx eas-cli@latest workflow:run create-development-builds.yml',
|
||||
deploy: 'npx eas-cli@latest workflow:run deploy-to-production.yml',
|
||||
},
|
||||
@@ -274,8 +260,6 @@ describe('projectFiles', () => {
|
||||
expect(fs.writeJson).toHaveBeenCalledWith(`${projectDir}/package.json`, expectedPackageJson, {
|
||||
spaces: 2,
|
||||
});
|
||||
|
||||
logSpy.expectLogToContain('Updated package.json with scripts');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -286,12 +270,14 @@ describe('projectFiles', () => {
|
||||
await copyProjectTemplatesAsync(projectDir);
|
||||
|
||||
expect(fs.copy).toHaveBeenCalledWith(
|
||||
expect.stringContaining('templates/.eas/workflows'),
|
||||
expect.stringContaining('.eas/workflows'),
|
||||
{ errorOnExist: false, overwrite: true }
|
||||
expect.stringContaining('templates'),
|
||||
projectDir,
|
||||
expect.objectContaining({
|
||||
errorOnExist: false,
|
||||
overwrite: true,
|
||||
filter: expect.any(Function),
|
||||
})
|
||||
);
|
||||
|
||||
logSpy.expectLogToContain('Created EAS workflow files');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -342,8 +328,6 @@ Install the dependencies first.`;
|
||||
projectReadmePath,
|
||||
expect.stringMatching(new RegExp(headings.join('[\\s\\S]*')))
|
||||
);
|
||||
|
||||
logSpy.expectLogToContain('Updated README.md with EAS configuration details');
|
||||
});
|
||||
|
||||
it('should replace npm run with package manager specific commands', async () => {
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import path from 'path';
|
||||
|
||||
import { printDirectory } from '../utils';
|
||||
|
||||
describe('utils', () => {
|
||||
describe('printDirectory', () => {
|
||||
let cwdSpy: jest.SpyInstance;
|
||||
|
||||
beforeEach(() => {
|
||||
// Mock process.cwd() to return a predictable value
|
||||
cwdSpy = jest.spyOn(process, 'cwd').mockReturnValue('/Users/test/projects');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('should return "." for the current directory', () => {
|
||||
const result = printDirectory('/Users/test/projects');
|
||||
expect(result).toBe('.');
|
||||
});
|
||||
|
||||
it('should return relative path with "./" prefix for subdirectory', () => {
|
||||
const result = printDirectory('/Users/test/projects/my-app');
|
||||
expect(result).toBe('./my-app');
|
||||
});
|
||||
|
||||
it('should return relative path with "./" prefix for nested subdirectory', () => {
|
||||
const result = printDirectory('/Users/test/projects/nested/my-app');
|
||||
expect(result).toBe('./nested/my-app');
|
||||
});
|
||||
|
||||
it('should return absolute path for directory outside cwd', () => {
|
||||
const result = printDirectory('/Users/other/projects/my-app');
|
||||
expect(result).toBe('/Users/other/projects/my-app');
|
||||
});
|
||||
|
||||
it('should return absolute path for parent directory', () => {
|
||||
const result = printDirectory('/Users/test');
|
||||
expect(result).toBe('/Users/test');
|
||||
});
|
||||
|
||||
it('should handle relative paths and convert them correctly', () => {
|
||||
// Relative path resolves to absolute first, then converts back to relative
|
||||
const result = printDirectory('my-app');
|
||||
expect(result).toBe('./my-app');
|
||||
});
|
||||
|
||||
it('should handle relative paths with "./" already', () => {
|
||||
const result = printDirectory('./my-app');
|
||||
expect(result).toBe('./my-app');
|
||||
});
|
||||
|
||||
it('should handle relative paths with "../" (goes outside cwd)', () => {
|
||||
const result = printDirectory('../other-project');
|
||||
// This goes outside cwd, so should return absolute path
|
||||
expect(result).toBe('/Users/test/other-project');
|
||||
});
|
||||
|
||||
it('should handle complex relative paths', () => {
|
||||
const result = printDirectory('./nested/deep/project');
|
||||
expect(result).toBe('./nested/deep/project');
|
||||
});
|
||||
|
||||
it('should normalize paths correctly', () => {
|
||||
const result = printDirectory('/Users/test/projects/./my-app/../my-app');
|
||||
expect(result).toBe('./my-app');
|
||||
});
|
||||
|
||||
it('should handle paths in real cwd', () => {
|
||||
// Restore mock to test with real cwd
|
||||
cwdSpy.mockRestore();
|
||||
const realCwd = process.cwd();
|
||||
|
||||
// Test with current directory
|
||||
const result1 = printDirectory(realCwd);
|
||||
expect(result1).toBe('.');
|
||||
|
||||
// Test with subdirectory
|
||||
const subDir = path.join(realCwd, 'test-dir');
|
||||
const result2 = printDirectory(subDir);
|
||||
expect(result2).toBe('./test-dir');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,17 +1,20 @@
|
||||
import chalk from 'chalk';
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
|
||||
import Log from '../../log';
|
||||
import { printDirectory } from './utils';
|
||||
import { canAccessRepositoryUsingSshAsync, runGitCloneAsync } from '../../onboarding/git';
|
||||
import { PackageManager, installDependenciesAsync } from '../../onboarding/installDependencies';
|
||||
import { runCommandAsync } from '../../onboarding/runCommand';
|
||||
import { ora } from '../../ora';
|
||||
|
||||
export async function cloneTemplateAsync(targetProjectDir: string): Promise<string> {
|
||||
const githubUsername = 'expo';
|
||||
const githubRepositoryName = 'expo-template-default';
|
||||
|
||||
Log.log(`📂 Cloning the project to ${targetProjectDir}`);
|
||||
Log.newLine();
|
||||
const spinner = ora(
|
||||
`${chalk.bold(`Cloning the project to ${printDirectory(targetProjectDir)}`)}`
|
||||
).start();
|
||||
|
||||
const cloneMethod = (await canAccessRepositoryUsingSshAsync({
|
||||
githubUsername,
|
||||
@@ -25,8 +28,11 @@ export async function cloneTemplateAsync(targetProjectDir: string): Promise<stri
|
||||
githubRepositoryName,
|
||||
targetProjectDir,
|
||||
cloneMethod,
|
||||
showOutput: false,
|
||||
});
|
||||
|
||||
spinner.succeed(`Cloned the project to ${printDirectory(finalTargetProjectDirectory)}`);
|
||||
|
||||
return finalTargetProjectDirectory;
|
||||
}
|
||||
|
||||
@@ -34,6 +40,7 @@ export async function installProjectDependenciesAsync(
|
||||
projectDir: string,
|
||||
packageManager: PackageManager
|
||||
): Promise<void> {
|
||||
const spinner = ora(`${chalk.bold('Installing project dependencies')}`).start();
|
||||
await installDependenciesAsync({
|
||||
outputLevel: 'none',
|
||||
projectDir,
|
||||
@@ -42,16 +49,20 @@ export async function installProjectDependenciesAsync(
|
||||
|
||||
const dependencies = ['expo-updates', '@expo/metro-runtime'];
|
||||
for (const dependency of dependencies) {
|
||||
spinner.text = `Installing ${chalk.bold(dependency)}`;
|
||||
await runCommandAsync({
|
||||
cwd: projectDir,
|
||||
command: 'npx',
|
||||
args: ['expo', 'install', dependency],
|
||||
showOutput: false,
|
||||
showSpinner: false,
|
||||
});
|
||||
}
|
||||
spinner.succeed(`Installed project dependencies`);
|
||||
}
|
||||
|
||||
export async function initializeGitRepositoryAsync(projectDir: string): Promise<void> {
|
||||
const spinner = ora(`${chalk.bold('Initializing Git repository')}`).start();
|
||||
await fs.remove(path.join(projectDir, '.git'));
|
||||
|
||||
const commands = [['init'], ['add', '.'], ['commit', '-m', 'Initial commit']];
|
||||
@@ -62,7 +73,8 @@ export async function initializeGitRepositoryAsync(projectDir: string): Promise<
|
||||
command: 'git',
|
||||
args,
|
||||
showOutput: false,
|
||||
showSpinner: false,
|
||||
});
|
||||
Log.log();
|
||||
}
|
||||
spinner.succeed(`Initialized Git repository`);
|
||||
}
|
||||
@@ -2,11 +2,12 @@ import fs from 'fs-extra';
|
||||
import { nanoid } from 'nanoid';
|
||||
import path from 'path';
|
||||
|
||||
import { printDirectory } from './utils';
|
||||
import { Role } from '../../graphql/generated';
|
||||
import Log from '../../log';
|
||||
import { findProjectIdByAccountNameAndSlugNullableAsync } from '../../project/fetchOrCreateProjectIDForWriteToConfigWithConfirmationAsync';
|
||||
import { Choice, promptAsync } from '../../prompts';
|
||||
import { Actor, getActorUsername } from '../../user/User';
|
||||
import { Actor } from '../../user/User';
|
||||
import { ExpoGraphqlClient } from '../context/contextUtils/createGraphqlClient';
|
||||
|
||||
function validateProjectPath(resolvedPath: string): void {
|
||||
@@ -31,7 +32,6 @@ function validateProjectPath(resolvedPath: string): void {
|
||||
}
|
||||
|
||||
export async function generateProjectConfigAsync(
|
||||
actor: Actor,
|
||||
pathArg: string | undefined,
|
||||
options: {
|
||||
graphqlClient: ExpoGraphqlClient;
|
||||
@@ -41,7 +41,7 @@ export async function generateProjectConfigAsync(
|
||||
projectName: string;
|
||||
projectDirectory: string;
|
||||
}> {
|
||||
let baseName = 'new-expo-project';
|
||||
let baseName = 'expo-project';
|
||||
let parentDirectory = process.cwd();
|
||||
|
||||
if (pathArg) {
|
||||
@@ -49,17 +49,26 @@ export async function generateProjectConfigAsync(
|
||||
validateProjectPath(resolvedPath);
|
||||
baseName = path.basename(resolvedPath);
|
||||
parentDirectory = path.dirname(resolvedPath);
|
||||
} else {
|
||||
baseName = (
|
||||
await promptAsync({
|
||||
type: 'text',
|
||||
name: 'name',
|
||||
message: 'What would you like to name your project?',
|
||||
initial: 'expo-project',
|
||||
})
|
||||
).name;
|
||||
}
|
||||
|
||||
// Find an available name checking both local filesystem and remote server
|
||||
const { projectName, projectDirectory } = await findAvailableProjectNameAsync(
|
||||
actor,
|
||||
baseName,
|
||||
parentDirectory,
|
||||
options
|
||||
);
|
||||
|
||||
Log.withInfo(`Using project directory: ${projectDirectory}`);
|
||||
Log.withInfo(`Using project name: ${projectName}`);
|
||||
Log.withInfo(`Using project directory: ${printDirectory(projectDirectory)}`);
|
||||
|
||||
return {
|
||||
projectName,
|
||||
@@ -130,17 +139,6 @@ export function getAccountChoices(actor: Actor, permissionsMap?: Map<string, boo
|
||||
});
|
||||
}
|
||||
|
||||
export function generateProjectNameVariations(actor: Actor, baseName: string): string[] {
|
||||
const username = getActorUsername(actor);
|
||||
const date = new Date().toISOString().split('T')[0];
|
||||
|
||||
return [
|
||||
baseName,
|
||||
`${baseName}-${username}-${date}`,
|
||||
`${baseName}-${username}-${date}-${nanoid(6)}`,
|
||||
];
|
||||
}
|
||||
|
||||
async function verifyProjectDoesNotExistAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
accountName: string,
|
||||
@@ -167,7 +165,6 @@ async function verifyProjectDoesNotExistAsync(
|
||||
* Remote server (project already exists on Expo)
|
||||
*/
|
||||
export async function findAvailableProjectNameAsync(
|
||||
actor: Actor,
|
||||
baseName: string,
|
||||
parentDirectory: string,
|
||||
{
|
||||
@@ -178,37 +175,24 @@ export async function findAvailableProjectNameAsync(
|
||||
projectAccount: string;
|
||||
}
|
||||
): Promise<{ projectName: string; projectDirectory: string }> {
|
||||
const nameVariations = generateProjectNameVariations(actor, baseName);
|
||||
let projectName = baseName;
|
||||
let projectDirectory = path.join(parentDirectory, projectName);
|
||||
|
||||
for (let i = 0; i < nameVariations.length; i++) {
|
||||
const nameVariation = nameVariations[i];
|
||||
const proposedDirectory = path.join(parentDirectory, nameVariation);
|
||||
const usingVariant = i !== 0;
|
||||
const localExists = await fs.pathExists(projectDirectory);
|
||||
|
||||
const localExists = await fs.pathExists(proposedDirectory);
|
||||
if (localExists) {
|
||||
continue;
|
||||
}
|
||||
const remoteAvailable = await verifyProjectDoesNotExistAsync(
|
||||
graphqlClient,
|
||||
projectAccount,
|
||||
projectName
|
||||
);
|
||||
|
||||
const remoteAvailable = await verifyProjectDoesNotExistAsync(
|
||||
graphqlClient,
|
||||
projectAccount,
|
||||
nameVariation,
|
||||
{ silent: usingVariant }
|
||||
);
|
||||
if (!remoteAvailable) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Log.withInfo(`Using ${usingVariant ? 'alternate ' : ''}project name: ${nameVariation}`);
|
||||
|
||||
return {
|
||||
projectName: nameVariation,
|
||||
projectDirectory: proposedDirectory,
|
||||
};
|
||||
if (localExists || !remoteAvailable) {
|
||||
projectName = `${baseName}-${nanoid(6)}`;
|
||||
projectDirectory = path.join(parentDirectory, projectName);
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`Unable to find a unique project name for "${baseName}". All generated variations already exist.`
|
||||
);
|
||||
return {
|
||||
projectName,
|
||||
projectDirectory,
|
||||
};
|
||||
}
|
||||
@@ -1,13 +1,11 @@
|
||||
import { ExpoConfig } from '@expo/config';
|
||||
import { AppVersionSource, EasJson } from '@expo/eas-json';
|
||||
import chalk from 'chalk';
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
import merge from 'ts-deepmerge';
|
||||
|
||||
import { getEASUpdateURL } from '../../api';
|
||||
import { AppFragment } from '../../graphql/generated';
|
||||
import Log, { learnMore } from '../../log';
|
||||
import { PackageManager } from '../../onboarding/installDependencies';
|
||||
import { easCliVersion } from '../../utils/easCli';
|
||||
|
||||
@@ -63,12 +61,6 @@ export async function generateAppConfigAsync(projectDir: string, app: AppFragmen
|
||||
|
||||
const appJsonPath = path.join(projectDir, 'app.json');
|
||||
await fs.writeJson(appJsonPath, { expo: mergedConfig }, { spaces: 2 });
|
||||
Log.withTick(
|
||||
`Generated ${chalk.bold('app.json')}. ${learnMore(
|
||||
'https://docs.expo.dev/versions/latest/config/app/'
|
||||
)}`
|
||||
);
|
||||
Log.log();
|
||||
}
|
||||
|
||||
export async function generateEasConfigAsync(projectDir: string): Promise<void> {
|
||||
@@ -116,12 +108,6 @@ export async function generateEasConfigAsync(projectDir: string): Promise<void>
|
||||
|
||||
const easJsonPath = path.join(projectDir, 'eas.json');
|
||||
await fs.writeJson(easJsonPath, easJson, { spaces: 2 });
|
||||
Log.withTick(
|
||||
`Generated ${chalk.bold('eas.json')}. ${learnMore(
|
||||
'https://docs.expo.dev/build-reference/eas-json/'
|
||||
)}`
|
||||
);
|
||||
Log.log();
|
||||
}
|
||||
|
||||
export async function updatePackageJsonAsync(projectDir: string): Promise<void> {
|
||||
@@ -131,27 +117,25 @@ export async function updatePackageJsonAsync(projectDir: string): Promise<void>
|
||||
if (!packageJson.scripts) {
|
||||
packageJson.scripts = {};
|
||||
}
|
||||
packageJson.scripts.preview = 'npx eas-cli@latest workflow:run publish-preview-update.yml';
|
||||
packageJson.scripts.draft = 'npx eas-cli@latest workflow:run create-draft.yml';
|
||||
packageJson.scripts['development-builds'] =
|
||||
'npx eas-cli@latest workflow:run create-development-builds.yml';
|
||||
packageJson.scripts.deploy = 'npx eas-cli@latest workflow:run deploy-to-production.yml';
|
||||
|
||||
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
||||
Log.withTick('Updated package.json with scripts');
|
||||
Log.log();
|
||||
}
|
||||
|
||||
export async function copyProjectTemplatesAsync(projectDir: string): Promise<void> {
|
||||
const templatesSourceDir = path.join(__dirname, 'templates', '.eas', 'workflows');
|
||||
const easWorkflowsTargetDir = path.join(projectDir, '.eas', 'workflows');
|
||||
const templatesSourceDir = path.join(__dirname, 'templates');
|
||||
|
||||
await fs.copy(templatesSourceDir, easWorkflowsTargetDir, {
|
||||
// Copy everything from templates to projectDir, skipping readme-additions.md
|
||||
await fs.copy(templatesSourceDir, projectDir, {
|
||||
overwrite: true,
|
||||
errorOnExist: false,
|
||||
filter: (src: string) => {
|
||||
return !src.endsWith('readme-additions.md');
|
||||
},
|
||||
});
|
||||
|
||||
Log.withTick('Created EAS workflow files');
|
||||
Log.log();
|
||||
}
|
||||
|
||||
export async function updateReadmeAsync(
|
||||
@@ -189,7 +173,4 @@ export async function updateReadmeAsync(
|
||||
mergedReadme = mergedReadme.replaceAll('npm run', `${packageManager} run`);
|
||||
|
||||
await fs.writeFile(projectReadmePath, mergedReadme);
|
||||
|
||||
Log.withTick('Updated README.md with EAS configuration details');
|
||||
Log.log();
|
||||
}
|
||||
+4
-1
@@ -1,4 +1,4 @@
|
||||
name: Publish preview update
|
||||
name: Create draft
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -10,3 +10,6 @@ jobs:
|
||||
type: update
|
||||
params:
|
||||
branch: ${{ github.ref_name || 'test' }}
|
||||
deploy_website:
|
||||
name: Deploy website
|
||||
type: deploy
|
||||
@@ -0,0 +1,163 @@
|
||||
# AGENTS.md
|
||||
|
||||
## Project Overview
|
||||
|
||||
This is an Expo/React Native mobile application. Prioritize mobile-first patterns, performance, and cross-platform compatibility.
|
||||
|
||||
## Documentation Resources
|
||||
|
||||
When working on this project, **always consult the official Expo documentation** available at:
|
||||
|
||||
- **https://docs.expo.dev/llms.txt** - Index of all available documentation files
|
||||
- **https://docs.expo.dev/llms-full.txt** - Complete Expo documentation including Expo Router, Expo Modules API, development process
|
||||
- **https://docs.expo.dev/llms-eas.txt** - Complete EAS (Expo Application Services) documentation
|
||||
- **https://docs.expo.dev/llms-sdk.txt** - Complete Expo SDK documentation
|
||||
- **https://reactnative.dev/docs/getting-started** - Complete React Native documentation
|
||||
|
||||
These documentation files are specifically formatted for AI agents and should be your **primary reference** for:
|
||||
|
||||
- Expo APIs and best practices
|
||||
- Expo Router navigation patterns
|
||||
- EAS Build, Submit, and Update workflows
|
||||
- Expo SDK modules and their usage
|
||||
- Development and deployment processes
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
/
|
||||
├── app/ # Expo Router file-based routing
|
||||
│ ├── (tabs)/ # Tab-based navigation screens
|
||||
│ │ ├── index.tsx # Home screen
|
||||
│ │ ├── explore.tsx # Explore screen
|
||||
│ │ └── _layout.tsx # Tabs layout
|
||||
│ ├── _layout.tsx # Root layout with theme provider
|
||||
│ └── modal.tsx # Modal screen example
|
||||
├── components/ # Reusable React components
|
||||
│ ├── ui/ # UI primitives (IconSymbol, Collapsible)
|
||||
│ └── ... # Feature components (themed, haptic, parallax)
|
||||
├── constants/ # App-wide constants (theme, colors)
|
||||
├── hooks/ # Custom React hooks (color scheme, theme)
|
||||
├── assets/ # Static assets (images, fonts)
|
||||
├── scripts/ # Utility scripts (reset-project)
|
||||
├── .eas/workflows/ # EAS Workflows (CI/CD automation)
|
||||
├── app.json # Expo configuration
|
||||
├── eas.json # EAS Build/Submit configuration
|
||||
└── package.json # Dependencies and scripts
|
||||
```
|
||||
|
||||
## Essential Commands
|
||||
|
||||
### Development
|
||||
|
||||
```bash
|
||||
npx expo start # Start dev server
|
||||
npx expo start --clear # Clear cache and start dev server
|
||||
npx expo install <package> # Install packages with compatible versions
|
||||
npx expo install --check # Check which installed packages need to be updated
|
||||
npx expo install --fix # Automatically update any invalid package versions
|
||||
npm run development-builds # Create development builds (workflow)
|
||||
npm run reset-project # Reset to blank template
|
||||
```
|
||||
|
||||
### Building & Testing
|
||||
|
||||
```bash
|
||||
npx expo doctor # Check project health and dependencies
|
||||
npx expo lint # Run ESLint
|
||||
npm run draft # Publish preview update and website (workflow)
|
||||
```
|
||||
|
||||
### Production
|
||||
|
||||
```bash
|
||||
npx eas-cli@latest build --platform ios -s # Use EAS to build for iOS platform and submit to App Store
|
||||
npx eas-cli@latest build --platform android -s # Use EAS to build for Android platform and submit to Google Play Store
|
||||
npm run deploy # Deploy to production (workflow)
|
||||
```
|
||||
|
||||
## Development Guidelines
|
||||
|
||||
### Code Style & Standards
|
||||
|
||||
- **TypeScript First**: Use TypeScript for all new code with strict type checking
|
||||
- **Naming Conventions**: Use meaningful, descriptive names for variables, functions, and components
|
||||
- **Self-Documenting Code**: Write clear, readable code that explains itself; only add comments for complex business logic or design decisions
|
||||
- **React 19 Patterns**: Follow modern React patterns including:
|
||||
- Function components with hooks
|
||||
- Enable React Compiler
|
||||
- Proper dependency arrays in useEffect
|
||||
- Memoization when appropriate (useMemo, useCallback)
|
||||
- Error boundaries for better error handling
|
||||
|
||||
### Navigation & Routing
|
||||
|
||||
- Use **Expo Router** for all navigation
|
||||
- Import `Link`, `router`, and `useLocalSearchParams` from `expo-router`
|
||||
- Docs: https://docs.expo.dev/router/introduction/
|
||||
|
||||
### Recommended Libraries
|
||||
|
||||
- **Navigation**: `expo-router` for navigation
|
||||
- **Images**: `expo-image` for optimized image handling and caching
|
||||
- **Animations**: `react-native-reanimated` for performant animations on native thread
|
||||
- **Gestures**: `react-native-gesture-handler` for native gesture recognition
|
||||
- **Storage**: Use `expo-sqlite` for persistent storage, `expo-sqlite/kv-store` for simple key-value storage
|
||||
|
||||
## Debugging & Development Tools
|
||||
|
||||
### DevTools Integration
|
||||
|
||||
- **React Native DevTools**: Use MCP `open_devtools` command to launch debugging tools
|
||||
- **Network Inspection**: Monitor API calls and network requests in DevTools
|
||||
- **Element Inspector**: Debug component hierarchy and styles
|
||||
- **Performance Profiler**: Identify performance bottlenecks
|
||||
- **Logging**: Use `console.log` for debugging (remove before production), `console.warn` for deprecation notices, `console.error` for actual errors, and implement error boundaries for production error handling
|
||||
|
||||
### Testing & Quality Assurance
|
||||
|
||||
#### Automated Testing with MCP Tools
|
||||
|
||||
Developers can configure the Expo MCP server with the following doc: https://docs.expo.dev/eas/ai/mcp/
|
||||
|
||||
- **Component Testing**: Add `testID` props to components for automation
|
||||
- **Visual Testing**: Use MCP `automation_take_screenshot` to verify UI appearance
|
||||
- **Interaction Testing**: Use MCP `automation_tap_by_testid` to simulate user interactions
|
||||
- **View Verification**: Use MCP `automation_find_view_by_testid` to validate component rendering
|
||||
|
||||
## EAS Workflows CI/CD
|
||||
|
||||
This project is pre-configured with **EAS Workflows** for automating development and release processes. Workflows are defined in `.eas/workflows/` directory.
|
||||
|
||||
When working with EAS Workflows, **always refer to**:
|
||||
|
||||
- https://docs.expo.dev/eas/workflows/ for workflow examples
|
||||
- The `.eas/workflows/` directory for existing workflow configurations
|
||||
- You can check that a workflow YAML is valid using the workflows schema: https://exp.host/--/api/v2/workflows/schema
|
||||
|
||||
### Build Profiles (eas.json)
|
||||
|
||||
- **development**: Development builds with dev client
|
||||
- **development-simulator**: Development builds for iOS simulator
|
||||
- **preview**: Internal distribution preview builds
|
||||
- **production**: Production builds with auto-increment
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Expo Go Errors & Development Builds
|
||||
|
||||
If there are errors in **Expo Go** or the project is not running, create a **development build**. **Expo Go** is a sandbox environment with a limited set of native modules. To create development builds, run `eas build:dev`. Additionally, after installing new packages or adding config plugins, new development builds are often required.
|
||||
|
||||
## AI Agent Instructions
|
||||
|
||||
When working on this project:
|
||||
|
||||
1. **Always start by consulting the appropriate documentation**:
|
||||
|
||||
- For general Expo questions: https://docs.expo.dev/llms-full.txt
|
||||
- For EAS/deployment questions: https://docs.expo.dev/llms-eas.txt
|
||||
- For SDK/API questions: https://docs.expo.dev/llms-sdk.txt
|
||||
|
||||
2. **Understand before implementing**: Read the relevant docs section before writing code
|
||||
|
||||
3. **Follow existing patterns**: Look at existing components and screens for patterns to follow
|
||||
@@ -0,0 +1,9 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
**Note**: This project uses `AGENTS.md` files for detailed guidance.
|
||||
|
||||
## Primary Reference
|
||||
|
||||
Please see `AGENTS.md` in this same directory for the main project documentation and guidance.
|
||||
@@ -21,7 +21,7 @@ This project is configured to use [EAS Workflows](https://docs.expo.dev/eas/work
|
||||
|
||||
### Previews
|
||||
|
||||
Run `npm run preview` to [publish a preview update](https://docs.expo.dev/eas/workflows/examples/publish-preview-update/) of your project, which can be viewed in Expo Go or in a development build.
|
||||
Run `npm run draft` to [publish a preview update](https://docs.expo.dev/eas/workflows/examples/publish-preview-update/) of your project, which can be viewed in Expo Go or in a development build.
|
||||
|
||||
### Development Builds
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import path from 'path';
|
||||
|
||||
/**
|
||||
* Formats a directory path for display.
|
||||
* If the directory is within the current working directory, returns a relative path.
|
||||
* Otherwise, returns the absolute path.
|
||||
*/
|
||||
export function printDirectory(directory: string): string {
|
||||
const cwd = process.cwd();
|
||||
const absoluteDir = path.isAbsolute(directory) ? directory : path.resolve(cwd, directory);
|
||||
|
||||
const relativePath = path.relative(cwd, absoluteDir);
|
||||
|
||||
// If the relative path doesn't start with '..' it means it's within or at the cwd
|
||||
if (!relativePath.startsWith('..') && !path.isAbsolute(relativePath)) {
|
||||
return relativePath !== '' ? `./${relativePath}` : '.';
|
||||
}
|
||||
|
||||
return absoluteDir;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import chalk from 'chalk';
|
||||
import * as fs from 'node:fs';
|
||||
|
||||
import { fetchRawLogsForBuildJobAsync, fetchRawLogsForCustomJobAsync } from './fetchLogs';
|
||||
@@ -11,14 +12,18 @@ import {
|
||||
import {
|
||||
WorkflowJobStatus,
|
||||
WorkflowJobType,
|
||||
WorkflowRunByIdQuery,
|
||||
WorkflowRunByIdWithJobsQuery,
|
||||
WorkflowRunFragment,
|
||||
WorkflowRunStatus,
|
||||
WorkflowRunTriggerEventType,
|
||||
} from '../../graphql/generated';
|
||||
import { WorkflowRunQuery } from '../../graphql/queries/WorkflowRunQuery';
|
||||
import Log from '../../log';
|
||||
import { ora } from '../../ora';
|
||||
import { Choice } from '../../prompts';
|
||||
import formatFields from '../../utils/formatFields';
|
||||
import { sleepAsync } from '../../utils/promise';
|
||||
import { ExpoGraphqlClient } from '../context/contextUtils/createGraphqlClient';
|
||||
|
||||
export function computeTriggerInfoForWorkflowRun(run: WorkflowRunFragment): {
|
||||
@@ -218,10 +223,12 @@ export async function infoForActiveWorkflowRunAsync(
|
||||
|
||||
export async function infoForFailedWorkflowRunAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
workflowRun: WorkflowRunByIdWithJobsQuery['workflowRuns']['byId']
|
||||
workflowRun: WorkflowRunByIdWithJobsQuery['workflowRuns']['byId'],
|
||||
maxLogLines: number = -1 // -1 means no limit
|
||||
): Promise<string> {
|
||||
const statusLines = [];
|
||||
const statusValues = [];
|
||||
const logLinesToKeep = maxLogLines === -1 ? Infinity : maxLogLines;
|
||||
for (const job of workflowRun.jobs) {
|
||||
if (job.status !== WorkflowJobStatus.Failure) {
|
||||
continue;
|
||||
@@ -233,7 +240,7 @@ export async function infoForFailedWorkflowRunAsync(
|
||||
if (steps.length > 0) {
|
||||
const failedStep = steps.find(step => step.status === 'fail');
|
||||
if (failedStep) {
|
||||
const logs = failedStep.logLines?.map(line => line.msg) ?? [];
|
||||
const logs = failedStep.logLines?.map(line => line.msg).slice(-logLinesToKeep) ?? [];
|
||||
statusValues.push({ label: ' Failed step', value: failedStep.name });
|
||||
statusValues.push({
|
||||
label: ' Logs for failed step',
|
||||
@@ -283,3 +290,84 @@ export async function maybeReadStdinAsync(): Promise<string | null> {
|
||||
});
|
||||
});
|
||||
}
|
||||
export async function showWorkflowStatusAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
{
|
||||
workflowRunId,
|
||||
spinnerUsesStdErr,
|
||||
waitForCompletion = true,
|
||||
}: { workflowRunId: string; spinnerUsesStdErr: boolean; waitForCompletion?: boolean }
|
||||
): Promise<WorkflowRunByIdQuery['workflowRuns']['byId']> {
|
||||
Log.log('Waiting for workflow run to complete. You can press Ctrl+C to exit.');
|
||||
|
||||
const spinner = ora({
|
||||
stream: spinnerUsesStdErr ? process.stderr : process.stdout,
|
||||
text: '',
|
||||
}).start();
|
||||
spinner.prefixText = chalk`{bold.yellow Workflow run is waiting to start:}`;
|
||||
|
||||
let failedFetchesCount = 0;
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
const workflowRun = await WorkflowRunQuery.withJobsByIdAsync(graphqlClient, workflowRunId, {
|
||||
useCache: false,
|
||||
});
|
||||
|
||||
failedFetchesCount = 0;
|
||||
|
||||
switch (workflowRun.status) {
|
||||
case WorkflowRunStatus.New:
|
||||
break;
|
||||
case WorkflowRunStatus.InProgress: {
|
||||
spinner.prefixText = chalk`{bold.green Workflow run is in progress:}`;
|
||||
spinner.text = await infoForActiveWorkflowRunAsync(graphqlClient, workflowRun, 5);
|
||||
break;
|
||||
}
|
||||
case WorkflowRunStatus.ActionRequired:
|
||||
spinner.prefixText = chalk`{bold.yellow Workflow run is waiting for action:}`;
|
||||
break;
|
||||
|
||||
case WorkflowRunStatus.Canceled:
|
||||
spinner.prefixText = chalk`{bold.yellow Workflow has been canceled.}`;
|
||||
spinner.stopAndPersist();
|
||||
return workflowRun;
|
||||
|
||||
case WorkflowRunStatus.Failure: {
|
||||
spinner.prefixText = chalk`{bold.red Workflow has failed.}`;
|
||||
const failedInfo = await infoForFailedWorkflowRunAsync(graphqlClient, workflowRun, 30);
|
||||
spinner.fail(failedInfo);
|
||||
return workflowRun;
|
||||
}
|
||||
case WorkflowRunStatus.Success:
|
||||
spinner.prefixText = chalk`{bold.green Workflow has completed successfully.}`;
|
||||
spinner.text = '';
|
||||
spinner.succeed('');
|
||||
return workflowRun;
|
||||
}
|
||||
if (!waitForCompletion) {
|
||||
if (spinner.isSpinning) {
|
||||
spinner.stopAndPersist();
|
||||
}
|
||||
return workflowRun;
|
||||
}
|
||||
} catch {
|
||||
spinner.text = '⚠ Failed to fetch the workflow run status. Check your network connection.';
|
||||
|
||||
failedFetchesCount += 1;
|
||||
|
||||
if (failedFetchesCount > 6) {
|
||||
spinner.fail('Failed to fetch the workflow run status 6 times in a row. Aborting wait.');
|
||||
process.exit(workflowRunExitCodes.WAIT_ABORTED);
|
||||
}
|
||||
}
|
||||
|
||||
await sleepAsync(10 /* seconds */ * 1000 /* milliseconds */);
|
||||
}
|
||||
}
|
||||
|
||||
export const workflowRunExitCodes = {
|
||||
WORKFLOW_FAILED: 11,
|
||||
WORKFLOW_CANCELED: 12,
|
||||
WAIT_ABORTED: 13,
|
||||
};
|
||||
@@ -14,11 +14,13 @@ import { EasNonInteractiveAndJsonFlags } from '../../commandUtils/flags';
|
||||
import { StatuspageServiceName } from '../../graphql/generated';
|
||||
import Log, { link } from '../../log';
|
||||
import { RequestedPlatform, selectRequestedPlatformAsync } from '../../platform';
|
||||
import { getOwnerAccountForProjectIdAsync } from '../../project/projectUtils';
|
||||
import { selectAsync } from '../../prompts';
|
||||
import uniq from '../../utils/expodash/uniq';
|
||||
import { enableJsonOutput } from '../../utils/json';
|
||||
import { ProfileData } from '../../utils/profiles';
|
||||
import { maybeWarnAboutEasOutagesAsync } from '../../utils/statuspageService';
|
||||
import { maybeWarnAboutUsageOveragesAsync } from '../../utils/usage/checkForOverages';
|
||||
|
||||
interface RawBuildFlags {
|
||||
platform?: string;
|
||||
@@ -161,6 +163,13 @@ export default class Build extends EasCommand {
|
||||
? [StatuspageServiceName.EasBuild, StatuspageServiceName.EasSubmit]
|
||||
: [StatuspageServiceName.EasBuild]
|
||||
);
|
||||
|
||||
const { projectId } = await getDynamicPrivateProjectConfigAsync();
|
||||
const account = await getOwnerAccountForProjectIdAsync(graphqlClient, projectId);
|
||||
await maybeWarnAboutUsageOveragesAsync({
|
||||
graphqlClient,
|
||||
accountId: account.id,
|
||||
});
|
||||
}
|
||||
|
||||
const flagsWithPlatform = await this.ensurePlatformSelectedAsync(flags);
|
||||
|
||||
@@ -44,8 +44,6 @@ export default class WorkerAliasDelete extends EasCommand {
|
||||
enableJsonOutput();
|
||||
}
|
||||
|
||||
Log.warn('EAS Hosting is still in preview and subject to changes.');
|
||||
|
||||
const {
|
||||
getDynamicPrivateProjectConfigAsync,
|
||||
loggedIn: { graphqlClient },
|
||||
|
||||
@@ -73,8 +73,6 @@ export default class WorkerAlias extends EasCommand {
|
||||
enableJsonOutput();
|
||||
}
|
||||
|
||||
Log.warn('EAS Hosting is still in preview and subject to changes.');
|
||||
|
||||
const {
|
||||
getDynamicPrivateProjectConfigAsync,
|
||||
loggedIn: { graphqlClient },
|
||||
|
||||
@@ -45,8 +45,6 @@ export default class WorkerDelete extends EasCommand {
|
||||
enableJsonOutput();
|
||||
}
|
||||
|
||||
Log.warn('EAS Hosting is still in preview and subject to changes.');
|
||||
|
||||
const {
|
||||
getDynamicPrivateProjectConfigAsync,
|
||||
loggedIn: { graphqlClient },
|
||||
|
||||
@@ -120,8 +120,6 @@ export default class WorkerDeploy extends EasCommand {
|
||||
enableJsonOutput();
|
||||
}
|
||||
|
||||
Log.warn('EAS Hosting is still in preview and subject to changes.');
|
||||
|
||||
const {
|
||||
getDynamicPrivateProjectConfigAsync,
|
||||
loggedIn: { graphqlClient },
|
||||
|
||||
@@ -51,7 +51,15 @@ jest.mock('../../../project/expoConfig', () => ({
|
||||
|
||||
jest.mock('../../../prompts', () => ({
|
||||
...jest.requireActual('../../../prompts'),
|
||||
promptAsync: jest.fn().mockResolvedValue({ account: { name: 'jester' } }),
|
||||
promptAsync: jest.fn().mockImplementation(async (options: any) => {
|
||||
if (options.name === 'account') {
|
||||
return { account: { name: 'jester' } };
|
||||
}
|
||||
if (options.name === 'name') {
|
||||
return { name: options.initial || 'expo-project' };
|
||||
}
|
||||
return {};
|
||||
}),
|
||||
}));
|
||||
|
||||
describe(New.name, () => {
|
||||
@@ -62,8 +70,8 @@ describe(New.name, () => {
|
||||
|
||||
expect(result).toEqual({
|
||||
projectAccount: 'jester',
|
||||
projectDirectory: expect.stringContaining('/new-expo-project'),
|
||||
projectName: 'new-expo-project',
|
||||
projectDirectory: expect.stringContaining('/expo-project'),
|
||||
projectName: 'expo-project',
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
updatePackageJsonAsync,
|
||||
updateReadmeAsync,
|
||||
} from '../../commandUtils/new/projectFiles';
|
||||
import { printDirectory } from '../../commandUtils/new/utils';
|
||||
import { AppFragment } from '../../graphql/generated';
|
||||
import { AppMutation } from '../../graphql/mutations/AppMutation';
|
||||
import { AppQuery } from '../../graphql/queries/AppQuery';
|
||||
@@ -40,7 +41,7 @@ export async function generateConfigsAsync(
|
||||
projectAccount: string;
|
||||
}> {
|
||||
const projectAccount = await promptForProjectAccountAsync(actor);
|
||||
const { projectName, projectDirectory } = await generateProjectConfigAsync(actor, args.path, {
|
||||
const { projectName, projectDirectory } = await generateProjectConfigAsync(args.path, {
|
||||
graphqlClient,
|
||||
projectAccount,
|
||||
});
|
||||
@@ -92,7 +93,7 @@ export async function createProjectAsync({
|
||||
},
|
||||
{ skipSDKVersionRequirement: true }
|
||||
);
|
||||
Log.withTick(`Project successfully linked (ID: ${chalk.bold(projectId)}) (modified app.json)`);
|
||||
Log.withInfo(`Project successfully linked (ID: ${chalk.bold(projectId)})`);
|
||||
|
||||
return projectId;
|
||||
}
|
||||
@@ -102,6 +103,7 @@ export async function generateProjectFilesAsync(
|
||||
app: AppFragment,
|
||||
packageManager: PackageManager
|
||||
): Promise<void> {
|
||||
const spinner = ora(`Generating project files`).start();
|
||||
await generateAppConfigAsync(projectDir, app);
|
||||
|
||||
await generateEasConfigAsync(projectDir);
|
||||
@@ -111,6 +113,17 @@ export async function generateProjectFilesAsync(
|
||||
await copyProjectTemplatesAsync(projectDir);
|
||||
|
||||
await updateReadmeAsync(projectDir, packageManager);
|
||||
spinner.succeed(`Generated project files`);
|
||||
Log.withInfo(
|
||||
`Generated ${chalk.bold('app.json')}. ${learnMore(
|
||||
'https://docs.expo.dev/versions/latest/config/app/'
|
||||
)}`
|
||||
);
|
||||
Log.withInfo(
|
||||
`Generated ${chalk.bold('eas.json')}. ${learnMore(
|
||||
'https://docs.expo.dev/build-reference/eas-json/'
|
||||
)}`
|
||||
);
|
||||
}
|
||||
|
||||
export default class New extends EasCommand {
|
||||
@@ -136,8 +149,6 @@ export default class New extends EasCommand {
|
||||
}),
|
||||
};
|
||||
|
||||
static override hidden = true;
|
||||
|
||||
static override contextDefinition = {
|
||||
...this.ContextOptions.LoggedIn,
|
||||
};
|
||||
@@ -155,11 +166,7 @@ export default class New extends EasCommand {
|
||||
);
|
||||
}
|
||||
|
||||
Log.warn(
|
||||
'This command is not yet implemented. It will create a new project, but it may not be fully configured.'
|
||||
);
|
||||
Log.log(`👋 Welcome to Expo, ${actor.username}!`);
|
||||
Log.newLine();
|
||||
|
||||
const {
|
||||
projectName,
|
||||
@@ -186,19 +193,21 @@ export default class New extends EasCommand {
|
||||
await initializeGitRepositoryAsync(projectDirectory);
|
||||
|
||||
Log.log('🎉 We finished creating your new project.');
|
||||
Log.newLine();
|
||||
Log.log('Next steps:');
|
||||
Log.withInfo(`Run \`cd ${projectDirectory}\` to navigate to your project.`);
|
||||
Log.withInfo(
|
||||
`Run \`${packageManager} run preview\` to create a preview build on EAS. ${learnMore(
|
||||
`Run ${chalk.bold(`cd ${printDirectory(projectDirectory)}`)} to navigate to your project.`
|
||||
);
|
||||
Log.withInfo(
|
||||
`Run ${chalk.bold(`${packageManager} run draft`)} to create a preview on EAS. ${learnMore(
|
||||
'https://docs.expo.dev/eas/workflows/examples/publish-preview-update/'
|
||||
)}`
|
||||
);
|
||||
Log.withInfo(
|
||||
`Run \`${packageManager} run start\` to start developing locally. ${learnMore(
|
||||
`Run ${chalk.bold(`${packageManager} run start`)} to start developing locally. ${learnMore(
|
||||
'https://docs.expo.dev/get-started/start-developing/'
|
||||
)}`
|
||||
);
|
||||
Log.withInfo(`See the README.md for more information about your project.`);
|
||||
Log.newLine();
|
||||
Log.withInfo(`See the ${chalk.bold('README.md')} for more information about your project.`);
|
||||
}
|
||||
}
|
||||
@@ -44,12 +44,12 @@ import spawnAsync from '@expo/spawn-async';
|
||||
import { Flags } from '@oclif/core';
|
||||
import { CombinedError } from '@urql/core';
|
||||
import chalk from 'chalk';
|
||||
import { boolish } from 'getenv';
|
||||
import * as path from 'node:path';
|
||||
import slash from 'slash';
|
||||
|
||||
import { getWorkflowRunUrl } from '../../build/utils/url';
|
||||
import EasCommand from '../../commandUtils/EasCommand';
|
||||
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
import { EASNonInteractiveFlag, EasJsonOnlyFlag } from '../../commandUtils/flags';
|
||||
import {
|
||||
maybePromptForMissingInputsAsync,
|
||||
@@ -59,34 +59,25 @@ import {
|
||||
} from '../../commandUtils/workflow/inputs';
|
||||
import {
|
||||
fileExistsAsync,
|
||||
infoForActiveWorkflowRunAsync,
|
||||
infoForFailedWorkflowRunAsync,
|
||||
maybeReadStdinAsync,
|
||||
showWorkflowStatusAsync,
|
||||
workflowRunExitCodes,
|
||||
} from '../../commandUtils/workflow/utils';
|
||||
import {
|
||||
WorkflowProjectSourceType,
|
||||
WorkflowRevision,
|
||||
WorkflowRunByIdQuery,
|
||||
WorkflowRunStatus,
|
||||
} from '../../graphql/generated';
|
||||
import { WorkflowRevisionMutation } from '../../graphql/mutations/WorkflowRevisionMutation';
|
||||
import { WorkflowRunMutation } from '../../graphql/mutations/WorkflowRunMutation';
|
||||
import { WorkflowRunQuery } from '../../graphql/queries/WorkflowRunQuery';
|
||||
import Log, { link } from '../../log';
|
||||
import { ora } from '../../ora';
|
||||
import { getOwnerAccountForProjectIdAsync } from '../../project/projectUtils';
|
||||
import { uploadAccountScopedFileAsync } from '../../project/uploadAccountScopedFileAsync';
|
||||
import { uploadAccountScopedProjectSourceAsync } from '../../project/uploadAccountScopedProjectSourceAsync';
|
||||
import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
|
||||
import { sleepAsync } from '../../utils/promise';
|
||||
import { WorkflowFile } from '../../utils/workflowFile';
|
||||
|
||||
const EXIT_CODES = {
|
||||
WORKFLOW_FAILED: 11,
|
||||
WORKFLOW_CANCELED: 12,
|
||||
WAIT_ABORTED: 13,
|
||||
};
|
||||
|
||||
export default class WorkflowRun extends EasCommand {
|
||||
static override description =
|
||||
'run an EAS workflow. The entire local project directory will be packaged and uploaded to EAS servers for the workflow run, unless the --ref flag is used.';
|
||||
@@ -99,8 +90,7 @@ export default class WorkflowRun extends EasCommand {
|
||||
default: false,
|
||||
allowNo: true,
|
||||
description: 'Exit codes: 0 = success, 11 = failure, 12 = canceled, 13 = wait aborted.',
|
||||
summary:
|
||||
'Wait for workflow run to complete. Defaults to false. Cannot be used with the --json flag.',
|
||||
summary: 'Wait for workflow run to complete. Defaults to false.',
|
||||
}),
|
||||
input: Flags.string({
|
||||
char: 'F',
|
||||
@@ -129,9 +119,6 @@ export default class WorkflowRun extends EasCommand {
|
||||
const { flags, args } = await this.parse(WorkflowRun);
|
||||
|
||||
if (flags.json) {
|
||||
if (flags.wait) {
|
||||
throw new Error('Cannot use --json and --wait flags simultaneously.');
|
||||
}
|
||||
enableJsonOutput();
|
||||
}
|
||||
|
||||
@@ -370,9 +357,11 @@ export default class WorkflowRun extends EasCommand {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
Log.newLine();
|
||||
const { status } = await waitForWorkflowRunToEndAsync(graphqlClient, {
|
||||
const spinnerUsesStdErr = boolish('CI', false) || flags.json;
|
||||
|
||||
const { status } = await showWorkflowStatusAsync(graphqlClient, {
|
||||
workflowRunId,
|
||||
spinnerUsesStdErr,
|
||||
});
|
||||
|
||||
if (flags.json) {
|
||||
@@ -387,71 +376,9 @@ export default class WorkflowRun extends EasCommand {
|
||||
}
|
||||
|
||||
if (status === WorkflowRunStatus.Failure) {
|
||||
process.exit(EXIT_CODES.WORKFLOW_FAILED);
|
||||
process.exit(workflowRunExitCodes.WORKFLOW_FAILED);
|
||||
} else if (status === WorkflowRunStatus.Canceled) {
|
||||
process.exit(EXIT_CODES.WORKFLOW_CANCELED);
|
||||
process.exit(workflowRunExitCodes.WORKFLOW_CANCELED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function waitForWorkflowRunToEndAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
{ workflowRunId }: { workflowRunId: string }
|
||||
): Promise<WorkflowRunByIdQuery['workflowRuns']['byId']> {
|
||||
Log.log('Waiting for workflow run to complete. You can press Ctrl+C to exit.');
|
||||
|
||||
const spinner = ora('').start();
|
||||
spinner.prefixText = chalk`{bold.yellow Workflow run is waiting to start:}`;
|
||||
|
||||
let failedFetchesCount = 0;
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
const workflowRun = await WorkflowRunQuery.withJobsByIdAsync(graphqlClient, workflowRunId, {
|
||||
useCache: false,
|
||||
});
|
||||
|
||||
failedFetchesCount = 0;
|
||||
|
||||
switch (workflowRun.status) {
|
||||
case WorkflowRunStatus.New:
|
||||
break;
|
||||
case WorkflowRunStatus.InProgress: {
|
||||
spinner.prefixText = chalk`{bold.green Workflow run is in progress:}`;
|
||||
spinner.text = await infoForActiveWorkflowRunAsync(graphqlClient, workflowRun, 5);
|
||||
break;
|
||||
}
|
||||
case WorkflowRunStatus.ActionRequired:
|
||||
spinner.prefixText = chalk`{bold.yellow Workflow run is waiting for action:}`;
|
||||
break;
|
||||
|
||||
case WorkflowRunStatus.Canceled:
|
||||
spinner.prefixText = chalk`{bold.yellow Workflow has been canceled.}`;
|
||||
spinner.stopAndPersist();
|
||||
return workflowRun;
|
||||
|
||||
case WorkflowRunStatus.Failure: {
|
||||
spinner.prefixText = chalk`{bold.red Workflow has failed.}`;
|
||||
const failedInfo = await infoForFailedWorkflowRunAsync(graphqlClient, workflowRun);
|
||||
spinner.fail(failedInfo);
|
||||
return workflowRun;
|
||||
}
|
||||
case WorkflowRunStatus.Success:
|
||||
spinner.prefixText = chalk`{bold.green Workflow has completed successfully.}`;
|
||||
spinner.succeed('');
|
||||
return workflowRun;
|
||||
}
|
||||
} catch {
|
||||
spinner.text = '⚠ Failed to fetch the workflow run status. Check your network connection.';
|
||||
|
||||
failedFetchesCount += 1;
|
||||
|
||||
if (failedFetchesCount > 6) {
|
||||
spinner.fail('Failed to fetch the workflow run status 6 times in a row. Aborting wait.');
|
||||
process.exit(EXIT_CODES.WAIT_ABORTED);
|
||||
}
|
||||
}
|
||||
|
||||
await sleepAsync(10 /* seconds */ * 1000 /* milliseconds */);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* EAS Workflow Status Command
|
||||
*
|
||||
* This command shows the status of an existing workflow run.
|
||||
*
|
||||
* If no run ID is provided, you will be prompted to select from recent workflow runs for the current project.
|
||||
*
|
||||
* If the selected run is still in progress, the command will show the progress of the run, with an option
|
||||
* to show periodic status updates while waiting for completion (similar to `eas workflow:run --wait`).
|
||||
*
|
||||
*/
|
||||
|
||||
import { Flags } from '@oclif/core';
|
||||
import { boolish } from 'getenv';
|
||||
|
||||
import { getWorkflowRunUrl } from '../../build/utils/url';
|
||||
import EasCommand from '../../commandUtils/EasCommand';
|
||||
import { EASNonInteractiveFlag, EasJsonOnlyFlag } from '../../commandUtils/flags';
|
||||
import {
|
||||
choiceFromWorkflowRun,
|
||||
processWorkflowRuns,
|
||||
showWorkflowStatusAsync,
|
||||
workflowRunExitCodes,
|
||||
} from '../../commandUtils/workflow/utils';
|
||||
import { WorkflowRunStatus } from '../../graphql/generated';
|
||||
import { AppQuery } from '../../graphql/queries/AppQuery';
|
||||
import { WorkflowRunQuery } from '../../graphql/queries/WorkflowRunQuery';
|
||||
import Log, { link } from '../../log';
|
||||
import { getOwnerAccountForProjectIdAsync } from '../../project/projectUtils';
|
||||
import { promptAsync } from '../../prompts';
|
||||
import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
|
||||
|
||||
export default class WorkflowStatus extends EasCommand {
|
||||
static override description =
|
||||
'show the status of an existing workflow run. If no run ID is provided, you will be prompted to select from recent workflow runs for the current project.';
|
||||
|
||||
static override args = [
|
||||
{
|
||||
name: 'WORKFLOW_RUN_ID',
|
||||
description: 'A workflow run ID.',
|
||||
},
|
||||
];
|
||||
|
||||
static override flags = {
|
||||
...EASNonInteractiveFlag,
|
||||
wait: Flags.boolean({
|
||||
default: false,
|
||||
allowNo: true,
|
||||
description: 'Exit codes: 0 = success, 11 = failure, 12 = canceled, 13 = wait aborted.',
|
||||
summary: 'Wait for workflow run to complete. Defaults to false.',
|
||||
}),
|
||||
...EasJsonOnlyFlag,
|
||||
};
|
||||
|
||||
static override contextDefinition = {
|
||||
...this.ContextOptions.DynamicProjectConfig,
|
||||
...this.ContextOptions.ProjectDir,
|
||||
...this.ContextOptions.Vcs,
|
||||
...this.ContextOptions.LoggedIn,
|
||||
};
|
||||
|
||||
async runAsync(): Promise<void> {
|
||||
const { flags, args } = await this.parse(WorkflowStatus);
|
||||
|
||||
if (flags.json) {
|
||||
enableJsonOutput();
|
||||
}
|
||||
|
||||
const {
|
||||
getDynamicPrivateProjectConfigAsync,
|
||||
loggedIn: { graphqlClient },
|
||||
} = await this.getContextAsync(WorkflowStatus, {
|
||||
nonInteractive: flags['non-interactive'],
|
||||
withServerSideEnvironment: null,
|
||||
});
|
||||
|
||||
const {
|
||||
projectId,
|
||||
exp: { slug: projectName },
|
||||
} = await getDynamicPrivateProjectConfigAsync();
|
||||
const account = await getOwnerAccountForProjectIdAsync(graphqlClient, projectId);
|
||||
|
||||
let workflowRunId = args.workflowRunId;
|
||||
|
||||
if (!workflowRunId && flags['non-interactive']) {
|
||||
throw new Error('Workflow run ID is required in non-interactive mode');
|
||||
}
|
||||
if (!workflowRunId) {
|
||||
const queryResult = await AppQuery.byIdWorkflowRunsFilteredByStatusAsync(
|
||||
graphqlClient,
|
||||
projectId,
|
||||
undefined,
|
||||
50
|
||||
);
|
||||
const runs = processWorkflowRuns(queryResult);
|
||||
if (runs.length === 0) {
|
||||
Log.warn('No workflow runs to show');
|
||||
return;
|
||||
}
|
||||
const answers = await promptAsync({
|
||||
type: 'select',
|
||||
name: 'selectedRun',
|
||||
message: 'Select a workflow run:',
|
||||
choices: runs.map(run => choiceFromWorkflowRun(run)),
|
||||
});
|
||||
workflowRunId = answers.selectedRun;
|
||||
}
|
||||
|
||||
Log.addNewLineIfNone();
|
||||
Log.log(`See logs: ${link(getWorkflowRunUrl(account.name, projectName, workflowRunId))}`);
|
||||
Log.addNewLineIfNone();
|
||||
|
||||
const spinnerUsesStdErr = boolish('CI', false) || flags.json;
|
||||
|
||||
await showWorkflowStatusAsync(graphqlClient, {
|
||||
workflowRunId,
|
||||
spinnerUsesStdErr,
|
||||
waitForCompletion: flags.wait,
|
||||
});
|
||||
const workflowRun = await WorkflowRunQuery.withJobsByIdAsync(graphqlClient, workflowRunId, {
|
||||
useCache: false,
|
||||
});
|
||||
const status = workflowRun.status;
|
||||
|
||||
if (flags.json) {
|
||||
printJsonOnlyOutput({
|
||||
...workflowRun,
|
||||
url: getWorkflowRunUrl(account.name, projectName, workflowRunId),
|
||||
});
|
||||
}
|
||||
|
||||
if (status === WorkflowRunStatus.Failure) {
|
||||
process.exit(workflowRunExitCodes.WORKFLOW_FAILED);
|
||||
} else if (status === WorkflowRunStatus.Canceled) {
|
||||
process.exit(workflowRunExitCodes.WORKFLOW_CANCELED);
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
@@ -9063,6 +9063,7 @@ export type WorkflowRun = ActivityTimelineProjectActivity & {
|
||||
createdAt: Scalars['DateTime']['output'];
|
||||
durationSeconds?: Maybe<Scalars['Int']['output']>;
|
||||
errors: Array<WorkflowRunError>;
|
||||
finalizedAt?: Maybe<Scalars['DateTime']['output']>;
|
||||
gitCommitHash?: Maybe<Scalars['String']['output']>;
|
||||
gitCommitMessage?: Maybe<Scalars['String']['output']>;
|
||||
githubRepository?: Maybe<GitHubRepository>;
|
||||
@@ -9977,6 +9978,14 @@ export type CancelWorkflowRunMutationVariables = Exact<{
|
||||
|
||||
export type CancelWorkflowRunMutation = { __typename?: 'RootMutation', workflowRun: { __typename?: 'WorkflowRunMutation', cancelWorkflowRun: { __typename?: 'WorkflowRun', id: string } } };
|
||||
|
||||
export type AccountUsageForOverageWarningQueryVariables = Exact<{
|
||||
accountId: Scalars['String']['input'];
|
||||
currentDate: Scalars['DateTime']['input'];
|
||||
}>;
|
||||
|
||||
|
||||
export type AccountUsageForOverageWarningQuery = { __typename?: 'RootQuery', account: { __typename?: 'AccountQuery', byId: { __typename?: 'Account', id: string, name: string, subscription?: { __typename?: 'SubscriptionDetails', id: string, name?: string | null } | null, usageMetrics: { __typename?: 'AccountUsageMetrics', EAS_BUILD: { __typename?: 'UsageMetricTotal', id: string, planMetrics: Array<{ __typename?: 'EstimatedUsage', id: string, serviceMetric: EasServiceMetric, value: number, limit: number }> } } } } };
|
||||
|
||||
export type AppByIdQueryVariables = Exact<{
|
||||
appId: Scalars['String']['input'];
|
||||
}>;
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
import { withErrorHandlingAsync } from '../client';
|
||||
import {
|
||||
AccountUsageForOverageWarningQuery,
|
||||
AccountUsageForOverageWarningQueryVariables,
|
||||
} from '../generated';
|
||||
|
||||
export const AccountUsageQuery = {
|
||||
async getUsageForOverageWarningAsync(
|
||||
graphqlClient: ExpoGraphqlClient,
|
||||
accountId: string,
|
||||
currentDate: Date
|
||||
): Promise<AccountUsageForOverageWarningQuery['account']['byId']> {
|
||||
const data = await withErrorHandlingAsync(
|
||||
graphqlClient
|
||||
.query<AccountUsageForOverageWarningQuery, AccountUsageForOverageWarningQueryVariables>(
|
||||
gql`
|
||||
query AccountUsageForOverageWarning($accountId: String!, $currentDate: DateTime!) {
|
||||
account {
|
||||
byId(accountId: $accountId) {
|
||||
id
|
||||
name
|
||||
subscription {
|
||||
id
|
||||
name
|
||||
}
|
||||
usageMetrics {
|
||||
EAS_BUILD: byBillingPeriod(date: $currentDate, service: BUILDS) {
|
||||
id
|
||||
planMetrics {
|
||||
id
|
||||
serviceMetric
|
||||
value
|
||||
limit
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
{ accountId, currentDate: currentDate.toISOString() },
|
||||
{
|
||||
additionalTypenames: ['Account', 'AccountUsageMetrics', 'UsageMetricTotal'],
|
||||
}
|
||||
)
|
||||
.toPromise()
|
||||
);
|
||||
|
||||
return data.account.byId;
|
||||
},
|
||||
};
|
||||
@@ -9,11 +9,13 @@ export async function runGitCloneAsync({
|
||||
githubRepositoryName,
|
||||
githubUsername,
|
||||
cloneMethod,
|
||||
showOutput = true,
|
||||
}: {
|
||||
githubUsername: string;
|
||||
githubRepositoryName: string;
|
||||
targetProjectDir: string;
|
||||
cloneMethod: 'ssh' | 'https';
|
||||
showOutput?: boolean;
|
||||
}): Promise<{
|
||||
targetProjectDir: string;
|
||||
}> {
|
||||
@@ -29,6 +31,7 @@ export async function runGitCloneAsync({
|
||||
return line.includes('Cloning into');
|
||||
},
|
||||
showSpinner: false,
|
||||
showOutput,
|
||||
});
|
||||
return { targetProjectDir };
|
||||
} catch (error: any) {
|
||||
|
||||
@@ -35,5 +35,6 @@ export async function installDependenciesAsync({
|
||||
);
|
||||
},
|
||||
showOutput: outputLevel !== 'none',
|
||||
showSpinner: outputLevel !== 'none',
|
||||
});
|
||||
}
|
||||
@@ -21,7 +21,9 @@ export async function runCommandAsync({
|
||||
showSpinner?: boolean;
|
||||
showOutput?: boolean;
|
||||
}): Promise<void> {
|
||||
Log.log(`🏗️ Running ${chalk.bold(`${command} ${args.join(' ')}`)}...`);
|
||||
if (showOutput) {
|
||||
Log.log(`🏗️ Running ${chalk.bold(`${command} ${args.join(' ')}`)}...`);
|
||||
}
|
||||
let spinner: Ora | undefined;
|
||||
if (showSpinner) {
|
||||
spinner = ora(`${chalk.bold(`${command} ${args.join(' ')}`)}`).start();
|
||||
@@ -71,6 +73,10 @@ export async function runCommandAsync({
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (!showOutput) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (showSpinner) {
|
||||
spinner?.succeed(`${chalk.bold(`${command} ${args.join(' ')}`)} succeeded`);
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,262 @@
|
||||
import { ExpoGraphqlClient } from '../../../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
import {
|
||||
AccountUsageForOverageWarningQuery,
|
||||
EasService,
|
||||
EasServiceMetric,
|
||||
EstimatedUsage,
|
||||
UsageMetricType,
|
||||
} from '../../../graphql/generated';
|
||||
import { AccountUsageQuery } from '../../../graphql/queries/AccountUsageQuery';
|
||||
import Log, { link } from '../../../log';
|
||||
import {
|
||||
createProgressBar,
|
||||
displayOverageWarning,
|
||||
maybeWarnAboutUsageOveragesAsync,
|
||||
} from '../checkForOverages';
|
||||
|
||||
jest.mock('../../../graphql/queries/AccountUsageQuery');
|
||||
jest.mock('../../../log', () => ({
|
||||
...jest.requireActual('../../../log'),
|
||||
warn: jest.fn(),
|
||||
newLine: jest.fn(),
|
||||
debug: jest.fn(),
|
||||
link: jest.fn((url: string, opts?: { text?: string }) => opts?.text ?? url),
|
||||
}));
|
||||
|
||||
function createMockPlanMetric({
|
||||
value = 50,
|
||||
limit = 100,
|
||||
}: Partial<Pick<EstimatedUsage, 'value' | 'limit'>> = {}): EstimatedUsage {
|
||||
return {
|
||||
__typename: 'EstimatedUsage',
|
||||
id: 'plan-metric-id',
|
||||
service: EasService.Builds,
|
||||
serviceMetric: EasServiceMetric.Builds,
|
||||
metricType: UsageMetricType.Build,
|
||||
value,
|
||||
limit,
|
||||
platformBreakdown: null,
|
||||
};
|
||||
}
|
||||
|
||||
function createMockAccountUsage({
|
||||
id = 'account-id',
|
||||
name = 'test-account',
|
||||
subscriptionName = 'Free',
|
||||
buildPlanMetrics = [],
|
||||
}: {
|
||||
id?: string;
|
||||
name?: string;
|
||||
subscriptionName?: string;
|
||||
buildPlanMetrics?: EstimatedUsage[];
|
||||
} = {}): AccountUsageForOverageWarningQuery['account']['byId'] {
|
||||
return {
|
||||
__typename: 'Account',
|
||||
id,
|
||||
name,
|
||||
subscription: {
|
||||
__typename: 'SubscriptionDetails',
|
||||
id: 'sub-id',
|
||||
name: subscriptionName,
|
||||
},
|
||||
usageMetrics: {
|
||||
EAS_BUILD: {
|
||||
__typename: 'UsageMetricTotal',
|
||||
id: 'metric-id',
|
||||
planMetrics: buildPlanMetrics,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
describe('maybeWarnAboutUsageOveragesAsync', () => {
|
||||
const mockGraphqlClient = {} as ExpoGraphqlClient;
|
||||
const mockGetUsageForOverageWarningAsync = jest.mocked(
|
||||
AccountUsageQuery.getUsageForOverageWarningAsync
|
||||
);
|
||||
const mockWarn = jest.mocked(Log.warn);
|
||||
const mockNewLine = jest.mocked(Log.newLine);
|
||||
const mockDebug = jest.mocked(Log.debug);
|
||||
|
||||
beforeEach(() => {
|
||||
mockGetUsageForOverageWarningAsync.mockClear();
|
||||
mockWarn.mockClear();
|
||||
mockNewLine.mockClear();
|
||||
mockDebug.mockClear();
|
||||
});
|
||||
|
||||
it('displays a warning for a Free plan with high build usage', async () => {
|
||||
mockGetUsageForOverageWarningAsync.mockResolvedValue(
|
||||
createMockAccountUsage({
|
||||
buildPlanMetrics: [createMockPlanMetric({ value: 85 })],
|
||||
})
|
||||
);
|
||||
|
||||
await maybeWarnAboutUsageOveragesAsync({
|
||||
graphqlClient: mockGraphqlClient,
|
||||
accountId: 'account-id',
|
||||
});
|
||||
|
||||
expect(mockGetUsageForOverageWarningAsync).toHaveBeenCalledWith(
|
||||
mockGraphqlClient,
|
||||
'account-id',
|
||||
expect.any(Date)
|
||||
);
|
||||
|
||||
expect(mockWarn).toHaveBeenCalledWith(
|
||||
expect.stringContaining("You've used 85% of your included build credits for this month.")
|
||||
);
|
||||
expect(mockWarn).toHaveBeenCalledWith(
|
||||
expect.stringContaining("You won't be able to start new builds once you reach the limit.")
|
||||
);
|
||||
expect(mockNewLine).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('displays a warning for a Starter plan with high build usage', async () => {
|
||||
mockGetUsageForOverageWarningAsync.mockResolvedValue(
|
||||
createMockAccountUsage({
|
||||
subscriptionName: 'Starter',
|
||||
buildPlanMetrics: [createMockPlanMetric({ value: 90 })],
|
||||
})
|
||||
);
|
||||
|
||||
await maybeWarnAboutUsageOveragesAsync({
|
||||
graphqlClient: mockGraphqlClient,
|
||||
accountId: 'account-id',
|
||||
});
|
||||
|
||||
expect(mockWarn).toHaveBeenCalledWith(
|
||||
expect.stringContaining("You've used 90% of your included build credits for this month.")
|
||||
);
|
||||
expect(mockWarn).toHaveBeenCalledWith(
|
||||
expect.stringContaining(
|
||||
'Additional usage beyond your limit will be charged at pay-as-you-go rates.'
|
||||
)
|
||||
);
|
||||
expect(mockNewLine).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('does not display a warning when usage is below threshold', async () => {
|
||||
mockGetUsageForOverageWarningAsync.mockResolvedValue(
|
||||
createMockAccountUsage({
|
||||
buildPlanMetrics: [createMockPlanMetric({ value: 50 })],
|
||||
})
|
||||
);
|
||||
|
||||
await maybeWarnAboutUsageOveragesAsync({
|
||||
graphqlClient: mockGraphqlClient,
|
||||
accountId: 'account-id',
|
||||
});
|
||||
|
||||
expect(mockWarn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('handles errors gracefully', async () => {
|
||||
mockGetUsageForOverageWarningAsync.mockRejectedValue(new Error('Network error'));
|
||||
|
||||
await maybeWarnAboutUsageOveragesAsync({
|
||||
graphqlClient: mockGraphqlClient,
|
||||
accountId: 'account-id',
|
||||
});
|
||||
|
||||
expect(mockWarn).not.toHaveBeenCalled();
|
||||
expect(mockDebug).toHaveBeenCalledWith(expect.stringContaining('Failed to fetch usage data'));
|
||||
});
|
||||
|
||||
it('does not display a warning when there are no plan metrics', async () => {
|
||||
mockGetUsageForOverageWarningAsync.mockResolvedValue(createMockAccountUsage());
|
||||
|
||||
await maybeWarnAboutUsageOveragesAsync({
|
||||
graphqlClient: mockGraphqlClient,
|
||||
accountId: 'account-id',
|
||||
});
|
||||
|
||||
expect(mockWarn).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('createProgressBar', () => {
|
||||
it('creates a progress bar with correct fill for a given percentage', () => {
|
||||
const bar = createProgressBar(85, 20);
|
||||
expect(bar).toBe('█████████████████░░░');
|
||||
});
|
||||
|
||||
it('creates a progress bar with correct fill for 100%', () => {
|
||||
const bar = createProgressBar(100, 20);
|
||||
expect(bar).toBe('████████████████████');
|
||||
});
|
||||
|
||||
it('creates a progress bar with correct fill for 0%', () => {
|
||||
const bar = createProgressBar(0, 20);
|
||||
expect(bar).toBe('░░░░░░░░░░░░░░░░░░░░');
|
||||
});
|
||||
|
||||
it('handles custom width', () => {
|
||||
const bar = createProgressBar(50, 10);
|
||||
expect(bar).toBe('█████░░░░░');
|
||||
});
|
||||
});
|
||||
|
||||
describe('displayOverageWarning', () => {
|
||||
const mockWarn = Log.warn as jest.MockedFunction<typeof Log.warn>;
|
||||
const mockLink = link as jest.MockedFunction<typeof link>;
|
||||
|
||||
beforeEach(() => {
|
||||
mockWarn.mockClear();
|
||||
mockLink.mockClear();
|
||||
});
|
||||
|
||||
it('displays a warning for a Free plan', () => {
|
||||
displayOverageWarning({
|
||||
percentUsed: 85,
|
||||
hasFreePlan: true,
|
||||
name: 'test-account',
|
||||
});
|
||||
|
||||
expect(mockWarn).toHaveBeenCalledTimes(2);
|
||||
expect(mockWarn).toHaveBeenCalledWith(
|
||||
expect.stringContaining("You've used 85% of your included build credits for this month.")
|
||||
);
|
||||
expect(mockWarn).toHaveBeenCalledWith(
|
||||
expect.stringContaining("You won't be able to start new builds once you reach the limit.")
|
||||
);
|
||||
expect(mockWarn).toHaveBeenCalledWith(
|
||||
expect.stringContaining('Upgrade your plan to continue service.')
|
||||
);
|
||||
});
|
||||
|
||||
it('displays a warning for a paid plan', () => {
|
||||
displayOverageWarning({
|
||||
percentUsed: 85,
|
||||
hasFreePlan: false,
|
||||
name: 'test-account',
|
||||
});
|
||||
|
||||
expect(mockWarn).toHaveBeenCalledTimes(2);
|
||||
expect(mockWarn).toHaveBeenCalledWith(
|
||||
expect.stringContaining("You've used 85% of your included build credits for this month.")
|
||||
);
|
||||
expect(mockWarn).toHaveBeenCalledWith(
|
||||
expect.stringContaining(
|
||||
'Additional usage beyond your limit will be charged at pay-as-you-go rates.'
|
||||
)
|
||||
);
|
||||
expect(mockWarn).toHaveBeenCalledWith(expect.stringContaining('See usage in billing.'));
|
||||
expect(mockWarn).toHaveBeenCalledWith(
|
||||
expect.stringContaining('██████████████████████████░░░░')
|
||||
);
|
||||
});
|
||||
|
||||
it('includes correct account name in billing URL', () => {
|
||||
displayOverageWarning({
|
||||
percentUsed: 85,
|
||||
hasFreePlan: true,
|
||||
name: 'my-custom-account',
|
||||
});
|
||||
|
||||
expect(mockLink).toHaveBeenCalledWith(
|
||||
'https://expo.dev/accounts/my-custom-account/settings/billing',
|
||||
expect.objectContaining({ text: 'Upgrade your plan to continue service.' })
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,85 @@
|
||||
import chalk from 'chalk';
|
||||
|
||||
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
|
||||
import { AccountUsageQuery } from '../../graphql/queries/AccountUsageQuery';
|
||||
import Log, { link } from '../../log';
|
||||
|
||||
const THRESHOLD_PERCENT = 85;
|
||||
|
||||
export async function maybeWarnAboutUsageOveragesAsync({
|
||||
graphqlClient,
|
||||
accountId,
|
||||
}: {
|
||||
graphqlClient: ExpoGraphqlClient;
|
||||
accountId: string;
|
||||
}): Promise<void> {
|
||||
try {
|
||||
const currentDate = new Date();
|
||||
const {
|
||||
name,
|
||||
subscription,
|
||||
usageMetrics: { EAS_BUILD },
|
||||
} = await AccountUsageQuery.getUsageForOverageWarningAsync(
|
||||
graphqlClient,
|
||||
accountId,
|
||||
currentDate
|
||||
);
|
||||
|
||||
const planMetric = EAS_BUILD?.planMetrics?.[0];
|
||||
if (!planMetric || !subscription) {
|
||||
return;
|
||||
}
|
||||
|
||||
const percentUsed = calculatePercentUsed(planMetric.value, planMetric.limit);
|
||||
if (percentUsed >= THRESHOLD_PERCENT) {
|
||||
const hasFreePlan = subscription.name === 'Free';
|
||||
displayOverageWarning({ percentUsed, hasFreePlan, name });
|
||||
}
|
||||
} catch (error) {
|
||||
// Silently fail if we can't fetch usage data - we don't want to block the user's workflow
|
||||
Log.debug(`Failed to fetch usage data: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function calculatePercentUsed(value: number, limit: number): number {
|
||||
if (limit === 0) {
|
||||
return 0;
|
||||
}
|
||||
return Math.min(Math.floor((value / limit) * 100), 100);
|
||||
}
|
||||
|
||||
export function createProgressBar(percentUsed: number, width: number = 30): string {
|
||||
const filledWidth = Math.round((percentUsed / 100) * width);
|
||||
const emptyWidth = width - filledWidth;
|
||||
const filled = '█'.repeat(filledWidth);
|
||||
const empty = '░'.repeat(emptyWidth);
|
||||
return `${filled}${empty}`;
|
||||
}
|
||||
|
||||
export function displayOverageWarning({
|
||||
percentUsed,
|
||||
hasFreePlan,
|
||||
name,
|
||||
}: {
|
||||
percentUsed: number;
|
||||
hasFreePlan: boolean;
|
||||
name: string;
|
||||
}): void {
|
||||
Log.warn(
|
||||
chalk.bold(`You've used ${percentUsed}% of your included build credits for this month. `) +
|
||||
createProgressBar(percentUsed)
|
||||
);
|
||||
|
||||
const billingUrl = `https://expo.dev/accounts/${name}/settings/billing`;
|
||||
const warning = hasFreePlan
|
||||
? "You won't be able to start new builds once you reach the limit. " +
|
||||
link(billingUrl, { text: 'Upgrade your plan to continue service.', dim: false })
|
||||
: 'Additional usage beyond your limit will be charged at pay-as-you-go rates. ' +
|
||||
link(billingUrl, {
|
||||
text: 'See usage in billing.',
|
||||
dim: false,
|
||||
});
|
||||
|
||||
Log.warn(warning);
|
||||
Log.newLine();
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@expo/eas-json",
|
||||
"description": "A library for interacting with eas.json",
|
||||
"version": "16.23.0",
|
||||
"version": "16.25.0",
|
||||
"author": "Expo <[email protected]>",
|
||||
"bugs": "https://github.com/expo/eas-cli/issues",
|
||||
"dependencies": {
|
||||
|
||||
@@ -522,7 +522,8 @@
|
||||
"**Closed testing** releases are available to a limited number of testers that you choose, who can test a pre-release version of your app and submit feedback.",
|
||||
"**Internal testing** releases are available to up to 100 testers that you choose.",
|
||||
"**Production releases** are available to all Google Play users in your chosen countries."
|
||||
]
|
||||
],
|
||||
"default": "internal"
|
||||
},
|
||||
"releaseStatus": {
|
||||
"enum": ["draft", "inProgress", "halted", "completed"],
|
||||
@@ -533,7 +534,8 @@
|
||||
"The release's APKs are being served to a fraction of users, if set.",
|
||||
"The release's APKs will no longer be served to users. Users who already have these APKs are unaffected.",
|
||||
"The release will have no further changes. Its APKs are being served to all users, unless they are eligible to APKs of a more recent release."
|
||||
]
|
||||
],
|
||||
"default": "completed"
|
||||
},
|
||||
"rollout": {
|
||||
"type": "number",
|
||||
|
||||
@@ -8,7 +8,9 @@ GITHUB_EMAIL=`git config get --global user.email`
|
||||
SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/.. && pwd )"
|
||||
ROOT_DIR="$( cd "$SCRIPTS_DIR"/.. && pwd )"
|
||||
|
||||
$SCRIPTS_DIR/bin/run update-local-plugin
|
||||
# Since https://github.com/expo/eas-cli/pull/3237 , the local plugin version is identical
|
||||
# to @expo/eas-build-job dependency, so the update-local-plugin step is no longer needed.
|
||||
# $SCRIPTS_DIR/bin/run update-local-plugin
|
||||
|
||||
next_version_bump=$($SCRIPTS_DIR/bin/run next-version)
|
||||
next_version=${1:-$next_version_bump}
|
||||
|
||||
@@ -1549,10 +1549,10 @@
|
||||
semver "^7.6.2"
|
||||
zod "^4.1.3"
|
||||
|
||||
"@expo/[email protected]9":
|
||||
version "1.0.239"
|
||||
resolved "https://registry.yarnpkg.com/@expo/eas-build-job/-/eas-build-job-1.0.239.tgz#025afd9c3fb9086cbb053ccbc08b7683aa74bbc4"
|
||||
integrity sha512-5P/dQL2S2iEyTvGKOPN95r7cNFW3HgnA4PNqXU0s5ctb10837sMX6/A5XgIg/Ow0SFGZRiP4cK9ZFAiK3m2Ong==
|
||||
"@expo/[email protected]43":
|
||||
version "1.0.243"
|
||||
resolved "https://registry.yarnpkg.com/@expo/eas-build-job/-/eas-build-job-1.0.243.tgz#2b390ca1a84b4a4ea06630cf875b96c0954094ab"
|
||||
integrity sha512-wLU9q0pzIKibr4jLMV/U6BYszk5T85p/WmRYUIqH7nhmy2dDUJHz0WlP/i/ZWAsnrHplwidbCZvZGoxwgJsISA==
|
||||
dependencies:
|
||||
"@expo/logger" "1.0.221"
|
||||
joi "^17.13.1"
|
||||
@@ -5598,11 +5598,6 @@ chalk@^5.2.0:
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385"
|
||||
integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==
|
||||
|
||||
chalk@^5.6.2:
|
||||
version "5.6.2"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.6.2.tgz#b1238b6e23ea337af71c7f8a295db5af0c158aea"
|
||||
integrity sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==
|
||||
|
||||
[email protected]:
|
||||
version "1.0.15"
|
||||
resolved "https://registry.yarnpkg.com/change-case-all/-/change-case-all-1.0.15.tgz#de29393167fc101d646cd76b0ef23e27d09756ad"
|
||||
@@ -5703,13 +5698,6 @@ cli-cursor@^2.1.0:
|
||||
dependencies:
|
||||
restore-cursor "^2.0.0"
|
||||
|
||||
cli-cursor@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-5.0.0.tgz#24a4831ecf5a6b01ddeb32fb71a4b2088b0dce38"
|
||||
integrity sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==
|
||||
dependencies:
|
||||
restore-cursor "^5.0.0"
|
||||
|
||||
[email protected], cli-progress@^3.10.0, cli-progress@^3.12.0:
|
||||
version "3.12.0"
|
||||
resolved "https://registry.yarnpkg.com/cli-progress/-/cli-progress-3.12.0.tgz#807ee14b66bcc086258e444ad0f19e7d42577942"
|
||||
@@ -5727,10 +5715,10 @@ cli-spinners@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.2.tgz#1773a8f4b9c4d6ac31563df53b3fc1d79462fe41"
|
||||
integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==
|
||||
|
||||
cli-spinners@^3.2.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-3.3.0.tgz#2ba7c98b4f4662e67315b5634365661be8574440"
|
||||
integrity sha512-/+40ljC3ONVnYIttjMWrlL51nItDAbBrq2upN8BPyvGU/2n5Oxw3tbNwORCaNuNqLJnxGqOfjUuhsv7l5Q4IsQ==
|
||||
cli-spinners@^2.4.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.4.0.tgz#c6256db216b878cfba4720e719cec7cf72685d7f"
|
||||
integrity sha512-sJAofoarcm76ZGpuooaO0eDy8saEy+YoZBLjC4h8srt4jeBnkYeOgqxgsJQTpyt2LjI5PTfLJHSL+41Yu4fEJA==
|
||||
|
||||
cli-table@^0.3.1:
|
||||
version "0.3.11"
|
||||
@@ -7919,11 +7907,6 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5:
|
||||
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
|
||||
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
|
||||
|
||||
get-east-asian-width@^1.3.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz#9bc4caa131702b4b61729cb7e42735bc550c9ee6"
|
||||
integrity sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==
|
||||
|
||||
get-intrinsic@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.0.1.tgz#94a9768fcbdd0595a1c9273aacf4c89d075631be"
|
||||
@@ -9122,11 +9105,6 @@ is-interactive@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e"
|
||||
integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==
|
||||
|
||||
is-interactive@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-2.0.0.tgz#40c57614593826da1100ade6059778d597f16e90"
|
||||
integrity sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==
|
||||
|
||||
is-lambda@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5"
|
||||
@@ -9362,11 +9340,6 @@ is-unicode-supported@^0.1.0:
|
||||
resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7"
|
||||
integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==
|
||||
|
||||
is-unicode-supported@^2.0.0, is-unicode-supported@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz#09f0ab0de6d3744d48d265ebb98f65d11f2a9b3a"
|
||||
integrity sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==
|
||||
|
||||
is-upper-case@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/is-upper-case/-/is-upper-case-2.0.2.tgz#f1105ced1fe4de906a5f39553e7d3803fd804649"
|
||||
@@ -10568,14 +10541,6 @@ log-symbols@^4.0.0:
|
||||
dependencies:
|
||||
chalk "^4.0.0"
|
||||
|
||||
log-symbols@^7.0.1:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-7.0.1.tgz#f52e68037d96f589fc572ff2193dc424d48c195b"
|
||||
integrity sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==
|
||||
dependencies:
|
||||
is-unicode-supported "^2.0.0"
|
||||
yoctocolors "^2.1.1"
|
||||
|
||||
log-update@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1"
|
||||
@@ -10947,11 +10912,6 @@ mimic-fn@^2.1.0:
|
||||
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
|
||||
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
|
||||
|
||||
mimic-function@^5.0.0:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/mimic-function/-/mimic-function-5.0.1.tgz#acbe2b3349f99b9deaca7fb70e48b83e94e67076"
|
||||
integrity sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==
|
||||
|
||||
mimic-response@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
|
||||
@@ -11951,13 +11911,6 @@ onetime@^5.1.0, onetime@^5.1.2:
|
||||
dependencies:
|
||||
mimic-fn "^2.1.0"
|
||||
|
||||
onetime@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/onetime/-/onetime-7.0.0.tgz#9f16c92d8c9ef5120e3acd9dd9957cceecc1ab60"
|
||||
integrity sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==
|
||||
dependencies:
|
||||
mimic-function "^5.0.0"
|
||||
|
||||
open@^8.0.4, open@^8.4.0:
|
||||
version "8.4.0"
|
||||
resolved "https://registry.yarnpkg.com/open/-/open-8.4.0.tgz#345321ae18f8138f82565a910fdc6b39e8c244f8"
|
||||
@@ -11979,6 +11932,20 @@ optionator@^0.9.3:
|
||||
prelude-ls "^1.2.1"
|
||||
type-check "^0.4.0"
|
||||
|
||||
[email protected]:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/ora/-/ora-5.1.0.tgz#b188cf8cd2d4d9b13fd25383bc3e5cba352c94f8"
|
||||
integrity sha512-9tXIMPvjZ7hPTbk8DFq1f7Kow/HU/pQYB60JbNq+QnGwcyhWVZaQ4hM9zQDEsPxw/muLpgiHSaumUZxCAmod/w==
|
||||
dependencies:
|
||||
chalk "^4.1.0"
|
||||
cli-cursor "^3.1.0"
|
||||
cli-spinners "^2.4.0"
|
||||
is-interactive "^1.0.0"
|
||||
log-symbols "^4.0.0"
|
||||
mute-stream "0.0.8"
|
||||
strip-ansi "^6.0.0"
|
||||
wcwidth "^1.0.1"
|
||||
|
||||
[email protected]:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/ora/-/ora-5.3.0.tgz#fb832899d3a1372fe71c8b2c534bbfe74961bb6f"
|
||||
@@ -11993,21 +11960,6 @@ [email protected]:
|
||||
strip-ansi "^6.0.0"
|
||||
wcwidth "^1.0.1"
|
||||
|
||||
[email protected]:
|
||||
version "9.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ora/-/ora-9.0.0.tgz#945236f5ce78a024cf4c25df6c46ecd09ab6e685"
|
||||
integrity sha512-m0pg2zscbYgWbqRR6ABga5c3sZdEon7bSgjnlXC64kxtxLOyjRcbbUkLj7HFyy/FTD+P2xdBWu8snGhYI0jc4A==
|
||||
dependencies:
|
||||
chalk "^5.6.2"
|
||||
cli-cursor "^5.0.0"
|
||||
cli-spinners "^3.2.0"
|
||||
is-interactive "^2.0.0"
|
||||
is-unicode-supported "^2.1.0"
|
||||
log-symbols "^7.0.1"
|
||||
stdin-discarder "^0.2.2"
|
||||
string-width "^8.1.0"
|
||||
strip-ansi "^7.1.2"
|
||||
|
||||
ora@^3.4.0:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/ora/-/ora-3.4.0.tgz#bf0752491059a3ef3ed4c85097531de9fdbcd318"
|
||||
@@ -13158,14 +13110,6 @@ restore-cursor@^3.1.0:
|
||||
onetime "^5.1.0"
|
||||
signal-exit "^3.0.2"
|
||||
|
||||
restore-cursor@^5.0.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-5.1.0.tgz#0766d95699efacb14150993f55baf0953ea1ebe7"
|
||||
integrity sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==
|
||||
dependencies:
|
||||
onetime "^7.0.0"
|
||||
signal-exit "^4.1.0"
|
||||
|
||||
[email protected]:
|
||||
version "0.13.1"
|
||||
resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658"
|
||||
@@ -13549,7 +13493,7 @@ signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3:
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
|
||||
integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
|
||||
|
||||
signal-exit@^4.0.1, signal-exit@^4.1.0:
|
||||
signal-exit@^4.0.1:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04"
|
||||
integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==
|
||||
@@ -13845,11 +13789,6 @@ [email protected]:
|
||||
resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
|
||||
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
|
||||
|
||||
stdin-discarder@^0.2.2:
|
||||
version "0.2.2"
|
||||
resolved "https://registry.yarnpkg.com/stdin-discarder/-/stdin-discarder-0.2.2.tgz#390037f44c4ae1a1ae535c5fe38dc3aba8d997be"
|
||||
integrity sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==
|
||||
|
||||
[email protected]:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/stream-buffers/-/stream-buffers-2.2.0.tgz#91d5f5130d1cef96dcfa7f726945188741d09ee4"
|
||||
@@ -13928,14 +13867,6 @@ string-width@^5.0.1, string-width@^5.1.2:
|
||||
emoji-regex "^9.2.2"
|
||||
strip-ansi "^7.0.1"
|
||||
|
||||
string-width@^8.1.0:
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-8.1.0.tgz#9e9fb305174947cf45c30529414b5da916e9e8d1"
|
||||
integrity sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==
|
||||
dependencies:
|
||||
get-east-asian-width "^1.3.0"
|
||||
strip-ansi "^7.1.0"
|
||||
|
||||
string.prototype.matchall@^4.0.11:
|
||||
version "4.0.11"
|
||||
resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz#1092a72c59268d2abaad76582dccc687c0297e0a"
|
||||
@@ -14100,13 +14031,6 @@ strip-ansi@^7.0.1:
|
||||
dependencies:
|
||||
ansi-regex "^6.0.1"
|
||||
|
||||
strip-ansi@^7.1.0, strip-ansi@^7.1.2:
|
||||
version "7.1.2"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.2.tgz#132875abde678c7ea8d691533f2e7e22bb744dba"
|
||||
integrity sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==
|
||||
dependencies:
|
||||
ansi-regex "^6.0.1"
|
||||
|
||||
strip-bom-buf@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-bom-buf/-/strip-bom-buf-1.0.0.tgz#1cb45aaf57530f4caf86c7f75179d2c9a51dd572"
|
||||
@@ -15716,11 +15640,6 @@ yocto-queue@^0.1.0:
|
||||
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
|
||||
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
|
||||
|
||||
yoctocolors@^2.1.1:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/yoctocolors/-/yoctocolors-2.1.2.tgz#d795f54d173494e7d8db93150cec0ed7f678c83a"
|
||||
integrity sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==
|
||||
|
||||
zod@^4.1.3:
|
||||
version "4.1.8"
|
||||
resolved "https://registry.yarnpkg.com/zod/-/zod-4.1.8.tgz#54f024adc634dd185006a8415da2bdd495b9d92b"
|
||||
|
||||
Reference in new issue
Block a user