Compare commits

...
19 Commits
Author SHA1 Message Date
Will Schurman 367b763adf v12.6.0 2024-10-21 14:26:49 -07:00
Will Schurman 49dba20200 [eas-cli] Add interactivity to eas update:edit command (#2638) 2024-10-21 14:19:18 -07:00
Juwan Wheatley f0b14bf6a1 [eas-cli] add pause/resume commands for Update Channels (#2614)
# Why

We want to allow developers to prevent updates from being served to certain builds by "pausing" update channels.

# How

- I added two new CLI commands to toggle the channel pausing state
- I added the pause status to the channel details output in the `view` and `list` commands

# Test Plan

Build the CLI locally under the `neas` alias, and run `neas channel:pause development && neas channel:view development && neas channel:resume development && neas channel:view development`:

<img width="1364" alt="Screenshot 2024-10-17 at 05 33 36" src="https://github.com/user-attachments/assets/fd557e57-bbf7-463c-8cec-1febcb2fdde8">
2024-10-21 15:08:45 -04:00
Piotr Szeremeta 161acbb160 Allow user to select environments manually in env:push (#2637)
# Why

[ENG-13853: Prompt user to enter the environment when not provided vs fail and rerun when using `eas env:push`](https://linear.app/expo/issue/ENG-13853/prompt-user-to-enter-the-environment-when-not-provided-vs-fail-and)

If the environment is not provided, we ask the user about it in other commands, I think we can do the same here for consistency vs throwing an error and having the user rerun it

# Test Plan

Tested manually
2024-10-21 15:35:17 +02:00
Expo CI 5aad520c23 update CHANGELOG.md 2024-10-19 18:28:59 +00:00
Cedric van Putten d6ec3ae106 v12.5.4 2024-10-19 20:23:43 +02:00
Cedric van Putten feb8d2d8f4 fix(eas-cli): resolve Apple authentication error (#2641)
* fix(eas-cli): resolve Apple authentication error

* docs(eas-cli): fix changelog entry

* chore(eas-cli): bump `@expo/apple-utils` again
2024-10-19 20:22:39 +02:00
Piotr Szeremeta c07fd222d9 Ask for file path in env:* commands (#2635)
# Why

[ENG-13855: When creating `file` type env var in `env:create` ask about file path vs variable value](https://linear.app/expo/issue/ENG-13855/when-creating-file-type-env-var-in-envcreate-ask-about-file-path-vs)
2024-10-18 16:50:59 +02:00
Piotr Szeremeta 1873804c8b Display message when env:list returns an empty result (#2630)
# Why

[ENG-13847: Show `no env vars found for this environment` if 0 env vars exist for given environment in `eas env:list`](https://linear.app/expo/issue/ENG-13847/show-no-env-vars-found-for-this-environment-if-0-env-vars-exist-for)

<img width="455" alt="image" src="https://github.com/user-attachments/assets/d4286fcb-0adf-4806-a876-4cbbcf3d6157">
2024-10-18 13:16:20 +02:00
Piotr Szeremeta 1cc4fd8880 Use lower case environment across all eas env commands (#2632)
# Why

[ENG-13846: Use lower-case environment names across all `eas env:xyz` commands for consistency](https://linear.app/expo/issue/ENG-13846/use-lower-case-environment-names-across-all-eas-envxyz-commands-for)
2024-10-18 13:14:50 +02:00
Piotr Szeremeta f83d7e0be7 Always ask for environment in env:get (#2631)
# Why

[ENG-13848: Always ask for `environment` in `eas env:get` command](https://linear.app/expo/issue/ENG-13848/always-ask-for-environment-in-eas-envget-command)
2024-10-18 13:14:13 +02:00
Piotr Szeremeta b225ba4bf3 Use the same names for visibility options in eas cli as on (#2629)
# Why

[ENG-13849: When no `--visibility` input is provided `eas env:create` should ask about it by default](https://linear.app/expo/issue/ENG-13849/when-no-visibility-input-is-provided-eas-envcreate-should-ask-about-it)

[ENG-13850: Use the same names for visibility options in EAS CLI as on website](https://linear.app/expo/issue/ENG-13850/use-the-same-names-for-visibility-options-in-eas-cli-as-on-website)

`eas env:*` commands were using obsolete names for visibility options: `public` and `secret`, instead of `plaintext` and `encrypted`. It should be updated.
Also, user is prompted for the variable visibility if not provided.

# Test Plan

Updated tests
2024-10-18 10:29:52 +02:00
Piotr Szeremeta 4fb5972f18 Support multiple environments in env:push command (#2620) 2024-10-17 16:59:57 +02:00
Piotr Szeremeta 463f73eec2 Fix in env:link command: fail in non-interactive mode if variable name is ambigous (#2627) 2024-10-17 16:59:31 +02:00
Szymon Dziedzic 2dbaed5b2a [eas-cli] remove @expo/config-types dependency (#2528)
<!-- If this PR requires a changelog entry, add it by commenting the PR with the command `/changelog-entry [breaking-change|new-feature|bug-fix|chore] [message]`. -->
<!-- You can skip the changelog check by labeling the PR with "no changelog". -->

# Why

Rely on ExpoConfig type from the `@expo/config` package in all places for consistency

# How

Rely on ExpoConfig type from the `@expo/config` package in all places for consistency

# Test Plan

Tests
2024-10-17 14:56:49 +02:00
Expo CI 20b76f72b0 update CHANGELOG.md 2024-10-16 15:30:02 +00:00
Szymon Dziedzic 56444432b9 v12.5.3 2024-10-16 17:24:52 +02:00
Piotr Szeremeta 02022d8d17 Support File type environment variables (#2512)
# Why

User should be able to upload files to environment variables and read content of those files

# How

* When an envvar is created with flag `--type FILE`, selected file is encoded to base64 and sent to www.
* EnvVarQueries return file contents when `includeFileContent` file is passed
* `env:get` automatically include file content, `env:list` requires `--include-file-content` flag
* Updated environment display - added `environments`, `type` and `visibility`

# Test Plan

tested manually, updated tests
2024-10-15 10:57:07 +02:00
Expo CI a7c77e8ab3 update CHANGELOG.md 2024-10-11 18:52:03 +00:00
45 changed files with 2185 additions and 573 deletions

No files matched your search

+14
View File
@@ -8,9 +8,23 @@ This is the log of notable changes to EAS CLI and related packages.
### 🎉 New features
- Add `eas channel:pause` and `eas channel:resume` commands to pause/resume update delivery to builds using specific update channels and display paused status in channel details output. ([#2614](https://github.com/expo/eas-cli/pull/2614) by [@fiberjw](https://github.com/fiberjw))
- Add interactivity to eas update:edit command. ([#2638](https://github.com/expo/eas-cli/pull/2638) by [@wschurman](https://github.com/wschurman))
### 🐛 Bug fixes
### 🧹 Chores
## [12.5.4](https://github.com/expo/eas-cli/releases/tag/v12.5.4) - 2024-10-19
## [12.5.3](https://github.com/expo/eas-cli/releases/tag/v12.5.3) - 2024-10-16
## [12.5.2](https://github.com/expo/eas-cli/releases/tag/v12.5.2) - 2024-10-11
### 🐛 Bug fixes
- Disallow republishing an update that is being rolled-out. ([#2602](https://github.com/expo/eas-cli/pull/2602) by [@wschurman](https://github.com/wschurman))
- Bump `@expo/apple-utils` to `2.0.2` resolving the Apple authentication error. ([#2641](https://github.com/expo/eas-cli/pull/2641) by [@byCedric](https://github.com/byCedric))
### 🧹 Chores
+1 -1
View File
@@ -1,5 +1,5 @@
{
"npmClient": "yarn",
"version": "12.5.2",
"version": "12.6.0",
"$schema": "node_modules/lerna/schemas/lerna-schema.json"
}
+131 -60
View File
@@ -81,6 +81,8 @@ eas --help COMMAND
* [`eas channel:create [NAME]`](#eas-channelcreate-name)
* [`eas channel:edit [NAME]`](#eas-channeledit-name)
* [`eas channel:list`](#eas-channellist)
* [`eas channel:pause [NAME]`](#eas-channelpause-name)
* [`eas channel:resume [NAME]`](#eas-channelresume-name)
* [`eas channel:rollout [CHANNEL]`](#eas-channelrollout-channel)
* [`eas channel:view [NAME]`](#eas-channelview-name)
* [`eas config`](#eas-config)
@@ -113,6 +115,7 @@ eas --help COMMAND
* [`eas update`](#eas-update)
* [`eas update:configure`](#eas-updateconfigure)
* [`eas update:delete GROUPID`](#eas-updatedelete-groupid)
* [`eas update:edit [GROUPID]`](#eas-updateedit-groupid)
* [`eas update:list`](#eas-updatelist)
* [`eas update:republish`](#eas-updaterepublish)
* [`eas update:roll-back-to-embedded`](#eas-updateroll-back-to-embedded)
@@ -143,7 +146,7 @@ ALIASES
$ eas login
```
_See code: [packages/eas-cli/src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/account/login.ts)_
## `eas account:logout`
@@ -160,7 +163,7 @@ ALIASES
$ eas logout
```
_See code: [packages/eas-cli/src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/account/logout.ts)_
## `eas account:view`
@@ -177,7 +180,7 @@ ALIASES
$ eas whoami
```
_See code: [packages/eas-cli/src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/account/view.ts)_
## `eas analytics [STATUS]`
@@ -191,7 +194,7 @@ DESCRIPTION
display or change analytics settings
```
_See code: [packages/eas-cli/src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v12.5.2/packages/eas-cli/src/commands/analytics.ts)_
_See code: [packages/eas-cli/src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v12.6.0/packages/eas-cli/src/commands/analytics.ts)_
## `eas autocomplete [SHELL]`
@@ -243,7 +246,7 @@ DESCRIPTION
create a branch
```
_See code: [packages/eas-cli/src/commands/branch/create.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/branch/create.ts)_
## `eas branch:delete [NAME]`
@@ -264,7 +267,7 @@ DESCRIPTION
delete a branch
```
_See code: [packages/eas-cli/src/commands/branch/delete.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/branch/delete.ts)_
## `eas branch:list`
@@ -284,7 +287,7 @@ DESCRIPTION
list all branches
```
_See code: [packages/eas-cli/src/commands/branch/list.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/branch/list.ts)_
## `eas branch:rename`
@@ -304,7 +307,7 @@ DESCRIPTION
rename a branch
```
_See code: [packages/eas-cli/src/commands/branch/rename.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/branch/rename.ts)_
## `eas branch:view [NAME]`
@@ -327,7 +330,7 @@ DESCRIPTION
view a branch
```
_See code: [packages/eas-cli/src/commands/branch/view.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/branch/view.ts)_
## `eas build`
@@ -364,7 +367,7 @@ DESCRIPTION
start a build
```
_See code: [packages/eas-cli/src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/build/index.ts)_
## `eas build:cancel [BUILD_ID]`
@@ -383,7 +386,7 @@ DESCRIPTION
cancel a build
```
_See code: [packages/eas-cli/src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/build/cancel.ts)_
## `eas build:configure`
@@ -400,7 +403,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/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/build/configure.ts)_
## `eas build:delete [BUILD_ID]`
@@ -419,7 +422,7 @@ DESCRIPTION
delete a build
```
_See code: [packages/eas-cli/src/commands/build/delete.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/build/delete.ts)_
## `eas build:inspect`
@@ -454,7 +457,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/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/build/inspect.ts)_
## `eas build:list`
@@ -504,7 +507,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/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/build/list.ts)_
## `eas build:resign`
@@ -533,7 +536,7 @@ DESCRIPTION
re-sign a build archive
```
_See code: [packages/eas-cli/src/commands/build/resign.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/build/resign.ts)_
## `eas build:run`
@@ -559,7 +562,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/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/build/run.ts)_
## `eas build:submit`
@@ -609,7 +612,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/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/build/version/get.ts)_
## `eas build:version:set`
@@ -628,7 +631,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/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/build/version/set.ts)_
## `eas build:version:sync`
@@ -647,7 +650,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/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/build/version/sync.ts)_
## `eas build:view [BUILD_ID]`
@@ -664,7 +667,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/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/build/view.ts)_
## `eas channel:create [NAME]`
@@ -685,7 +688,7 @@ DESCRIPTION
create a channel
```
_See code: [packages/eas-cli/src/commands/channel/create.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/channel/create.ts)_
## `eas channel:edit [NAME]`
@@ -707,7 +710,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/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/channel/edit.ts)_
## `eas channel:list`
@@ -727,7 +730,51 @@ DESCRIPTION
list all channels
```
_See code: [packages/eas-cli/src/commands/channel/list.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/channel/list.ts)_
## `eas channel:pause [NAME]`
pause a channel to stop it from sending updates
```
USAGE
$ eas channel:pause [NAME] [--branch <value>] [--json --non-interactive]
ARGUMENTS
NAME Name of the channel to edit
FLAGS
--branch=<value> Name of the branch to point to
--json Enable JSON output, non-JSON messages will be printed to stderr.
--non-interactive Run the command in non-interactive mode.
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/v12.6.0/packages/eas-cli/src/commands/channel/pause.ts)_
## `eas channel:resume [NAME]`
resume a channel to start sending updates
```
USAGE
$ eas channel:resume [NAME] [--branch <value>] [--json --non-interactive]
ARGUMENTS
NAME Name of the channel to edit
FLAGS
--branch=<value> Name of the branch to point to
--json Enable JSON output, non-JSON messages will be printed to stderr.
--non-interactive Run the command in non-interactive mode.
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/v12.6.0/packages/eas-cli/src/commands/channel/resume.ts)_
## `eas channel:rollout [CHANNEL]`
@@ -760,7 +807,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/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/channel/rollout.ts)_
## `eas channel:view [NAME]`
@@ -783,7 +830,7 @@ DESCRIPTION
view a channel
```
_See code: [packages/eas-cli/src/commands/channel/view.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/channel/view.ts)_
## `eas config`
@@ -804,7 +851,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/v12.5.2/packages/eas-cli/src/commands/config.ts)_
_See code: [packages/eas-cli/src/commands/config.ts](https://github.com/expo/eas-cli/blob/v12.6.0/packages/eas-cli/src/commands/config.ts)_
## `eas credentials`
@@ -821,7 +868,7 @@ DESCRIPTION
manage credentials
```
_See code: [packages/eas-cli/src/commands/credentials/index.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/credentials/index.ts)_
## `eas credentials:configure-build`
@@ -839,7 +886,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/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/credentials/configure-build.ts)_
## `eas device:create`
@@ -853,7 +900,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/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/device/create.ts)_
## `eas device:delete`
@@ -873,7 +920,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/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/device/delete.ts)_
## `eas device:list`
@@ -894,7 +941,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/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/device/list.ts)_
## `eas device:rename`
@@ -915,7 +962,7 @@ DESCRIPTION
rename a registered device
```
_See code: [packages/eas-cli/src/commands/device/rename.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/device/rename.ts)_
## `eas device:view [UDID]`
@@ -929,7 +976,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/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/device/view.ts)_
## `eas diagnostics`
@@ -943,7 +990,7 @@ DESCRIPTION
display environment info
```
_See code: [packages/eas-cli/src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v12.5.2/packages/eas-cli/src/commands/diagnostics.ts)_
_See code: [packages/eas-cli/src/commands/diagnostics.ts](https://github.com/expo/eas-cli/blob/v12.6.0/packages/eas-cli/src/commands/diagnostics.ts)_
## `eas help [COMMAND]`
@@ -1051,7 +1098,7 @@ DESCRIPTION
validate the local store configuration
```
_See code: [packages/eas-cli/src/commands/metadata/lint.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/metadata/lint.ts)_
## `eas metadata:pull`
@@ -1068,7 +1115,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/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/metadata/pull.ts)_
## `eas metadata:push`
@@ -1085,7 +1132,7 @@ DESCRIPTION
sync the local store configuration to the app stores
```
_See code: [packages/eas-cli/src/commands/metadata/push.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/metadata/push.ts)_
## `eas onboarding [TARGET_PROJECT_DIRECTORY]`
@@ -1115,7 +1162,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/v12.5.2/packages/eas-cli/src/commands/open.ts)_
_See code: [packages/eas-cli/src/commands/open.ts](https://github.com/expo/eas-cli/blob/v12.6.0/packages/eas-cli/src/commands/open.ts)_
## `eas project:info`
@@ -1129,7 +1176,7 @@ DESCRIPTION
information about the current project
```
_See code: [packages/eas-cli/src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/project/info.ts)_
## `eas project:init`
@@ -1152,7 +1199,7 @@ ALIASES
$ eas init
```
_See code: [packages/eas-cli/src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/project/init.ts)_
## `eas project:onboarding [TARGET_PROJECT_DIRECTORY]`
@@ -1170,7 +1217,7 @@ ALIASES
$ eas onboarding
```
_See code: [packages/eas-cli/src/commands/project/onboarding.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/project/onboarding.ts)_
## `eas secret:create`
@@ -1193,7 +1240,7 @@ DESCRIPTION
create an environment secret on the current project or owner account
```
_See code: [packages/eas-cli/src/commands/secret/create.ts](https://github.com/expo/eas-cli/blob/v12.5.2/packages/eas-cli/src/commands/secret/create.ts)_
_See code: [packages/eas-cli/src/commands/secret/create.ts](https://github.com/expo/eas-cli/blob/v12.6.0/packages/eas-cli/src/commands/secret/create.ts)_
## `eas secret:delete`
@@ -1211,7 +1258,7 @@ DESCRIPTION
delete an environment secret by ID
```
_See code: [packages/eas-cli/src/commands/secret/delete.ts](https://github.com/expo/eas-cli/blob/v12.5.2/packages/eas-cli/src/commands/secret/delete.ts)_
_See code: [packages/eas-cli/src/commands/secret/delete.ts](https://github.com/expo/eas-cli/blob/v12.6.0/packages/eas-cli/src/commands/secret/delete.ts)_
## `eas secret:list`
@@ -1225,7 +1272,7 @@ DESCRIPTION
list environment secrets available for your current app
```
_See code: [packages/eas-cli/src/commands/secret/list.ts](https://github.com/expo/eas-cli/blob/v12.5.2/packages/eas-cli/src/commands/secret/list.ts)_
_See code: [packages/eas-cli/src/commands/secret/list.ts](https://github.com/expo/eas-cli/blob/v12.6.0/packages/eas-cli/src/commands/secret/list.ts)_
## `eas secret:push`
@@ -1245,7 +1292,7 @@ DESCRIPTION
read environment secrets from env file and store on the server
```
_See code: [packages/eas-cli/src/commands/secret/push.ts](https://github.com/expo/eas-cli/blob/v12.5.2/packages/eas-cli/src/commands/secret/push.ts)_
_See code: [packages/eas-cli/src/commands/secret/push.ts](https://github.com/expo/eas-cli/blob/v12.6.0/packages/eas-cli/src/commands/secret/push.ts)_
## `eas submit`
@@ -1276,7 +1323,7 @@ ALIASES
$ eas build:submit
```
_See code: [packages/eas-cli/src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v12.5.2/packages/eas-cli/src/commands/submit.ts)_
_See code: [packages/eas-cli/src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v12.6.0/packages/eas-cli/src/commands/submit.ts)_
## `eas update`
@@ -1314,7 +1361,7 @@ DESCRIPTION
publish an update group
```
_See code: [packages/eas-cli/src/commands/update/index.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/update/index.ts)_
## `eas update:configure`
@@ -1332,7 +1379,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/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/update/configure.ts)_
## `eas update:delete GROUPID`
@@ -1353,7 +1400,31 @@ 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/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/update/delete.ts)_
## `eas update:edit [GROUPID]`
edit all the updates in an update group
```
USAGE
$ eas update:edit [GROUPID] [--rollout-percentage <value>] [--branch <value>] [--json --non-interactive]
ARGUMENTS
GROUPID The ID of an update group to edit.
FLAGS
--branch=<value> Branch for which to list updates to select from
--json Enable JSON output, non-JSON messages will be printed to stderr.
--non-interactive Run the command in non-interactive mode.
--rollout-percentage=<value> Rollout percentage to set for a rollout update. The specified number must be an integer
between 1 and 100.
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/v12.6.0/packages/eas-cli/src/commands/update/edit.ts)_
## `eas update:list`
@@ -1375,7 +1446,7 @@ DESCRIPTION
view the recent updates
```
_See code: [packages/eas-cli/src/commands/update/list.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/update/list.ts)_
## `eas update:republish`
@@ -1407,7 +1478,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/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/update/republish.ts)_
## `eas update:roll-back-to-embedded`
@@ -1435,7 +1506,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/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/update/roll-back-to-embedded.ts)_
## `eas update:rollback`
@@ -1455,7 +1526,7 @@ DESCRIPTION
roll back to an embedded update or an existing update
```
_See code: [packages/eas-cli/src/commands/update/rollback.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/update/rollback.ts)_
## `eas update:view GROUPID`
@@ -1475,7 +1546,7 @@ DESCRIPTION
update group details
```
_See code: [packages/eas-cli/src/commands/update/view.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/update/view.ts)_
## `eas webhook:create`
@@ -1496,7 +1567,7 @@ DESCRIPTION
create a webhook
```
_See code: [packages/eas-cli/src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/webhook/create.ts)_
## `eas webhook:delete [ID]`
@@ -1516,7 +1587,7 @@ DESCRIPTION
delete a webhook
```
_See code: [packages/eas-cli/src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/webhook/delete.ts)_
## `eas webhook:list`
@@ -1534,7 +1605,7 @@ DESCRIPTION
list webhooks
```
_See code: [packages/eas-cli/src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/webhook/list.ts)_
## `eas webhook:update`
@@ -1556,7 +1627,7 @@ DESCRIPTION
update a webhook
```
_See code: [packages/eas-cli/src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/webhook/update.ts)_
## `eas webhook:view ID`
@@ -1573,7 +1644,7 @@ DESCRIPTION
view a webhook
```
_See code: [packages/eas-cli/src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v12.5.2/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/v12.6.0/packages/eas-cli/src/commands/webhook/view.ts)_
## `eas whoami`
+942 -180
View File
File diff suppressed because it is too large. Load diff
+2 -3
View File
@@ -1,18 +1,17 @@
{
"name": "eas-cli",
"description": "EAS command line tool",
"version": "12.5.2",
"version": "12.6.0",
"author": "Expo <[email protected]>",
"bin": {
"eas": "./bin/run"
},
"bugs": "https://github.com/expo/eas-cli/issues",
"dependencies": {
"@expo/apple-utils": "1.8.0",
"@expo/apple-utils": "2.0.2",
"@expo/code-signing-certificates": "0.0.5",
"@expo/config": "8.5.4",
"@expo/config-plugins": "7.8.4",
"@expo/config-types": "50.0.0",
"@expo/eas-build-job": "1.0.136",
"@expo/eas-json": "12.5.2",
"@expo/env": "^0.3.0",
@@ -1,4 +1,4 @@
import { ExpoConfig } from '@expo/config-types';
import { ExpoConfig } from '@expo/config';
import { AppVersionSource, EasJson } from '@expo/eas-json';
import { Command, Config } from '@oclif/core';
import { vol } from 'memfs';
@@ -1,4 +1,4 @@
import { ExpoConfig } from '@expo/config-types';
import { ExpoConfig } from '@expo/config';
import { Env, Platform, Workflow } from '@expo/eas-build-job';
import {
AppVersionSource,
@@ -128,6 +128,7 @@ export const testChannelObject: UpdateChannelObject = {
branchMapping:
'{"data":[{"branchId":"754bf17f-efc0-46ab-8a59-a03f20e53e9b","branchMappingLogic":{"operand":0.15,"clientKey":"rolloutToken","branchMappingOperator":"hash_lt"}},{"branchId":"6941a8dd-5c0a-48bc-8876-f49c88ed419f","branchMappingLogic":"true"}],"version":0}',
updateBranches: [testUpdateBranch1, testUpdateBranch2],
isPaused: false,
__typename: 'UpdateChannel',
};
+13 -2
View File
@@ -110,7 +110,11 @@ export async function listAndRenderBranchesAndUpdatesOnChannelAsync(
}
): Promise<void> {
const channel = await ChannelQuery.viewUpdateChannelAsync(graphqlClient, { appId, channelName });
renderChannelHeaderContent({ channelName: channel.name, channelId: channel.id });
renderChannelHeaderContent({
channelName: channel.name,
channelId: channel.id,
isPaused: channel.isPaused,
});
if (paginatedQueryOptions.nonInteractive) {
const branches = await queryBranchesAndUpdateGroupsOnChannelAsync(graphqlClient, {
@@ -167,7 +171,11 @@ function renderPageOfChannels(
printJsonOnlyOutput({ currentPage });
} else {
for (const channel of currentPage) {
renderChannelHeaderContent({ channelName: channel.name, channelId: channel.id });
renderChannelHeaderContent({
channelName: channel.name,
channelId: channel.id,
isPaused: channel.isPaused,
});
Log.addNewLineIfNone();
logChannelDetails(channel);
@@ -196,9 +204,11 @@ function renderPageOfBranchesOnChannel(
function renderChannelHeaderContent({
channelName,
channelId,
isPaused,
}: {
channelName: string;
channelId: string;
isPaused: boolean;
}): void {
Log.addNewLineIfNone();
Log.log(chalk.bold('Channel:'));
@@ -206,6 +216,7 @@ function renderChannelHeaderContent({
formatFields([
{ label: 'Name', value: channelName },
{ label: 'ID', value: channelId },
{ label: 'Status', value: isPaused ? 'Paused' : 'Active' },
])
);
Log.addNewLineIfNone();
@@ -1,4 +1,4 @@
import { ExpoConfig } from '@expo/config-types';
import { ExpoConfig } from '@expo/config';
import ContextField, { ContextOptions } from './ContextField';
import { findProjectDirAndVerifyProjectSetupAsync } from './contextUtils/findProjectDirAndVerifyProjectSetupAsync';
@@ -1,4 +1,4 @@
import { ExpoConfig } from '@expo/config-types';
import { ExpoConfig } from '@expo/config';
import { InvalidEasJsonError } from '@expo/eas-json/build/errors';
import ContextField, { ContextOptions } from './ContextField';
@@ -1,4 +1,4 @@
import { ExpoConfig } from '@expo/config-types';
import { ExpoConfig } from '@expo/config';
import ContextField, { ContextOptions } from './ContextField';
import { findProjectDirAndVerifyProjectSetupAsync } from './contextUtils/findProjectDirAndVerifyProjectSetupAsync';
@@ -1,5 +1,4 @@
import { getProjectConfigDescription } from '@expo/config';
import { ExpoConfig } from '@expo/config-types';
import { ExpoConfig, getProjectConfigDescription } from '@expo/config';
import { Env } from '@expo/eas-build-job';
import chalk from 'chalk';
+3 -12
View File
@@ -1,10 +1,6 @@
import { Flags } from '@oclif/core';
import {
EnvironmentVariableEnvironment,
EnvironmentVariableScope,
EnvironmentVariableVisibility,
} from '../graphql/generated';
import { EnvironmentVariableEnvironment, EnvironmentVariableScope } from '../graphql/generated';
// NOTE: not exactly true, but, provided mapToLowercase and upperCaseAsync
// are used in tandem, it saves on unnecessary typying in commands
@@ -56,14 +52,9 @@ export const EASVariableFormatFlag = {
};
export const EASVariableVisibilityFlag = {
visibility: Flags.enum<EnvironmentVariableVisibility>({
visibility: Flags.enum<'plaintext' | 'sensitive' | 'encrypted'>({
description: 'Visibility of the variable',
options: mapToLowercase([
EnvironmentVariableVisibility.Secret,
EnvironmentVariableVisibility.Sensitive,
EnvironmentVariableVisibility.Public,
]),
parse: upperCaseAsync,
options: ['plaintext', 'sensitive', 'encrypted'],
}),
};
@@ -0,0 +1,113 @@
import { Flags } from '@oclif/core';
import chalk from 'chalk';
import { print } from 'graphql';
import gql from 'graphql-tag';
import { selectChannelOnAppAsync } from '../../channel/queries';
import EasCommand from '../../commandUtils/EasCommand';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
import { EasNonInteractiveAndJsonFlags } from '../../commandUtils/flags';
import { withErrorHandlingAsync } from '../../graphql/client';
import {
PauseUpdateChannelMutation,
PauseUpdateChannelMutationVariables,
UpdateChannelBasicInfoFragment,
} from '../../graphql/generated';
import { ChannelQuery } from '../../graphql/queries/ChannelQuery';
import { UpdateChannelBasicInfoFragmentNode } from '../../graphql/types/UpdateChannelBasicInfo';
import Log from '../../log';
import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
export async function pauseUpdateChannelAsync(
graphqlClient: ExpoGraphqlClient,
{ channelId }: PauseUpdateChannelMutationVariables
): Promise<UpdateChannelBasicInfoFragment> {
const data = await withErrorHandlingAsync(
graphqlClient
.mutation<PauseUpdateChannelMutation, PauseUpdateChannelMutationVariables>(
gql`
mutation PauseUpdateChannel($channelId: ID!) {
updateChannel {
pauseUpdateChannel(channelId: $channelId) {
id
...UpdateChannelBasicInfoFragment
}
}
}
${print(UpdateChannelBasicInfoFragmentNode)}
`,
{ channelId }
)
.toPromise()
);
const channel = data.updateChannel.pauseUpdateChannel;
if (!channel) {
throw new Error(`Could not find a channel with id: ${channelId}`);
}
return channel;
}
export default class ChannelPause extends EasCommand {
static override description = 'pause a channel to stop it from sending updates';
static override args = [
{
name: 'name',
required: false,
description: 'Name of the channel to edit',
},
];
static override flags = {
branch: Flags.string({
description: 'Name of the branch to point to',
}),
...EasNonInteractiveAndJsonFlags,
};
static override contextDefinition = {
...this.ContextOptions.ProjectConfig,
...this.ContextOptions.LoggedIn,
};
async runAsync(): Promise<void> {
const {
args,
flags: { json, 'non-interactive': nonInteractive },
} = await this.parse(ChannelPause);
const {
privateProjectConfig: { projectId },
loggedIn: { graphqlClient },
} = await this.getContextAsync(ChannelPause, {
nonInteractive,
});
if (json) {
enableJsonOutput();
}
const existingChannel = args.name
? await ChannelQuery.viewUpdateChannelAsync(graphqlClient, {
appId: projectId,
channelName: args.name,
})
: await selectChannelOnAppAsync(graphqlClient, {
projectId,
selectionPromptTitle: 'Select a channel to edit',
paginatedQueryOptions: { json, nonInteractive, offset: 0 },
});
const channel = await pauseUpdateChannelAsync(graphqlClient, {
channelId: existingChannel.id,
});
if (json) {
printJsonOnlyOutput(channel);
} else {
Log.withTick(chalk`Channel {bold ${channel.name}} is now paused.\n`);
Log.addNewLineIfNone();
Log.log(
chalk`Users with builds on channel {bold ${channel.name}} will no longer receive updates.`
);
}
}
}
@@ -0,0 +1,111 @@
import { Flags } from '@oclif/core';
import chalk from 'chalk';
import { print } from 'graphql';
import gql from 'graphql-tag';
import { selectChannelOnAppAsync } from '../../channel/queries';
import EasCommand from '../../commandUtils/EasCommand';
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
import { EasNonInteractiveAndJsonFlags } from '../../commandUtils/flags';
import { withErrorHandlingAsync } from '../../graphql/client';
import {
ResumeUpdateChannelMutation,
ResumeUpdateChannelMutationVariables,
UpdateChannelBasicInfoFragment,
} from '../../graphql/generated';
import { ChannelQuery } from '../../graphql/queries/ChannelQuery';
import { UpdateChannelBasicInfoFragmentNode } from '../../graphql/types/UpdateChannelBasicInfo';
import Log from '../../log';
import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
export async function resumeUpdateChannelAsync(
graphqlClient: ExpoGraphqlClient,
{ channelId }: ResumeUpdateChannelMutationVariables
): Promise<UpdateChannelBasicInfoFragment> {
const data = await withErrorHandlingAsync(
graphqlClient
.mutation<ResumeUpdateChannelMutation, ResumeUpdateChannelMutationVariables>(
gql`
mutation ResumeUpdateChannel($channelId: ID!) {
updateChannel {
resumeUpdateChannel(channelId: $channelId) {
id
...UpdateChannelBasicInfoFragment
}
}
}
${print(UpdateChannelBasicInfoFragmentNode)}
`,
{ channelId }
)
.toPromise()
);
const channel = data.updateChannel.resumeUpdateChannel;
if (!channel) {
throw new Error(`Could not find a channel with id: ${channelId}`);
}
return channel;
}
export default class ChannelResume extends EasCommand {
static override description = 'resume a channel to start sending updates';
static override args = [
{
name: 'name',
required: false,
description: 'Name of the channel to edit',
},
];
static override flags = {
branch: Flags.string({
description: 'Name of the branch to point to',
}),
...EasNonInteractiveAndJsonFlags,
};
static override contextDefinition = {
...this.ContextOptions.ProjectConfig,
...this.ContextOptions.LoggedIn,
};
async runAsync(): Promise<void> {
const {
args,
flags: { json, 'non-interactive': nonInteractive },
} = await this.parse(ChannelResume);
const {
privateProjectConfig: { projectId },
loggedIn: { graphqlClient },
} = await this.getContextAsync(ChannelResume, {
nonInteractive,
});
if (json) {
enableJsonOutput();
}
const existingChannel = args.name
? await ChannelQuery.viewUpdateChannelAsync(graphqlClient, {
appId: projectId,
channelName: args.name,
})
: await selectChannelOnAppAsync(graphqlClient, {
projectId,
selectionPromptTitle: 'Select a channel to edit',
paginatedQueryOptions: { json, nonInteractive, offset: 0 },
});
const channel = await resumeUpdateChannelAsync(graphqlClient, {
channelId: existingChannel.id,
});
if (json) {
printJsonOnlyOutput(channel);
} else {
Log.withTick(chalk`Channel {bold ${channel.name}} is now active.\n`);
Log.addNewLineIfNone();
Log.log(chalk`Users with builds on channel {bold ${channel.name}} will now receive updates.`);
}
}
}
@@ -13,8 +13,10 @@ import { EnvironmentVariableMutation } from '../../../graphql/mutations/Environm
import { AppQuery } from '../../../graphql/queries/AppQuery';
import { EnvironmentVariablesQuery } from '../../../graphql/queries/EnvironmentVariablesQuery';
import {
parseVisibility,
promptVariableEnvironmentAsync,
promptVariableNameAsync,
promptVariableTypeAsync,
promptVariableValueAsync,
} from '../../../utils/prompts';
import EnvironmentVariableCreate from '../create';
@@ -32,6 +34,10 @@ describe(EnvironmentVariableCreate, () => {
beforeEach(() => {
jest.resetAllMocks();
jest
.mocked(parseVisibility)
.mockImplementation(jest.requireActual('../../../utils/prompts').parseVisibility);
jest.mocked(AppQuery.byIdAsync).mockImplementation(async () => getMockAppFragment());
jest
.mocked(EnvironmentVariableMutation.createForAppAsync)
@@ -60,6 +66,7 @@ describe(EnvironmentVariableCreate, () => {
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
scope: EnvironmentVariableScope.Shared,
type: EnvironmentSecretType.String,
}));
jest.mocked(EnvironmentVariablesQuery.byAppIdAsync).mockImplementation(async () => []);
jest.mocked(EnvironmentVariablesQuery.sharedAsync).mockImplementation(async () => []);
@@ -68,7 +75,16 @@ describe(EnvironmentVariableCreate, () => {
describe('in interactive mode', () => {
it('creates a project variable', async () => {
const command = new EnvironmentVariableCreate(
['--name', 'VarName', '--value', 'VarValue', '--environment', 'production'],
[
'--name',
'VarName',
'--value',
'VarValue',
'--environment',
'production',
'--visibility',
'encrypted',
],
mockConfig
);
@@ -86,7 +102,7 @@ describe(EnvironmentVariableCreate, () => {
name: 'VarName',
value: 'VarValue',
environments: [EnvironmentVariableEnvironment.Production],
visibility: EnvironmentVariableVisibility.Public,
visibility: EnvironmentVariableVisibility.Secret,
type: EnvironmentSecretType.String,
},
testProjectId
@@ -95,7 +111,16 @@ describe(EnvironmentVariableCreate, () => {
it('updates an existing variable in the same environment', async () => {
const command = new EnvironmentVariableCreate(
['--name', 'VarName', '--value', 'VarValue', '--environment', 'production'],
[
'--name',
'VarName',
'--value',
'VarValue',
'--environment',
'production',
'--visibility',
'encrypted',
],
mockConfig
);
@@ -142,7 +167,7 @@ describe(EnvironmentVariableCreate, () => {
name: 'VarName',
value: 'VarValue',
environments: [EnvironmentVariableEnvironment.Production],
visibility: EnvironmentVariableVisibility.Public,
visibility: EnvironmentVariableVisibility.Secret,
});
});
@@ -322,6 +347,10 @@ describe(EnvironmentVariableCreate, () => {
jest.mocked(promptVariableNameAsync).mockImplementation(async () => 'VarName');
jest.mocked(promptVariableValueAsync).mockImplementation(async () => 'VarValue');
jest
.mocked(promptVariableTypeAsync)
.mockImplementation(async () => EnvironmentSecretType.String);
jest
.mocked(promptVariableEnvironmentAsync)
// @ts-expect-error
@@ -3,7 +3,9 @@ import { Config } from '@oclif/core';
import { ExpoGraphqlClient } from '../../../commandUtils/context/contextUtils/createGraphqlClient';
import { testProjectId } from '../../../credentials/__tests__/fixtures-constants';
import {
EnvironmentSecretType,
EnvironmentVariableEnvironment,
EnvironmentVariableFragment,
EnvironmentVariableScope,
EnvironmentVariableVisibility,
} from '../../../graphql/generated';
@@ -20,7 +22,7 @@ jest.mock('../../../utils/prompts');
describe(EnvironmentVariableGet, () => {
const graphqlClient = {} as any as ExpoGraphqlClient;
const mockConfig = {} as unknown as Config;
const mockVariables = [
const mockVariables: EnvironmentVariableFragment[] = [
{
id: 'var1',
name: 'TEST_VAR_1',
@@ -30,6 +32,7 @@ describe(EnvironmentVariableGet, () => {
updatedAt: new Date().toISOString(),
scope: EnvironmentVariableScope.Project,
visibility: EnvironmentVariableVisibility.Public,
type: EnvironmentSecretType.String,
},
];
@@ -55,6 +58,7 @@ describe(EnvironmentVariableGet, () => {
appId: testProjectId,
environment: undefined,
filterNames: ['TEST_VAR_1'],
includeFileContent: true,
}
);
expect(Log.log).toHaveBeenCalledWith(expect.stringContaining('TEST_VAR_1'));
@@ -99,6 +103,7 @@ describe(EnvironmentVariableGet, () => {
updatedAt: new Date().toISOString(),
scope: EnvironmentVariableScope.Project,
visibility: EnvironmentVariableVisibility.Public,
type: EnvironmentSecretType.String,
},
]);
await command.runAsync();
@@ -4,6 +4,7 @@ import { getMockAppFragment } from '../../../__tests__/commands/utils';
import { ExpoGraphqlClient } from '../../../commandUtils/context/contextUtils/createGraphqlClient';
import { testProjectId } from '../../../credentials/__tests__/fixtures-constants';
import {
EnvironmentSecretType,
EnvironmentVariableEnvironment,
EnvironmentVariableFragment,
EnvironmentVariableScope,
@@ -28,6 +29,7 @@ const mockVariables: EnvironmentVariableFragment[] = [
visibility: EnvironmentVariableVisibility.Public,
createdAt: undefined,
updatedAt: undefined,
type: EnvironmentSecretType.String,
},
{
id: 'var2',
@@ -38,6 +40,7 @@ const mockVariables: EnvironmentVariableFragment[] = [
visibility: EnvironmentVariableVisibility.Public,
createdAt: undefined,
updatedAt: undefined,
type: EnvironmentSecretType.String,
},
];
@@ -65,6 +68,7 @@ describe(EnvironmentVariableList, () => {
expect(EnvironmentVariablesQuery.byAppIdAsync).toHaveBeenCalledWith(graphqlClient, {
appId: testProjectId,
environment: undefined,
includeFileContent: false,
});
expect(Log.log).toHaveBeenCalledWith(expect.stringContaining('TEST_VAR_1'));
expect(Log.log).toHaveBeenCalledWith(expect.stringContaining('TEST_VAR_2'));
@@ -85,6 +89,7 @@ describe(EnvironmentVariableList, () => {
expect(EnvironmentVariablesQuery.byAppIdAsync).toHaveBeenCalledWith(graphqlClient, {
appId: testProjectId,
environment: EnvironmentVariableEnvironment.Production,
includeFileContent: false,
});
expect(Log.log).toHaveBeenCalledWith(expect.stringContaining('TEST_VAR_1'));
expect(Log.log).toHaveBeenCalledWith(expect.stringContaining('TEST_VAR_2'));
@@ -109,6 +114,7 @@ describe(EnvironmentVariableList, () => {
{
appId: testProjectId,
environment: undefined,
includeFileContent: false,
}
);
expect(Log.log).toHaveBeenCalledWith(expect.stringContaining('TEST_VAR_1'));
@@ -130,6 +136,7 @@ describe(EnvironmentVariableList, () => {
expect(EnvironmentVariablesQuery.sharedAsync).toHaveBeenCalledWith(graphqlClient, {
appId: testProjectId,
environment: undefined,
includeFileContent: false,
});
expect(Log.log).toHaveBeenCalledWith(expect.stringContaining('TEST_VAR_1'));
expect(Log.log).toHaveBeenCalledWith(expect.stringContaining('TEST_VAR_2'));
@@ -155,6 +162,7 @@ describe(EnvironmentVariableList, () => {
expect(EnvironmentVariablesQuery.sharedWithSensitiveAsync).toHaveBeenCalledWith(graphqlClient, {
appId: testProjectId,
environment: undefined,
includeFileContent: false,
});
expect(Log.log).toHaveBeenCalledWith(expect.stringContaining('TEST_VAR_1'));
expect(Log.log).toHaveBeenCalledWith(expect.stringContaining('TEST_VAR_2'));
@@ -5,6 +5,7 @@ import { getMockAppFragment } from '../../../__tests__/commands/utils';
import {
EnvironmentVariableEnvironment,
EnvironmentVariableScope,
EnvironmentVariableVisibility,
} from '../../../graphql/generated';
import { EnvironmentVariableMutation } from '../../../graphql/mutations/EnvironmentVariableMutation';
import { AppQuery } from '../../../graphql/queries/AppQuery';
@@ -59,6 +60,8 @@ describe(EnvironmentVariableUpdate, () => {
'NEW_VARIABLE',
'--environment',
'production',
'--visibility',
'plaintext',
],
mockConfig
);
@@ -71,6 +74,7 @@ describe(EnvironmentVariableUpdate, () => {
name: 'NEW_VARIABLE',
value: 'new-value',
environments: [EnvironmentVariableEnvironment.Production],
visibility: EnvironmentVariableVisibility.Public,
});
expect(Log.withTick).toHaveBeenCalledWith(
`Updated variable ${chalk.bold('TEST_VARIABLE')} on project @testuser/testpp.`
+68 -9
View File
@@ -1,5 +1,7 @@
import { Flags } from '@oclif/core';
import chalk from 'chalk';
import fs from 'fs-extra';
import path from 'path';
import EasCommand from '../../commandUtils/EasCommand';
import {
@@ -23,9 +25,12 @@ import {
} from '../../project/projectUtils';
import { confirmAsync } from '../../prompts';
import {
parseVisibility,
promptVariableEnvironmentAsync,
promptVariableNameAsync,
promptVariableTypeAsync,
promptVariableValueAsync,
promptVariableVisibilityAsync,
} from '../../utils/prompts';
import { performForEnvironmentsAsync } from '../../utils/variableUtils';
@@ -34,7 +39,8 @@ type CreateFlags = {
value?: string;
link?: boolean;
force?: boolean;
visibility?: EnvironmentVariableVisibility;
type?: 'string' | 'file';
visibility?: 'plaintext' | 'sensitive' | 'encrypted';
scope?: EnvironmentVariableScope;
environment?: EnvironmentVariableEnvironment[];
'non-interactive': boolean;
@@ -60,6 +66,10 @@ export default class EnvironmentVariableCreate extends EasCommand {
description: 'Overwrite existing variable',
default: false,
}),
type: Flags.enum<'string' | 'file'>({
description: 'The type of variable',
options: ['string', 'file'],
}),
...EASVariableVisibilityFlag,
...EASVariableScopeFlag,
...EASMultiEnvironmentFlag,
@@ -86,6 +96,7 @@ export default class EnvironmentVariableCreate extends EasCommand {
visibility,
link,
force,
type,
} = await this.promptForMissingFlagsAsync(validatedFlags);
const {
@@ -155,6 +166,7 @@ export default class EnvironmentVariableCreate extends EasCommand {
value,
visibility,
environments,
type,
})
: await EnvironmentVariableMutation.createForAppAsync(
graphqlClient,
@@ -163,7 +175,7 @@ export default class EnvironmentVariableCreate extends EasCommand {
value,
environments,
visibility,
type: EnvironmentSecretType.String,
type: type ?? EnvironmentSecretType.String,
},
projectId
);
@@ -206,6 +218,7 @@ export default class EnvironmentVariableCreate extends EasCommand {
value,
visibility,
environments,
type,
})
: await EnvironmentVariableMutation.createSharedVariableAsync(
graphqlClient,
@@ -214,7 +227,7 @@ export default class EnvironmentVariableCreate extends EasCommand {
value,
visibility,
environments,
type: EnvironmentSecretType.String,
type: type ?? EnvironmentSecretType.String,
},
ownerAccount.id
);
@@ -281,44 +294,89 @@ export default class EnvironmentVariableCreate extends EasCommand {
name,
value,
environment,
visibility = EnvironmentVariableVisibility.Public,
visibility,
'non-interactive': nonInteractive,
type,
...rest
}: CreateFlags): Promise<Required<CreateFlags>> {
}: CreateFlags): Promise<
Required<
Omit<CreateFlags, 'type' | 'visibility'> & {
type: EnvironmentSecretType | undefined;
visibility: EnvironmentVariableVisibility;
}
>
> {
if (!name) {
name = await promptVariableNameAsync(nonInteractive);
}
let newType;
let newVisibility = visibility ? parseVisibility(visibility) : undefined;
if (type === 'file') {
newType = EnvironmentSecretType.FileBase64;
} else if (type === 'string') {
newType = EnvironmentSecretType.String;
}
if (!type && !value && !nonInteractive) {
newType = await promptVariableTypeAsync(nonInteractive);
}
if (!newVisibility) {
newVisibility = await promptVariableVisibilityAsync(nonInteractive);
}
if (!value) {
value = await promptVariableValueAsync({
nonInteractive,
hidden: visibility !== EnvironmentVariableVisibility.Public,
hidden: newVisibility !== EnvironmentVariableVisibility.Public,
filePath: newType === EnvironmentSecretType.FileBase64,
});
}
let environmentFilePath: string | undefined;
if (newType === EnvironmentSecretType.FileBase64) {
environmentFilePath = path.resolve(value);
if (!(await fs.pathExists(environmentFilePath))) {
throw new Error(`File "${value}" does not exist`);
}
}
value = environmentFilePath ? await fs.readFile(environmentFilePath, 'base64') : value;
if (!environment) {
environment = await promptVariableEnvironmentAsync({ nonInteractive, multiple: true });
if (!environment || environment.length === 0) {
throw new Error('No environments selected');
}
}
newVisibility = newVisibility ?? EnvironmentVariableVisibility.Public;
return {
name,
value,
environment,
visibility,
visibility: newVisibility,
link: rest.link ?? false,
force: rest.force ?? false,
scope: rest.scope ?? EnvironmentVariableScope.Project,
'non-interactive': nonInteractive,
type: newType,
...rest,
};
}
private validateFlags(flags: CreateFlags): CreateFlags {
private validateFlags(flags: CreateFlags & { type?: string; visibility?: string }): CreateFlags {
if (flags.scope !== EnvironmentVariableScope.Shared && flags.link) {
throw new Error(
`Unexpected argument: --link can only be used when creating shared variables`
`Unexpected argument: --link can only be used when creating shared variables`
);
}
if (
flags.scope === EnvironmentVariableScope.Shared &&
flags.environment &&
@@ -329,6 +387,7 @@ export default class EnvironmentVariableCreate extends EasCommand {
'Unexpected argument: --environment in non-interactive mode can only be used with --link flag.'
);
}
return flags;
}
}
+16 -20
View File
@@ -1,5 +1,4 @@
import { Flags } from '@oclif/core';
import assert from 'assert';
import chalk from 'chalk';
import EasCommand from '../../commandUtils/EasCommand';
@@ -14,11 +13,12 @@ import {
EnvironmentVariableEnvironment,
EnvironmentVariableFragment,
EnvironmentVariableScope,
EnvironmentVariableVisibility,
} from '../../graphql/generated';
import { EnvironmentVariablesQuery } from '../../graphql/queries/EnvironmentVariablesQuery';
import Log from '../../log';
import { promptVariableEnvironmentAsync, promptVariableNameAsync } from '../../utils/prompts';
import { formatVariable } from '../../utils/variableUtils';
import { formatVariable, formatVariableValue } from '../../utils/variableUtils';
type GetFlags = {
'variable-name'?: string;
@@ -73,6 +73,13 @@ export default class EnvironmentVariableGet extends EasCommand {
name = await promptVariableNameAsync(nonInteractive);
}
if (!environment) {
environment = await promptVariableEnvironmentAsync({
nonInteractive,
multiple: false,
});
}
const variables = await getVariablesAsync(graphqlClient, scope, projectId, name, environment);
if (variables.length === 0) {
@@ -83,24 +90,11 @@ export default class EnvironmentVariableGet extends EasCommand {
let variable;
if (variables.length > 1) {
if (!environment) {
const availableEnvironments = variables.reduce<EnvironmentVariableEnvironment[]>(
(acc, v) => [...acc, ...(v.environments ?? [])],
[] as EnvironmentVariableEnvironment[]
);
environment = await promptVariableEnvironmentAsync({
nonInteractive,
multiple: false,
availableEnvironments,
});
}
assert(environment, 'Environment is required.');
const variableInEnvironment = variables.find(v => v.environments?.includes(environment!));
if (!variableInEnvironment) {
throw new Error(`Variable with name "${name}" not found in environment "${environment}"`);
throw new Error(
`Variable with name "${name}" not found in environment "${environment.toLocaleLowerCase()}"`
);
}
variable = variableInEnvironment;
@@ -108,7 +102,7 @@ export default class EnvironmentVariableGet extends EasCommand {
variable = variables[0];
}
if (!variable.value) {
if (variable.visibility === EnvironmentVariableVisibility.Secret) {
throw new Error(
`${chalk.bold(
variable.name
@@ -117,7 +111,7 @@ export default class EnvironmentVariableGet extends EasCommand {
}
if (format === 'short') {
Log.log(`${chalk.bold(variable.name)}=${variable.value}`);
Log.log(`${chalk.bold(variable.name)}=${formatVariableValue(variable)}`);
} else {
Log.log(formatVariable(variable));
}
@@ -156,6 +150,7 @@ async function getVariablesAsync(
appId: projectId,
environment,
filterNames: [name],
includeFileContent: true,
});
return appVariables;
} else {
@@ -164,6 +159,7 @@ async function getVariablesAsync(
{
appId: projectId,
filterNames: [name],
includeFileContent: true,
}
);
return sharedVariables;
+5
View File
@@ -64,6 +64,11 @@ export default class EnvironmentVariableLink extends EasCommand {
let selectedVariable = variables[0];
if (variables.length > 1) {
if (nonInteractive) {
throw new Error(
'Multiple variables found, run command with --variable-name and --variable-environment arguments.'
);
}
selectedVariable = await selectAsync(
'Select shared variable',
variables.map(variable => ({
+33 -16
View File
@@ -8,40 +8,47 @@ import {
EASVariableFormatFlag,
EASVariableScopeFlag,
} from '../../commandUtils/flags';
import { EnvironmentVariableEnvironment, EnvironmentVariableScope } from '../../graphql/generated';
import {
EnvironmentVariableEnvironment,
EnvironmentVariableFragment,
EnvironmentVariableScope,
} from '../../graphql/generated';
import { EnvironmentVariablesQuery } from '../../graphql/queries/EnvironmentVariablesQuery';
EnvironmentVariableWithFileContent,
EnvironmentVariablesQuery,
} from '../../graphql/queries/EnvironmentVariablesQuery';
import Log from '../../log';
import { promptVariableEnvironmentAsync } from '../../utils/prompts';
import { formatVariable, performForEnvironmentsAsync } from '../../utils/variableUtils';
import {
formatVariable,
formatVariableValue,
performForEnvironmentsAsync,
} from '../../utils/variableUtils';
async function getVariablesForScopeAsync(
graphqlClient: ExpoGraphqlClient,
{
scope,
includingSensitive,
includeFileContent,
environment,
projectId,
}: {
scope: EnvironmentVariableScope;
includingSensitive: boolean;
includeFileContent: boolean;
environment?: EnvironmentVariableEnvironment;
projectId: string;
}
): Promise<EnvironmentVariableFragment[]> {
): Promise<EnvironmentVariableWithFileContent[]> {
if (scope === EnvironmentVariableScope.Project) {
if (includingSensitive) {
return await EnvironmentVariablesQuery.byAppIdWithSensitiveAsync(graphqlClient, {
appId: projectId,
environment,
includeFileContent,
});
}
return await EnvironmentVariablesQuery.byAppIdAsync(graphqlClient, {
appId: projectId,
environment,
includeFileContent,
});
}
@@ -49,8 +56,13 @@ async function getVariablesForScopeAsync(
? await EnvironmentVariablesQuery.sharedWithSensitiveAsync(graphqlClient, {
appId: projectId,
environment,
includeFileContent,
})
: await EnvironmentVariablesQuery.sharedAsync(graphqlClient, { appId: projectId, environment });
: await EnvironmentVariablesQuery.sharedAsync(graphqlClient, {
appId: projectId,
environment,
includeFileContent,
});
}
export default class EnvironmentValueList extends EasCommand {
@@ -68,6 +80,10 @@ export default class EnvironmentValueList extends EasCommand {
description: 'Display sensitive values in the output',
default: false,
}),
'include-file-content': Flags.boolean({
description: 'Display files content in the output',
default: false,
}),
...EASVariableFormatFlag,
...EASVariableScopeFlag,
...EASMultiEnvironmentFlag,
@@ -80,6 +96,7 @@ export default class EnvironmentValueList extends EasCommand {
format,
scope,
'include-sensitive': includeSensitive,
'include-file-content': includeFileContent,
'non-interactive': nonInteractive,
},
} = await this.parse(EnvironmentValueList);
@@ -98,24 +115,24 @@ export default class EnvironmentValueList extends EasCommand {
const variables = await getVariablesForScopeAsync(graphqlClient, {
scope,
includingSensitive: includeSensitive,
includeFileContent,
environment,
projectId,
});
Log.addNewLineIfNone();
if (environment) {
Log.log(chalk.bold(`Environment: ${environment}`));
Log.log(chalk.bold(`Environment: ${environment.toLocaleLowerCase()}`));
}
if (variables.length === 0) {
Log.log('No variables found for this environment.');
return;
}
if (format === 'short') {
for (const variable of variables) {
// TODO: Add Learn more link
Log.log(
`${chalk.bold(variable.name)}=${
variable.value ??
"***** (This is a secret env variable that can only be accessed on EAS builder and can't be read in any UI. Learn more.)"
}`
);
Log.log(`${chalk.bold(variable.name)}=${formatVariableValue(variable)}`);
}
} else {
if (scope === EnvironmentVariableScope.Shared) {
+1 -1
View File
@@ -63,7 +63,7 @@ export default class EnvironmentVariablePull extends EasCommand {
}
}
const filePrefix = `# Environment: ${environment}\n\n`;
const filePrefix = `# Environment: ${environment.toLocaleLowerCase()}\n\n`;
const envFileContent = environmentVariables
.map((variable: EnvironmentVariableFragment) => {
+113 -108
View File
@@ -3,7 +3,7 @@ import dotenv from 'dotenv';
import fs from 'fs-extra';
import EasCommand from '../../commandUtils/EasCommand';
import { EASEnvironmentFlag } from '../../commandUtils/flags';
import { EASMultiEnvironmentFlag } from '../../commandUtils/flags';
import {
EnvironmentVariableEnvironment,
EnvironmentVariableFragment,
@@ -17,11 +17,7 @@ import {
import { EnvironmentVariablesQuery } from '../../graphql/queries/EnvironmentVariablesQuery';
import Log from '../../log';
import { confirmAsync, promptAsync } from '../../prompts';
type PushFlags = {
environment?: EnvironmentVariableEnvironment;
path: string;
};
import { promptVariableEnvironmentAsync } from '../../utils/prompts';
export default class EnvironmentVariablePush extends EasCommand {
static override description = 'push env file';
@@ -34,7 +30,7 @@ export default class EnvironmentVariablePush extends EasCommand {
};
static override flags = {
...EASEnvironmentFlag,
...EASMultiEnvironmentFlag,
path: Flags.string({
description: 'Path to the input `.env` file',
default: '.env.local',
@@ -42,9 +38,10 @@ export default class EnvironmentVariablePush extends EasCommand {
};
async runAsync(): Promise<void> {
const { flags } = await this.parse(EnvironmentVariablePush);
let {
flags: { environment: environments, path: envPath },
} = await this.parse(EnvironmentVariablePush);
const { environment, path: envPath } = this.validateFlags(flags);
const {
privateProjectConfig: { projectId },
loggedIn: { graphqlClient },
@@ -52,110 +49,127 @@ export default class EnvironmentVariablePush extends EasCommand {
nonInteractive: false,
});
if (!environments) {
environments = await promptVariableEnvironmentAsync({
nonInteractive: false,
multiple: true,
});
}
const updateVariables: Record<string, EnvironmentVariablePushInput> =
await this.parseEnvFileAsync(envPath, environment);
await this.parseEnvFileAsync(envPath, environments);
const variableNames = Object.keys(updateVariables);
const existingVariables = await EnvironmentVariablesQuery.byAppIdAsync(graphqlClient, {
appId: projectId,
environment,
filterNames: variableNames,
});
for (const environment of environments) {
const displayedEnvironment = environment.toLocaleLowerCase();
const existingVariables = await EnvironmentVariablesQuery.byAppIdAsync(graphqlClient, {
appId: projectId,
environment,
filterNames: variableNames,
});
const existingDifferentVariables: EnvironmentVariableFragment[] = [];
// Remove variables that are the same as the ones in the environment
existingVariables.forEach(variable => {
const existingVariableUpdate = updateVariables[variable.name];
if (existingVariableUpdate && existingVariableUpdate.value !== variable.value) {
existingDifferentVariables.push(variable);
} else {
delete updateVariables[variable.name];
}
});
const existingDifferentVariables: EnvironmentVariableFragment[] = [];
// Remove variables that are the same as the ones in the environment
existingVariables.forEach(existingVariable => {
const existingVariableUpdate = updateVariables[existingVariable.name];
const existingDifferentSharedVariables = existingDifferentVariables.filter(
variable => variable.scope === EnvironmentVariableScope.Shared
);
if (existingVariableUpdate) {
const hasMoreEnvironments = existingVariableUpdate.environments.some(
newEnv => !existingVariable.environments?.includes(newEnv)
);
if (existingDifferentSharedVariables.length > 0) {
const existingDifferentSharedVariablesNames = existingDifferentSharedVariables.map(
variable => variable.name
if (existingVariableUpdate.value !== existingVariable.value || hasMoreEnvironments) {
existingDifferentVariables.push(existingVariable);
} else {
delete updateVariables[existingVariable.name];
}
}
});
const existingDifferentSharedVariables = existingDifferentVariables.filter(
variable => variable.scope === EnvironmentVariableScope.Shared
);
Log.error('Shared variables cannot be overwritten by eas env:push command.');
Log.error('Remove them from the env file or unlink them from the project to continue:');
existingDifferentSharedVariablesNames.forEach(name => {
Log.error(`- ${name}`);
});
throw new Error('Shared variables cannot be overwritten by eas env:push command');
}
if (existingDifferentVariables.length > 0) {
Log.warn('Some variables already exist in the environment.');
const variableNames = existingDifferentVariables.map(variable => variable.name);
const confirmationMessage =
variableNames.length > 1
? `The ${variableNames.join(
', '
)} environment variables already exist in ${environment} environment. Do you want to override them all?`
: `The ${variableNames[0]} environment variable already exists in ${environment} environment. Do you want to override it?`;
const confirm = await confirmAsync({
message: confirmationMessage,
});
let variablesToOverwrite: string[] = [];
if (!confirm && existingDifferentVariables.length === 1) {
throw new Error('No new variables to push.');
}
if (confirm) {
variablesToOverwrite = existingDifferentVariables.map(variable => variable.name);
} else {
const promptResult = await promptAsync({
type: 'multiselect',
name: 'variablesToOverwrite',
message: 'Select variables to overwrite:',
// @ts-expect-error property missing from `@types/prompts`
optionsPerPage: 20,
choices: existingDifferentVariables.map(variable => ({
title: `${variable.name}: ${updateVariables[variable.name].value} (was ${
variable.value ?? '(secret)'
})`,
value: variable.name,
})),
if (existingDifferentSharedVariables.length > 0) {
const existingDifferentSharedVariablesNames = existingDifferentSharedVariables.map(
variable => variable.name
);
Log.error('Shared variables cannot be overwritten by eas env:push command.');
Log.error('Remove them from the env file or unlink them from the project to continue:');
existingDifferentSharedVariablesNames.forEach(name => {
Log.error(`- ${name}`);
});
variablesToOverwrite = promptResult.variablesToOverwrite;
throw new Error('Shared variables cannot be overwritten by eas env:push command');
}
for (const existingVariable of existingVariables) {
const name = existingVariable.name;
if (variablesToOverwrite.includes(name)) {
updateVariables[name]['overwrite'] = true;
if (existingDifferentVariables.length > 0) {
Log.warn(`Some variables already exist in the ${displayedEnvironment} environment.`);
const variableNames = existingDifferentVariables.map(variable => variable.name);
const confirmationMessage =
variableNames.length > 1
? `The ${variableNames.join(
', '
)} environment variables already exist in ${displayedEnvironment} environment. Do you want to override them all?`
: `The ${variableNames[0]} environment variable already exists in ${displayedEnvironment} environment. Do you want to override it?`;
const confirm = await confirmAsync({
message: confirmationMessage,
});
let variablesToOverwrite: string[] = [];
if (!confirm && existingDifferentVariables.length === 0) {
throw new Error('No new variables to push.');
}
if (confirm) {
variablesToOverwrite = existingDifferentVariables.map(variable => variable.name);
} else {
delete updateVariables[name];
const promptResult = await promptAsync({
type: 'multiselect',
name: 'variablesToOverwrite',
message: 'Select variables to overwrite:',
// @ts-expect-error property missing from `@types/prompts`
optionsPerPage: 20,
choices: existingDifferentVariables.map(variable => ({
title: `${variable.name}: ${updateVariables[variable.name].value} (was ${
variable.value ?? '(secret)'
})`,
value: variable.name,
})),
});
variablesToOverwrite = promptResult.variablesToOverwrite;
}
for (const existingVariable of existingVariables) {
const name = existingVariable.name;
if (variablesToOverwrite.includes(name)) {
updateVariables[name]['overwrite'] = true;
} else {
delete updateVariables[name];
}
}
}
}
// Check if any of the sensitive variables already exist in the environment. Prompt the user to overwrite them.
const existingSensitiveVariables = existingVariables.filter(
variable => variable.value === null
);
if (existingSensitiveVariables.length > 0) {
const existingSensitiveVariablesNames = existingSensitiveVariables.map(
variable => `- ${variable.name}`
// Check if any of the sensitive variables already exist in the environment. Prompt the user to overwrite them.
const existingSensitiveVariables = existingVariables.filter(
variable => variable.visibility !== EnvironmentVariableVisibility.Public
);
const confirm = await confirmAsync({
message: `You are about to overwrite sensitive variables.\n${existingSensitiveVariablesNames.join(
'\n'
)}\n Do you want to continue?`,
});
if (!confirm) {
throw new Error('Aborting...');
if (existingSensitiveVariables.length > 0) {
const existingSensitiveVariablesNames = existingSensitiveVariables.map(
variable => `- ${variable.name}`
);
const confirm = await confirmAsync({
message: `You are about to overwrite sensitive variables.\n${existingSensitiveVariablesNames.join(
'\n'
)}\n Do you want to continue?`,
});
if (!confirm) {
throw new Error('Aborting...');
}
}
}
@@ -171,13 +185,12 @@ export default class EnvironmentVariablePush extends EasCommand {
variablesToPush,
projectId
);
Log.log(`Uploaded env file to ${environment} environment.`);
Log.log(`Uploaded env file to ${environments.join(', ').toLocaleLowerCase()}.`);
}
private async parseEnvFileAsync(
envPath: string,
environment: string
environments: EnvironmentVariableEnvironment[]
): Promise<Record<string, EnvironmentVariablePushInput>> {
if (!(await fs.exists(envPath))) {
throw new Error(`File ${envPath} does not exist.`);
@@ -190,7 +203,7 @@ export default class EnvironmentVariablePush extends EasCommand {
pushInput[name] = {
name,
value,
environment,
environments,
visibility: name.startsWith('EXPO_SENSITIVE')
? EnvironmentVariableVisibility.Sensitive
: EnvironmentVariableVisibility.Public,
@@ -199,12 +212,4 @@ export default class EnvironmentVariablePush extends EasCommand {
return pushInput;
}
private validateFlags(flags: PushFlags): Required<PushFlags> {
if (!flags.environment) {
throw new Error('Please provide an environment to push the env file to.');
}
return { ...flags, environment: flags.environment };
}
}
+151 -41
View File
@@ -1,6 +1,8 @@
import { Flags } from '@oclif/core';
import assert from 'assert';
import chalk from 'chalk';
import fs from 'fs-extra';
import path from 'path';
import EasCommand from '../../commandUtils/EasCommand';
import {
@@ -11,6 +13,7 @@ import {
EasEnvironmentFlagParameters,
} from '../../commandUtils/flags';
import {
EnvironmentSecretType,
EnvironmentVariableEnvironment,
EnvironmentVariableFragment,
EnvironmentVariableScope,
@@ -25,8 +28,10 @@ import {
} from '../../project/projectUtils';
import { selectAsync } from '../../prompts';
import {
parseVisibility,
promptVariableEnvironmentAsync,
promptVariableNameAsync,
promptVariableTypeAsync,
promptVariableValueAsync,
promptVariableVisibilityAsync,
} from '../../utils/prompts';
@@ -37,7 +42,8 @@ type UpdateFlags = {
value?: string;
scope?: EnvironmentVariableScope;
environment?: EnvironmentVariableEnvironment[];
visibility?: EnvironmentVariableVisibility;
visibility?: 'plaintext' | 'sensitive' | 'encrypted';
type?: 'string' | 'file';
'variable-name'?: string;
'variable-environment'?: EnvironmentVariableEnvironment;
'non-interactive': boolean;
@@ -63,6 +69,10 @@ export default class EnvironmentVariableUpdate extends EasCommand {
value: Flags.string({
description: 'New value or the variable',
}),
type: Flags.enum<'string' | 'file'>({
description: 'The type of variable',
options: ['string', 'file'],
}),
...EASVariableVisibilityFlag,
...EASVariableScopeFlag,
...EASMultiEnvironmentFlag,
@@ -77,14 +87,15 @@ export default class EnvironmentVariableUpdate extends EasCommand {
async runAsync(): Promise<void> {
const { flags } = await this.parse(EnvironmentVariableUpdate);
let {
const {
name,
value,
value: rawValue,
scope,
'variable-name': currentName,
'variable-environment': currentEnvironment,
'non-interactive': nonInteractive,
environment: environments,
type,
visibility,
} = this.validateFlags(flags);
@@ -126,7 +137,7 @@ export default class EnvironmentVariableUpdate extends EasCommand {
if (existingVariables.length === 0) {
throw new Error(
`Variable with name ${currentName} ${
currentEnvironment ? `in environment ${currentEnvironment}` : ''
currentEnvironment ? `in environment ${currentEnvironment.toLocaleLowerCase()}` : ''
} does not exist ${suffix}.`
);
} else if (existingVariables.length > 1) {
@@ -142,47 +153,29 @@ export default class EnvironmentVariableUpdate extends EasCommand {
}
assert(selectedVariable, 'Variable must be selected');
if (!nonInteractive) {
if (!name) {
name = await promptVariableNameAsync(nonInteractive, selectedVariable.name);
if (!name || name.length === 0) {
name = undefined;
}
}
if (!value) {
value = await promptVariableValueAsync({
nonInteractive,
required: false,
initial: selectedVariable.value,
});
if (!value || value.length === 0) {
value = undefined;
}
}
if (!environments || environments.length === 0) {
environments = await promptVariableEnvironmentAsync({
nonInteractive,
multiple: true,
selectedEnvironments: selectedVariable.environments ?? [],
});
}
if (!visibility) {
visibility = await promptVariableVisibilityAsync(
nonInteractive,
selectedVariable.visibility
);
}
}
const {
name: newName,
value: newValue,
environment: newEnvironments,
visibility: newVisibility,
type: newType,
} = await this.promptForMissingFlagsAsync(selectedVariable, {
name,
value: rawValue,
environment: environments,
visibility,
'non-interactive': nonInteractive,
type,
});
const variable = await EnvironmentVariableMutation.updateAsync(graphqlClient, {
id: selectedVariable.id,
name,
value,
environments,
visibility,
name: newName,
value: newValue,
environments: newEnvironments,
type: newType,
visibility: newVisibility,
});
if (!variable) {
throw new Error(`Could not update variable with name ${name} ${suffix}`);
@@ -197,8 +190,125 @@ export default class EnvironmentVariableUpdate extends EasCommand {
'Current name is required in non-interactive mode. Run the command with --variable-name flag.'
);
}
if (flags['type'] && !flags['value']) {
throw new Error('Value is required when type is set. Run the command with --value flag.');
}
}
return flags;
}
private async promptForMissingFlagsAsync(
selectedVariable: EnvironmentVariableFragment,
{
name,
value,
environment: environments,
visibility,
'non-interactive': nonInteractive,
type,
...rest
}: UpdateFlags
): Promise<
Omit<UpdateFlags, 'type' | 'visibility'> & {
type?: EnvironmentSecretType;
visibility?: EnvironmentVariableVisibility;
}
> {
let newType;
let newVisibility: EnvironmentVariableVisibility | undefined;
if (type === 'file') {
newType = EnvironmentSecretType.FileBase64;
} else if (type === 'string') {
newType = EnvironmentSecretType.String;
}
if (!nonInteractive) {
if (!name) {
name = await promptVariableNameAsync(nonInteractive, selectedVariable.name);
if (!name || name.length === 0) {
name = undefined;
}
}
if (!type && !value && !nonInteractive) {
newType = await promptVariableTypeAsync(nonInteractive, selectedVariable.type);
if (!newType || newType === selectedVariable.type) {
newType = undefined;
}
}
if (!value) {
value = await promptVariableValueAsync({
nonInteractive,
required: false,
filePath: (newType ?? selectedVariable.type) === EnvironmentSecretType.FileBase64,
initial:
(newType ?? selectedVariable.type) === EnvironmentSecretType.FileBase64
? undefined
: selectedVariable.value,
});
if (!value || value.length === 0 || value === selectedVariable.value) {
value = undefined;
}
}
let environmentFilePath: string | undefined;
if ((newType ?? selectedVariable.type) === EnvironmentSecretType.FileBase64 && value) {
environmentFilePath = path.resolve(value);
if (!(await fs.pathExists(environmentFilePath))) {
throw new Error(`File "${value}" does not exist`);
}
}
value = environmentFilePath ? await fs.readFile(environmentFilePath, 'base64') : value;
if (!environments || environments.length === 0) {
environments = await promptVariableEnvironmentAsync({
nonInteractive,
multiple: true,
selectedEnvironments: selectedVariable.environments ?? [],
});
if (
!environments ||
environments.length === 0 ||
environments === selectedVariable.environments
) {
environments = undefined;
}
}
if (!visibility) {
newVisibility = await promptVariableVisibilityAsync(
nonInteractive,
selectedVariable.visibility
);
if (!newVisibility || newVisibility === selectedVariable.visibility) {
newVisibility = undefined;
}
}
}
if (visibility) {
newVisibility = parseVisibility(visibility);
}
return {
name,
value,
environment: environments,
visibility: newVisibility,
scope: rest.scope ?? EnvironmentVariableScope.Project,
'non-interactive': nonInteractive,
type: newType,
...rest,
};
}
}
@@ -1,5 +1,4 @@
import { ConfigError, getProjectConfigDescription } from '@expo/config';
import { ExpoConfig } from '@expo/config-types';
import { ConfigError, ExpoConfig, getProjectConfigDescription } from '@expo/config';
import { Flags } from '@oclif/core';
import chalk from 'chalk';
import nullthrows from 'nullthrows';
@@ -1,4 +1,4 @@
import { ExpoConfig } from '@expo/config-types';
import { ExpoConfig } from '@expo/config';
import { Platform } from '@expo/eas-build-job';
import { AppVersionSource, EasJson } from '@expo/eas-json';
import chalk from 'chalk';
+46 -3
View File
@@ -2,12 +2,14 @@ import { Flags } from '@oclif/core';
import assert from 'assert';
import chalk from 'chalk';
import { selectBranchOnAppAsync } from '../../branch/queries';
import EasCommand from '../../commandUtils/EasCommand';
import { EasNonInteractiveAndJsonFlags } from '../../commandUtils/flags';
import { PublishMutation } from '../../graphql/mutations/PublishMutation';
import { UpdateQuery } from '../../graphql/queries/UpdateQuery';
import Log from '../../log';
import { promptAsync } from '../../prompts';
import { selectUpdateGroupOnBranchAsync } from '../../update/queries';
import {
formatUpdateGroup,
getUpdateGroupDescriptions,
@@ -17,12 +19,10 @@ import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
export default class UpdateEdit extends EasCommand {
static override description = 'edit all the updates in an update group';
static override hidden = true;
static override args = [
{
name: 'groupId',
required: true,
description: 'The ID of an update group to edit.',
},
];
@@ -34,24 +34,30 @@ export default class UpdateEdit extends EasCommand {
min: 0,
max: 100,
}),
branch: Flags.string({
description: 'Branch for which to list updates to select from',
}),
...EasNonInteractiveAndJsonFlags,
};
static override contextDefinition = {
...this.ContextOptions.ProjectConfig,
...this.ContextOptions.LoggedIn,
};
async runAsync(): Promise<void> {
const {
args: { groupId },
args: { groupId: maybeGroupId },
flags: {
'rollout-percentage': rolloutPercentage,
json: jsonFlag,
'non-interactive': nonInteractive,
branch: branchFlag,
},
} = await this.parse(UpdateEdit);
const {
privateProjectConfig: { projectId },
loggedIn: { graphqlClient },
} = await this.getContextAsync(UpdateEdit, { nonInteractive });
@@ -59,6 +65,43 @@ export default class UpdateEdit extends EasCommand {
enableJsonOutput();
}
let groupId: string | undefined = maybeGroupId;
if (!groupId) {
let branch = branchFlag;
if (!branch) {
const validationMessage = 'Branch name may not be empty.';
if (nonInteractive) {
throw new Error(validationMessage);
}
const selectedBranch = await selectBranchOnAppAsync(graphqlClient, {
projectId,
promptTitle: 'On which branch would you like search for an update to edit?',
displayTextForListItem: updateBranch => ({
title: updateBranch.name,
}),
paginatedQueryOptions: {
json: jsonFlag,
nonInteractive,
offset: 0,
},
});
branch = selectedBranch.name;
}
const selectedUpdateGroup = await selectUpdateGroupOnBranchAsync(graphqlClient, {
projectId,
branchName: branch,
paginatedQueryOptions: {
json: jsonFlag,
nonInteractive,
offset: 0,
},
});
groupId = selectedUpdateGroup[0].group;
}
const proposedUpdatesToEdit = (
await UpdateQuery.viewUpdateGroupAsync(graphqlClient, { groupId })
).map(u => ({ updateId: u.id, rolloutPercentage: u.rolloutPercentage }));
+1 -1
View File
@@ -1,4 +1,4 @@
import { ExpoConfig } from '@expo/config-types';
import { ExpoConfig } from '@expo/config';
import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
import { Client } from '../vcs/vcs';
+174 -31
View File
@@ -762,7 +762,8 @@ export type ActivityTimelineProjectActivity = {
export enum ActivityTimelineProjectActivityType {
Build = 'BUILD',
Submission = 'SUBMISSION',
Update = 'UPDATE'
Update = 'UPDATE',
Worker = 'WORKER'
}
/** A regular user, SSO user, or robot that can authenticate with Expo services and be a member of accounts. */
@@ -1373,6 +1374,7 @@ export type App = Project & {
workerDeploymentsCrashes?: Maybe<WorkerDeploymentCrashes>;
workerDeploymentsRequest: WorkerDeploymentRequestEdge;
workerDeploymentsRequests?: Maybe<WorkerDeploymentRequests>;
workflows: Array<Workflow>;
};
@@ -2531,17 +2533,13 @@ export type AuditLogMutationExportAuditLogsArgs = {
export type AuditLogQuery = {
__typename?: 'AuditLogQuery';
/** Query Audit Logs by account ID */
byAccountId: Array<AuditLog>;
/** Audit logs for account */
byId: AuditLog;
};
export type AuditLogQueryByAccountIdArgs = {
accountId: Scalars['ID']['input'];
limit: Scalars['Int']['input'];
offset: Scalars['Int']['input'];
targetEntityMutationType?: InputMaybe<Array<TargetEntityMutationType>>;
targetEntityTypeName?: InputMaybe<Array<EntityTypeName>>;
export type AuditLogQueryByIdArgs = {
auditLogId: Scalars['ID']['input'];
};
export enum AuditLogsExportFormat {
@@ -3881,7 +3879,9 @@ export enum EntityTypeName {
GoogleServiceAccountKey = 'GoogleServiceAccountKey',
IosAppCredentials = 'IosAppCredentials',
UserInvitation = 'UserInvitation',
UserPermission = 'UserPermission'
UserPermission = 'UserPermission',
Workflow = 'Workflow',
WorkflowRevision = 'WorkflowRevision'
}
export type EnvironmentSecret = {
@@ -5463,6 +5463,25 @@ export type RequestsFilters = {
statusType?: InputMaybe<Array<ResponseStatusType>>;
};
export type RequestsOrderBy = {
direction?: InputMaybe<RequestsOrderByDirection>;
field: RequestsOrderByField;
};
export enum RequestsOrderByDirection {
Asc = 'ASC',
Desc = 'DESC'
}
export enum RequestsOrderByField {
AssetsSum = 'ASSETS_SUM',
CacheHitRatio = 'CACHE_HIT_RATIO',
CachePassRatio = 'CACHE_PASS_RATIO',
CrashesSum = 'CRASHES_SUM',
Duration = 'DURATION',
RequestsSum = 'REQUESTS_SUM'
}
export type RescindUserInvitationResult = {
__typename?: 'RescindUserInvitationResult';
id: Scalars['ID']['output'];
@@ -5799,6 +5818,8 @@ export type RootQuery = {
/** Top-level query object for querying Webhooks. */
webhook: WebhookQuery;
workerDeployment: WorkerDeploymentQuery;
workflowRevisions: WorkflowRevisionQuery;
workflows: WorkflowQuery;
};
@@ -7175,19 +7196,14 @@ export type UserAuditLogMutationExportUserAuditLogsArgs = {
export type UserAuditLogQuery = {
__typename?: 'UserAuditLogQuery';
/** Query User Audit Logs by user ID */
byUserId: Array<UserAuditLog>;
/** Audit logs for user */
byId: UserAuditLog;
byUserIdPaginated: UserAuditLogConnection;
};
export type UserAuditLogQueryByUserIdArgs = {
limit: Scalars['Int']['input'];
offset: Scalars['Int']['input'];
targetEntityMutationType?: InputMaybe<Array<TargetEntityMutationType>>;
targetEntityTypeName?: InputMaybe<Array<UserEntityTypeName>>;
userId: Scalars['ID']['input'];
export type UserAuditLogQueryByIdArgs = {
auditLogId: Scalars['ID']['input'];
};
@@ -7517,8 +7533,10 @@ export type WorkerCustomDomain = {
verificationRecord?: Maybe<CustomDomainDnsRecord>;
};
export type WorkerDeployment = {
export type WorkerDeployment = ActivityTimelineProjectActivity & {
__typename?: 'WorkerDeployment';
activityTimestamp: Scalars['DateTime']['output'];
actor?: Maybe<Actor>;
aliases?: Maybe<Array<WorkerDeploymentAlias>>;
crashes?: Maybe<WorkerDeploymentCrashes>;
createdAt: Scalars['DateTime']['output'];
@@ -7719,8 +7737,10 @@ export type WorkerDeploymentRequests = {
byBrowser: Array<WorkerDeploymentRequestsBrowserEdge>;
byCacheStatus: Array<WorkerDeploymentRequestsCacheStatusEdge>;
byContinent: Array<WorkerDeploymentRequestsContinentEdge>;
byCountry: Array<WorkerDeploymentRequestsCountryEdge>;
byMethod: Array<WorkerDeploymentRequestsMethodEdge>;
byOS: Array<WorkerDeploymentRequestsOperatingSystemEdge>;
byResponseType: Array<WorkerDeploymentRequestsResponseTypeEdge>;
byStatusType: Array<WorkerDeploymentRequestsStatusTypeEdge>;
interval: Scalars['Int']['output'];
minRowsWithoutLimit: Scalars['Int']['output'];
@@ -7729,6 +7749,54 @@ export type WorkerDeploymentRequests = {
timeseries: Array<WorkerDeploymentRequestsTimeseriesEdge>;
};
export type WorkerDeploymentRequestsByBrowserArgs = {
limit?: InputMaybe<Scalars['Int']['input']>;
orderBy?: InputMaybe<RequestsOrderBy>;
};
export type WorkerDeploymentRequestsByCacheStatusArgs = {
limit?: InputMaybe<Scalars['Int']['input']>;
orderBy?: InputMaybe<RequestsOrderBy>;
};
export type WorkerDeploymentRequestsByContinentArgs = {
limit?: InputMaybe<Scalars['Int']['input']>;
orderBy?: InputMaybe<RequestsOrderBy>;
};
export type WorkerDeploymentRequestsByCountryArgs = {
limit?: InputMaybe<Scalars['Int']['input']>;
orderBy?: InputMaybe<RequestsOrderBy>;
};
export type WorkerDeploymentRequestsByMethodArgs = {
limit?: InputMaybe<Scalars['Int']['input']>;
orderBy?: InputMaybe<RequestsOrderBy>;
};
export type WorkerDeploymentRequestsByOsArgs = {
limit?: InputMaybe<Scalars['Int']['input']>;
orderBy?: InputMaybe<RequestsOrderBy>;
};
export type WorkerDeploymentRequestsByResponseTypeArgs = {
limit?: InputMaybe<Scalars['Int']['input']>;
orderBy?: InputMaybe<RequestsOrderBy>;
};
export type WorkerDeploymentRequestsByStatusTypeArgs = {
limit?: InputMaybe<Scalars['Int']['input']>;
orderBy?: InputMaybe<RequestsOrderBy>;
};
export type WorkerDeploymentRequestsAggregationNode = {
__typename?: 'WorkerDeploymentRequestsAggregationNode';
assetsPerMs?: Maybe<Scalars['Float']['output']>;
@@ -7788,6 +7856,12 @@ export type WorkerDeploymentRequestsContinentEdge = {
node: WorkerDeploymentRequestsAggregationNode;
};
export type WorkerDeploymentRequestsCountryEdge = {
__typename?: 'WorkerDeploymentRequestsCountryEdge';
country?: Maybe<Scalars['String']['output']>;
node: WorkerDeploymentRequestsAggregationNode;
};
export type WorkerDeploymentRequestsMethodEdge = {
__typename?: 'WorkerDeploymentRequestsMethodEdge';
method: Scalars['String']['output'];
@@ -7800,6 +7874,12 @@ export type WorkerDeploymentRequestsOperatingSystemEdge = {
os?: Maybe<UserAgentOs>;
};
export type WorkerDeploymentRequestsResponseTypeEdge = {
__typename?: 'WorkerDeploymentRequestsResponseTypeEdge';
node: WorkerDeploymentRequestsAggregationNode;
responseType: ResponseType;
};
export type WorkerDeploymentRequestsStatusTypeEdge = {
__typename?: 'WorkerDeploymentRequestsStatusTypeEdge';
node: WorkerDeploymentRequestsAggregationNode;
@@ -7811,8 +7891,10 @@ export type WorkerDeploymentRequestsTimeseriesEdge = {
byBrowser: Array<WorkerDeploymentRequestsBrowserEdge>;
byCacheStatus: Array<WorkerDeploymentRequestsCacheStatusEdge>;
byContinent: Array<WorkerDeploymentRequestsContinentEdge>;
byCountry: Array<WorkerDeploymentRequestsCountryEdge>;
byMethod: Array<WorkerDeploymentRequestsMethodEdge>;
byOS: Array<WorkerDeploymentRequestsOperatingSystemEdge>;
byResponseType: Array<WorkerDeploymentRequestsResponseTypeEdge>;
byStatusType: Array<WorkerDeploymentRequestsStatusTypeEdge>;
node?: Maybe<WorkerDeploymentRequestsAggregationNode>;
timestamp: Scalars['DateTime']['output'];
@@ -7833,6 +7915,17 @@ export enum WorkerLoggerLevel {
Warn = 'WARN'
}
export type Workflow = {
__typename?: 'Workflow';
app: App;
createdAt: Scalars['DateTime']['output'];
fileName: Scalars['String']['output'];
id: Scalars['ID']['output'];
name?: Maybe<Scalars['String']['output']>;
revisions: Array<WorkflowRevision>;
updatedAt: Scalars['DateTime']['output'];
};
export type WorkflowJobMutation = {
__typename?: 'WorkflowJobMutation';
approveWorkflowJob: Scalars['ID']['output'];
@@ -7843,6 +7936,38 @@ export type WorkflowJobMutationApproveWorkflowJobArgs = {
workflowJobId: Scalars['ID']['input'];
};
/** Look up Workflow by ID */
export type WorkflowQuery = {
__typename?: 'WorkflowQuery';
byId: Workflow;
};
/** Look up Workflow by ID */
export type WorkflowQueryByIdArgs = {
workflowId: Scalars['ID']['input'];
};
export type WorkflowRevision = {
__typename?: 'WorkflowRevision';
blobSha: Scalars['String']['output'];
commitSha: Scalars['String']['output'];
createdAt: Scalars['DateTime']['output'];
id: Scalars['ID']['output'];
workflow: Workflow;
yamlConfig: Scalars['String']['output'];
};
export type WorkflowRevisionQuery = {
__typename?: 'WorkflowRevisionQuery';
byId: WorkflowRevision;
};
export type WorkflowRevisionQueryByIdArgs = {
workflowRevisionId: Scalars['ID']['input'];
};
export type DeleteAndroidAppBuildCredentialsResult = {
__typename?: 'deleteAndroidAppBuildCredentialsResult';
id: Scalars['ID']['output'];
@@ -7931,6 +8056,20 @@ export type UpdateChannelBranchMappingMutationVariables = Exact<{
export type UpdateChannelBranchMappingMutation = { __typename?: 'RootMutation', updateChannel: { __typename?: 'UpdateChannelMutation', editUpdateChannel: { __typename?: 'UpdateChannel', id: string, name: string, branchMapping: string } } };
export type PauseUpdateChannelMutationVariables = Exact<{
channelId: Scalars['ID']['input'];
}>;
export type PauseUpdateChannelMutation = { __typename?: 'RootMutation', updateChannel: { __typename?: 'UpdateChannelMutation', pauseUpdateChannel: { __typename?: 'UpdateChannel', id: string, name: string, branchMapping: string } } };
export type ResumeUpdateChannelMutationVariables = Exact<{
channelId: Scalars['ID']['input'];
}>;
export type ResumeUpdateChannelMutation = { __typename?: 'RootMutation', updateChannel: { __typename?: 'UpdateChannelMutation', resumeUpdateChannel: { __typename?: 'UpdateChannel', id: string, name: string, branchMapping: string } } };
export type AppInfoQueryVariables = Exact<{
appId: Scalars['String']['input'];
}>;
@@ -8436,7 +8575,7 @@ export type LinkSharedEnvironmentVariableMutationVariables = Exact<{
}>;
export type LinkSharedEnvironmentVariableMutation = { __typename?: 'RootMutation', environmentVariable: { __typename?: 'EnvironmentVariableMutation', linkSharedEnvironmentVariable: { __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environments?: Array<EnvironmentVariableEnvironment> | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null } } };
export type LinkSharedEnvironmentVariableMutation = { __typename?: 'RootMutation', environmentVariable: { __typename?: 'EnvironmentVariableMutation', linkSharedEnvironmentVariable: { __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environments?: Array<EnvironmentVariableEnvironment> | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null, type: EnvironmentSecretType } } };
export type UnlinkSharedEnvironmentVariableMutationVariables = Exact<{
appId: Scalars['ID']['input'];
@@ -8445,7 +8584,7 @@ export type UnlinkSharedEnvironmentVariableMutationVariables = Exact<{
}>;
export type UnlinkSharedEnvironmentVariableMutation = { __typename?: 'RootMutation', environmentVariable: { __typename?: 'EnvironmentVariableMutation', unlinkSharedEnvironmentVariable: { __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environments?: Array<EnvironmentVariableEnvironment> | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null } } };
export type UnlinkSharedEnvironmentVariableMutation = { __typename?: 'RootMutation', environmentVariable: { __typename?: 'EnvironmentVariableMutation', unlinkSharedEnvironmentVariable: { __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environments?: Array<EnvironmentVariableEnvironment> | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null, type: EnvironmentSecretType } } };
export type CreateEnvironmentVariableForAccountMutationVariables = Exact<{
input: CreateSharedEnvironmentVariableInput;
@@ -8453,7 +8592,7 @@ export type CreateEnvironmentVariableForAccountMutationVariables = Exact<{
}>;
export type CreateEnvironmentVariableForAccountMutation = { __typename?: 'RootMutation', environmentVariable: { __typename?: 'EnvironmentVariableMutation', createEnvironmentVariableForAccount: { __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environments?: Array<EnvironmentVariableEnvironment> | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null } } };
export type CreateEnvironmentVariableForAccountMutation = { __typename?: 'RootMutation', environmentVariable: { __typename?: 'EnvironmentVariableMutation', createEnvironmentVariableForAccount: { __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environments?: Array<EnvironmentVariableEnvironment> | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null, type: EnvironmentSecretType } } };
export type CreateEnvironmentVariableForAppMutationVariables = Exact<{
input: CreateEnvironmentVariableInput;
@@ -8461,14 +8600,14 @@ export type CreateEnvironmentVariableForAppMutationVariables = Exact<{
}>;
export type CreateEnvironmentVariableForAppMutation = { __typename?: 'RootMutation', environmentVariable: { __typename?: 'EnvironmentVariableMutation', createEnvironmentVariableForApp: { __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environments?: Array<EnvironmentVariableEnvironment> | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null } } };
export type CreateEnvironmentVariableForAppMutation = { __typename?: 'RootMutation', environmentVariable: { __typename?: 'EnvironmentVariableMutation', createEnvironmentVariableForApp: { __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environments?: Array<EnvironmentVariableEnvironment> | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null, type: EnvironmentSecretType } } };
export type UpdateEnvironmentVariableMutationVariables = Exact<{
input: UpdateEnvironmentVariableInput;
}>;
export type UpdateEnvironmentVariableMutation = { __typename?: 'RootMutation', environmentVariable: { __typename?: 'EnvironmentVariableMutation', updateEnvironmentVariable: { __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environments?: Array<EnvironmentVariableEnvironment> | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null } } };
export type UpdateEnvironmentVariableMutation = { __typename?: 'RootMutation', environmentVariable: { __typename?: 'EnvironmentVariableMutation', updateEnvironmentVariable: { __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environments?: Array<EnvironmentVariableEnvironment> | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null, type: EnvironmentSecretType } } };
export type DeleteEnvironmentVariableMutationVariables = Exact<{
id: Scalars['ID']['input'];
@@ -8686,7 +8825,7 @@ export type ViewUpdateChannelOnAppQueryVariables = Exact<{
}>;
export type ViewUpdateChannelOnAppQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, updateChannelByName?: { __typename?: 'UpdateChannel', id: string, name: string, updatedAt: any, createdAt: any, branchMapping: string, updateBranches: Array<{ __typename?: 'UpdateBranch', id: string, name: string, updateGroups: Array<Array<{ __typename?: 'Update', id: string, group: string, message?: string | null, createdAt: any, runtimeVersion: string, platform: string, manifestFragment: string, isRollBackToEmbedded: boolean, manifestPermalink: string, gitCommitHash?: string | null, rolloutPercentage?: number | null, actor?: { __typename: 'Robot', firstName?: string | null, id: string } | { __typename: 'SSOUser', username: string, id: string } | { __typename: 'User', username: string, id: string } | null, branch: { __typename?: 'UpdateBranch', id: string, name: string }, codeSigningInfo?: { __typename?: 'CodeSigningInfo', keyid: string, sig: string, alg: string } | null, rolloutControlUpdate?: { __typename?: 'Update', id: string } | null }>> }> } | null } } };
export type ViewUpdateChannelOnAppQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, updateChannelByName?: { __typename?: 'UpdateChannel', id: string, isPaused: boolean, name: string, updatedAt: any, createdAt: any, branchMapping: string, updateBranches: Array<{ __typename?: 'UpdateBranch', id: string, name: string, updateGroups: Array<Array<{ __typename?: 'Update', id: string, group: string, message?: string | null, createdAt: any, runtimeVersion: string, platform: string, manifestFragment: string, isRollBackToEmbedded: boolean, manifestPermalink: string, gitCommitHash?: string | null, rolloutPercentage?: number | null, actor?: { __typename: 'Robot', firstName?: string | null, id: string } | { __typename: 'SSOUser', username: string, id: string } | { __typename: 'User', username: string, id: string } | null, branch: { __typename?: 'UpdateBranch', id: string, name: string }, codeSigningInfo?: { __typename?: 'CodeSigningInfo', keyid: string, sig: string, alg: string } | null, rolloutControlUpdate?: { __typename?: 'Update', id: string } | null }>> }> } | null } } };
export type ViewUpdateChannelsOnAppQueryVariables = Exact<{
appId: Scalars['String']['input'];
@@ -8695,7 +8834,7 @@ export type ViewUpdateChannelsOnAppQueryVariables = Exact<{
}>;
export type ViewUpdateChannelsOnAppQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, updateChannels: Array<{ __typename?: 'UpdateChannel', id: string, name: string, updatedAt: any, createdAt: any, branchMapping: string, updateBranches: Array<{ __typename?: 'UpdateBranch', id: string, name: string, updateGroups: Array<Array<{ __typename?: 'Update', id: string, group: string, message?: string | null, createdAt: any, runtimeVersion: string, platform: string, manifestFragment: string, isRollBackToEmbedded: boolean, manifestPermalink: string, gitCommitHash?: string | null, rolloutPercentage?: number | null, actor?: { __typename: 'Robot', firstName?: string | null, id: string } | { __typename: 'SSOUser', username: string, id: string } | { __typename: 'User', username: string, id: string } | null, branch: { __typename?: 'UpdateBranch', id: string, name: string }, codeSigningInfo?: { __typename?: 'CodeSigningInfo', keyid: string, sig: string, alg: string } | null, rolloutControlUpdate?: { __typename?: 'Update', id: string } | null }>> }> }> } } };
export type ViewUpdateChannelsOnAppQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, updateChannels: Array<{ __typename?: 'UpdateChannel', id: string, isPaused: boolean, name: string, updatedAt: any, createdAt: any, branchMapping: string, updateBranches: Array<{ __typename?: 'UpdateBranch', id: string, name: string, updateGroups: Array<Array<{ __typename?: 'Update', id: string, group: string, message?: string | null, createdAt: any, runtimeVersion: string, platform: string, manifestFragment: string, isRollBackToEmbedded: boolean, manifestPermalink: string, gitCommitHash?: string | null, rolloutPercentage?: number | null, actor?: { __typename: 'Robot', firstName?: string | null, id: string } | { __typename: 'SSOUser', username: string, id: string } | { __typename: 'User', username: string, id: string } | null, branch: { __typename?: 'UpdateBranch', id: string, name: string }, codeSigningInfo?: { __typename?: 'CodeSigningInfo', keyid: string, sig: string, alg: string } | null, rolloutControlUpdate?: { __typename?: 'Update', id: string } | null }>> }> }> } } };
export type ViewUpdateChannelsPaginatedOnAppQueryVariables = Exact<{
appId: Scalars['String']['input'];
@@ -8719,37 +8858,41 @@ export type EnvironmentVariablesIncludingSensitiveByAppIdQueryVariables = Exact<
appId: Scalars['String']['input'];
filterNames?: InputMaybe<Array<Scalars['String']['input']> | Scalars['String']['input']>;
environment?: InputMaybe<EnvironmentVariableEnvironment>;
includeFileContent: Scalars['Boolean']['input'];
}>;
export type EnvironmentVariablesIncludingSensitiveByAppIdQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, environmentVariablesIncludingSensitive: Array<{ __typename?: 'EnvironmentVariableWithSecret', id: string, name: string, value?: string | null, environments?: Array<EnvironmentVariableEnvironment> | null }> } } };
export type EnvironmentVariablesIncludingSensitiveByAppIdQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, environmentVariablesIncludingSensitive: Array<{ __typename?: 'EnvironmentVariableWithSecret', id: string, name: string, value?: string | null, environments?: Array<EnvironmentVariableEnvironment> | null, valueWithFileContent?: string | null }> } } };
export type EnvironmentVariablesByAppIdQueryVariables = Exact<{
appId: Scalars['String']['input'];
filterNames?: InputMaybe<Array<Scalars['String']['input']> | Scalars['String']['input']>;
environment?: InputMaybe<EnvironmentVariableEnvironment>;
includeFileContent: Scalars['Boolean']['input'];
}>;
export type EnvironmentVariablesByAppIdQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, environmentVariables: Array<{ __typename?: 'EnvironmentVariable', id: string, linkedEnvironments?: Array<EnvironmentVariableEnvironment> | null, name: string, value?: string | null, environments?: Array<EnvironmentVariableEnvironment> | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null }> } } };
export type EnvironmentVariablesByAppIdQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, environmentVariables: Array<{ __typename?: 'EnvironmentVariable', id: string, linkedEnvironments?: Array<EnvironmentVariableEnvironment> | null, name: string, value?: string | null, environments?: Array<EnvironmentVariableEnvironment> | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null, type: EnvironmentSecretType, valueWithFileContent?: string | null }> } } };
export type EnvironmentVariablesSharedQueryVariables = Exact<{
appId: Scalars['String']['input'];
filterNames?: InputMaybe<Array<Scalars['String']['input']> | Scalars['String']['input']>;
environment?: InputMaybe<EnvironmentVariableEnvironment>;
includeFileContent: Scalars['Boolean']['input'];
}>;
export type EnvironmentVariablesSharedQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, ownerAccount: { __typename?: 'Account', id: string, environmentVariables: Array<{ __typename?: 'EnvironmentVariable', id: string, linkedEnvironments?: Array<EnvironmentVariableEnvironment> | null, name: string, value?: string | null, environments?: Array<EnvironmentVariableEnvironment> | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null }> } } } };
export type EnvironmentVariablesSharedQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, ownerAccount: { __typename?: 'Account', id: string, environmentVariables: Array<{ __typename?: 'EnvironmentVariable', id: string, linkedEnvironments?: Array<EnvironmentVariableEnvironment> | null, name: string, value?: string | null, environments?: Array<EnvironmentVariableEnvironment> | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null, type: EnvironmentSecretType, valueWithFileContent?: string | null }> } } } };
export type EnvironmentVariablesSharedWithSensitiveQueryVariables = Exact<{
appId: Scalars['String']['input'];
filterNames?: InputMaybe<Array<Scalars['String']['input']> | Scalars['String']['input']>;
environment?: InputMaybe<EnvironmentVariableEnvironment>;
includeFileContent: Scalars['Boolean']['input'];
}>;
export type EnvironmentVariablesSharedWithSensitiveQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, ownerAccount: { __typename?: 'Account', id: string, environmentVariablesIncludingSensitive: Array<{ __typename?: 'EnvironmentVariableWithSecret', id: string, name: string, value?: string | null, environments?: Array<EnvironmentVariableEnvironment> | null }> } } } };
export type EnvironmentVariablesSharedWithSensitiveQuery = { __typename?: 'RootQuery', app: { __typename?: 'AppQuery', byId: { __typename?: 'App', id: string, ownerAccount: { __typename?: 'Account', id: string, environmentVariablesIncludingSensitive: Array<{ __typename?: 'EnvironmentVariableWithSecret', id: string, name: string, value?: string | null, environments?: Array<EnvironmentVariableEnvironment> | null, valueWithFileContent?: string | null }> } } } };
export type GoogleServiceAccountKeyByIdQueryVariables = Exact<{
ascApiKeyId: Scalars['ID']['input'];
@@ -8868,7 +9011,7 @@ export type BuildWithSubmissionsFragment = { __typename?: 'Build', id: string, s
export type EnvironmentSecretFragment = { __typename?: 'EnvironmentSecret', id: string, name: string, type: EnvironmentSecretType, createdAt: any };
export type EnvironmentVariableFragment = { __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environments?: Array<EnvironmentVariableEnvironment> | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null };
export type EnvironmentVariableFragment = { __typename?: 'EnvironmentVariable', id: string, name: string, value?: string | null, environments?: Array<EnvironmentVariableEnvironment> | null, createdAt: any, updatedAt: any, scope: EnvironmentVariableScope, visibility?: EnvironmentVariableVisibility | null, type: EnvironmentSecretType };
export type RuntimeFragment = { __typename?: 'Runtime', id: string, version: string };
@@ -29,7 +29,7 @@ type CreateVariableArgs = {
export type EnvironmentVariablePushInput = {
name: string;
value: string;
environment: string;
environments: EnvironmentVariableEnvironment[];
visibility: EnvironmentVariableVisibility;
overwrite?: boolean;
};
@@ -59,6 +59,7 @@ export const ChannelQuery = {
id
updateChannelByName(name: $channelName) {
id
isPaused
name
updatedAt
createdAt
@@ -104,6 +105,7 @@ export const ChannelQuery = {
id
updateChannels(offset: $offset, limit: $limit) {
id
isPaused
name
updatedAt
createdAt
@@ -11,11 +11,16 @@ import {
EnvironmentVariablesSharedQueryVariables,
} from '../generated';
import { EnvironmentVariableFragmentNode } from '../types/EnvironmentVariable';
import { EnvironmentVariableWithSecretFragmentNode } from '../types/EnvironmentVariableWithSecret';
type EnvironmentVariableWithLinkedEnvironments = EnvironmentVariableFragment & {
linkedEnvironments?: EnvironmentVariableEnvironment[] | null;
};
export type EnvironmentVariableWithFileContent = EnvironmentVariableFragment & {
valueWithFileContent?: string | null | undefined;
};
export const EnvironmentVariablesQuery = {
async byAppIdWithSensitiveAsync(
graphqlClient: ExpoGraphqlClient,
@@ -23,12 +28,14 @@ export const EnvironmentVariablesQuery = {
appId,
environment,
filterNames,
includeFileContent = false,
}: {
appId: string;
environment?: EnvironmentVariableEnvironment;
filterNames?: string[];
includeFileContent?: boolean;
}
): Promise<EnvironmentVariableFragment[]> {
): Promise<EnvironmentVariableWithFileContent[]> {
const data = await withErrorHandlingAsync(
graphqlClient
.query(
@@ -37,6 +44,7 @@ export const EnvironmentVariablesQuery = {
$appId: String!
$filterNames: [String!]
$environment: EnvironmentVariableEnvironment
$includeFileContent: Boolean!
) {
app {
byId(appId: $appId) {
@@ -46,15 +54,16 @@ export const EnvironmentVariablesQuery = {
environment: $environment
) {
id
name
value
environments
...EnvironmentVariableWithSecretFragment
valueWithFileContent: value(includeFileContent: $includeFileContent)
@include(if: $includeFileContent)
}
}
}
}
${print(EnvironmentVariableWithSecretFragmentNode)}
`,
{ appId, filterNames, environment },
{ appId, filterNames, environment, includeFileContent },
{ additionalTypenames: ['EnvironmentVariableWithSecret'] }
)
.toPromise()
@@ -68,12 +77,14 @@ export const EnvironmentVariablesQuery = {
appId,
environment,
filterNames,
includeFileContent = false,
}: {
appId: string;
environment?: EnvironmentVariableEnvironment;
filterNames?: string[];
includeFileContent?: boolean;
}
): Promise<EnvironmentVariableWithLinkedEnvironments[]> {
): Promise<(EnvironmentVariableWithFileContent & EnvironmentVariableWithLinkedEnvironments)[]> {
const data = await withErrorHandlingAsync(
graphqlClient
.query<EnvironmentVariablesByAppIdQuery>(
@@ -82,6 +93,7 @@ export const EnvironmentVariablesQuery = {
$appId: String!
$filterNames: [String!]
$environment: EnvironmentVariableEnvironment
$includeFileContent: Boolean!
) {
app {
byId(appId: $appId) {
@@ -90,13 +102,15 @@ export const EnvironmentVariablesQuery = {
id
linkedEnvironments(appId: $appId)
...EnvironmentVariableFragment
valueWithFileContent: value(includeFileContent: $includeFileContent)
@include(if: $includeFileContent)
}
}
}
}
${print(EnvironmentVariableFragmentNode)}
`,
{ appId, filterNames, environment },
{ appId, filterNames, environment, includeFileContent },
{ additionalTypenames: ['EnvironmentVariable'] }
)
.toPromise()
@@ -110,8 +124,14 @@ export const EnvironmentVariablesQuery = {
appId,
filterNames,
environment,
}: { appId: string; filterNames?: string[]; environment?: EnvironmentVariableEnvironment }
): Promise<EnvironmentVariableWithLinkedEnvironments[]> {
includeFileContent = false,
}: {
appId: string;
filterNames?: string[];
environment?: EnvironmentVariableEnvironment;
includeFileContent?: boolean;
}
): Promise<(EnvironmentVariableWithFileContent & EnvironmentVariableWithLinkedEnvironments)[]> {
const data = await withErrorHandlingAsync(
graphqlClient
.query<EnvironmentVariablesSharedQuery, EnvironmentVariablesSharedQueryVariables>(
@@ -120,6 +140,7 @@ export const EnvironmentVariablesQuery = {
$appId: String!
$filterNames: [String!]
$environment: EnvironmentVariableEnvironment
$includeFileContent: Boolean!
) {
app {
byId(appId: $appId) {
@@ -130,6 +151,8 @@ export const EnvironmentVariablesQuery = {
id
linkedEnvironments(appId: $appId)
...EnvironmentVariableFragment
valueWithFileContent: value(includeFileContent: $includeFileContent)
@include(if: $includeFileContent)
}
}
}
@@ -137,7 +160,7 @@ export const EnvironmentVariablesQuery = {
}
${print(EnvironmentVariableFragmentNode)}
`,
{ appId, filterNames, environment },
{ appId, filterNames, environment, includeFileContent },
{ additionalTypenames: ['EnvironmentVariable'] }
)
.toPromise()
@@ -151,8 +174,14 @@ export const EnvironmentVariablesQuery = {
appId,
filterNames,
environment,
}: { appId: string; filterNames?: string[]; environment?: EnvironmentVariableEnvironment }
): Promise<EnvironmentVariableFragment[]> {
includeFileContent = false,
}: {
appId: string;
filterNames?: string[];
environment?: EnvironmentVariableEnvironment;
includeFileContent?: boolean;
}
): Promise<EnvironmentVariableWithFileContent[]> {
const data = await withErrorHandlingAsync(
graphqlClient
.query(
@@ -161,6 +190,7 @@ export const EnvironmentVariablesQuery = {
$appId: String!
$filterNames: [String!]
$environment: EnvironmentVariableEnvironment
$includeFileContent: Boolean!
) {
app {
byId(appId: $appId) {
@@ -172,16 +202,17 @@ export const EnvironmentVariablesQuery = {
environment: $environment
) {
id
name
value
environments
...EnvironmentVariableWithSecretFragment
valueWithFileContent: value(includeFileContent: $includeFileContent)
@include(if: $includeFileContent)
}
}
}
}
}
${print(EnvironmentVariableWithSecretFragmentNode)}
`,
{ appId, filterNames, environment },
{ appId, filterNames, environment, includeFileContent },
{ additionalTypenames: ['EnvironmentVariableWithSecret'] }
)
.toPromise()
@@ -10,5 +10,6 @@ export const EnvironmentVariableFragmentNode = gql`
updatedAt
scope
visibility
type
}
`;
@@ -0,0 +1,15 @@
import gql from 'graphql-tag';
export const EnvironmentVariableWithSecretFragmentNode = gql`
fragment EnvironmentVariableWithSecretFragment on EnvironmentVariableWithSecret {
id
name
value
environments
createdAt
updatedAt
scope
visibility
type
}
`;
+1 -1
View File
@@ -1,4 +1,4 @@
import { ExpoConfig } from '@expo/config-types';
import { ExpoConfig } from '@expo/config';
import { SubmitProfile } from '@expo/eas-json';
import fs from 'fs-extra';
import path from 'path';
+1 -1
View File
@@ -1,4 +1,4 @@
import { ExpoConfig } from '@expo/config-types';
import { ExpoConfig } from '@expo/config';
import { SubmitProfile } from '@expo/eas-json';
import { AppleData } from './apple/data';
+3
View File
@@ -53,13 +53,16 @@ export async function selectAsync<T>(
choices: ExpoChoice<T>[],
config?: {
options?: Options;
initial?: T;
warningMessageForDisabledEntries?: string;
}
): Promise<T> {
const initial = config?.initial ? choices.findIndex(({ value }) => value === config.initial) : 0;
const { value } = await promptAsync(
{
message,
choices,
initial,
name: 'value',
type: 'select',
warn: config?.warningMessageForDisabledEntries,
+1 -1
View File
@@ -1,4 +1,4 @@
import { ExpoConfig } from '@expo/config-types';
import { ExpoConfig } from '@expo/config';
import { Env, Platform, Workflow } from '@expo/eas-build-job';
import { EasJsonAccessor } from '@expo/eas-json';
import chalk from 'chalk';
+1 -1
View File
@@ -1,4 +1,4 @@
import { ExpoConfig } from '@expo/config-types';
import { ExpoConfig } from '@expo/config';
import spawnAsync from '@expo/spawn-async';
import chalk from 'chalk';
import { boolish } from 'getenv';
+63 -13
View File
@@ -1,12 +1,51 @@
import chalk from 'chalk';
import capitalize from './expodash/capitalize';
import {
EnvironmentSecretType,
EnvironmentVariableEnvironment,
EnvironmentVariableVisibility,
} from '../graphql/generated';
import { promptAsync, selectAsync } from '../prompts';
export async function promptVariableTypeAsync(
nonInteractive: boolean,
initialType?: EnvironmentSecretType
): Promise<EnvironmentSecretType> {
if (nonInteractive) {
throw new Error('The `--type` flag must be set when running in `--non-interactive` mode.');
}
const options = [
{
title: 'String',
value: EnvironmentSecretType.String,
},
{
title: 'File',
value: EnvironmentSecretType.FileBase64,
},
];
return await selectAsync('Select the type of variable', options, {
initial: initialType,
});
}
export function parseVisibility(
stringVisibility: 'plaintext' | 'sensitive' | 'encrypted'
): EnvironmentVariableVisibility {
switch (stringVisibility) {
case 'plaintext':
return EnvironmentVariableVisibility.Public;
case 'sensitive':
return EnvironmentVariableVisibility.Sensitive;
case 'encrypted':
return EnvironmentVariableVisibility.Secret;
default:
throw new Error(`Invalid visibility: ${stringVisibility}`);
}
}
export async function promptVariableVisibilityAsync(
nonInteractive: boolean,
selectedVisibility?: EnvironmentVariableVisibility | null
@@ -16,14 +55,23 @@ export async function promptVariableVisibilityAsync(
'The `--visibility` flag must be set when running in `--non-interactive` mode.'
);
}
return await selectAsync(
'Select visibility:',
Object.values(EnvironmentVariableVisibility).map(visibility => ({
title: capitalize(visibility),
value: visibility,
selected: visibility === selectedVisibility,
}))
);
return await selectAsync('Select visibility:', [
{
title: 'Plain text',
value: EnvironmentVariableVisibility.Public,
selected: selectedVisibility === EnvironmentVariableVisibility.Public,
},
{
title: 'Sensitive',
value: EnvironmentVariableVisibility.Sensitive,
selected: selectedVisibility === EnvironmentVariableVisibility.Sensitive,
},
{
title: 'Encrypted',
value: EnvironmentVariableVisibility.Secret,
selected: selectedVisibility === EnvironmentVariableVisibility.Secret,
},
]);
}
type EnvironmentPromptArgs = {
@@ -56,7 +104,7 @@ export async function promptVariableEnvironmentAsync({
return await selectAsync(
'Select environment:',
(availableEnvironments ?? Object.values(EnvironmentVariableEnvironment)).map(environment => ({
title: environment,
title: environment.toLocaleLowerCase(),
value: environment,
}))
);
@@ -66,7 +114,7 @@ export async function promptVariableEnvironmentAsync({
name: 'environments',
type: 'multiselect',
choices: Object.values(EnvironmentVariableEnvironment).map(environment => ({
title: environment,
title: environment.toLocaleLowerCase(),
value: environment,
selected: selectedEnvironments?.includes(environment),
})),
@@ -78,11 +126,13 @@ export async function promptVariableValueAsync({
nonInteractive,
required = true,
hidden = false,
filePath = false,
initial,
}: {
nonInteractive: boolean;
required?: boolean;
initial?: string | null;
filePath?: boolean;
hidden?: boolean;
}): Promise<string> {
if (nonInteractive && required) {
@@ -94,9 +144,9 @@ export async function promptVariableValueAsync({
}
const { variableValue } = await promptAsync({
type: hidden ? 'password' : 'text',
type: hidden && !filePath ? 'password' : 'text',
name: 'variableValue',
message: 'Variable value:',
message: filePath ? 'File path:' : 'Variable value:',
initial: initial ?? '',
validate: variableValue => {
if (!required) {
+43 -3
View File
@@ -2,17 +2,48 @@ import dateFormat from 'dateformat';
import formatFields from './formatFields';
import {
EnvironmentSecretType,
EnvironmentVariableEnvironment,
EnvironmentVariableFragment,
EnvironmentVariableScope,
EnvironmentVariableVisibility,
} from '../graphql/generated';
import { EnvironmentVariableWithFileContent } from '../graphql/queries/EnvironmentVariablesQuery';
export function formatVariableName(variable: EnvironmentVariableFragment): string {
const name = variable.name;
const scope = variable.scope === EnvironmentVariableScope.Project ? 'project' : 'shared';
const environments = variable.environments?.join(', ') ?? '';
const updatedAt = variable.updatedAt ? new Date(variable.updatedAt).toLocaleString() : '';
return `${name} | ${scope} | ${environments} | Updated at: ${updatedAt}`;
const type = variable.type === EnvironmentSecretType.FileBase64 ? 'file' : 'string';
const visibility = variable.visibility;
return `${name} | ${scope} | ${type} | ${visibility} | ${environments} | Updated at: ${updatedAt}`;
}
export function formatVariableValue(variable: EnvironmentVariableWithFileContent): string {
// TODO: Add Learn more link
if (variable.value) {
return variable.value;
}
if (variable.valueWithFileContent) {
return atob(variable.valueWithFileContent);
}
if (variable.visibility === EnvironmentVariableVisibility.Sensitive) {
return '***** (This is a sensitive env variable. To access it, run command with --include-sensitive flag. Learn more.)';
}
if (variable.visibility === EnvironmentVariableVisibility.Secret) {
return "***** (This is a secret env variable that can only be accessed on EAS builder and can't be read in any UI. Learn more.)";
}
if (variable.type === EnvironmentSecretType.FileBase64) {
return '***** (This is a file env variable. To access it, run command with --include-file-content flag. Learn more.)';
}
return '*****';
}
export async function performForEnvironmentsAsync(
@@ -23,12 +54,21 @@ export async function performForEnvironmentsAsync(
return await Promise.all(selectedEnvironments.map(env => fun(env)));
}
export function formatVariable(variable: EnvironmentVariableFragment): string {
export function formatVariable(variable: EnvironmentVariableWithFileContent): string {
return formatFields([
{ label: 'ID', value: variable.id },
{ label: 'Name', value: variable.name },
{ label: 'Value', value: variable.value ?? '(secret)' },
{ label: 'Value', value: formatVariableValue(variable) },
{ label: 'Scope', value: variable.scope },
{ label: 'Visibility', value: variable.visibility ?? '' },
{
label: 'Environments',
value: variable.environments ? variable.environments.join(', ') : '-',
},
{
label: 'type',
value: variable.type === EnvironmentSecretType.FileBase64 ? 'file' : 'string',
},
{ label: 'Created at', value: dateFormat(variable.createdAt, 'mmm dd HH:MM:ss') },
{ label: 'Updated at', value: dateFormat(variable.updatedAt, 'mmm dd HH:MM:ss') },
]);
Generated
+8 -33
View File
@@ -1359,10 +1359,10 @@
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.56.0.tgz#ef20350fec605a7f7035a01764731b2de0f3782b"
integrity sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==
"@expo/apple-utils@1.8.0":
version "1.8.0"
resolved "https://registry.yarnpkg.com/@expo/apple-utils/-/apple-utils-1.8.0.tgz#8a359cefbad000be66caa18235ecd4c03406a15d"
integrity sha512-JKGfPCCGko7GtLcvCj9VeyrSJGimgWsBJnR4G10kGY9sUQo3ykEgVrUBUaG2HJrCLzbeDUExmsbuZRWqJha77g==
"@expo/apple-utils@2.0.2":
version "2.0.2"
resolved "https://registry.yarnpkg.com/@expo/apple-utils/-/apple-utils-2.0.2.tgz#1e765aa334485b2cd28d4476bedded0c4d812b71"
integrity sha512-KIfzTYgk81YeXCwPVfR2lWdMZBMS2gUt5BXXV1sgDl7BbmjPlRbixL7kaieegwimPmXG2y3+Tth2lqWjuip3oQ==
"@expo/bunyan@^4.0.0":
version "4.0.0"
@@ -1428,7 +1428,7 @@
xcode "^3.0.1"
xml2js "0.6.0"
"@expo/[email protected]", "@expo/config-types@^50.0.0", "@expo/config-types@^50.0.0-alpha.1":
"@expo/config-types@^50.0.0", "@expo/config-types@^50.0.0-alpha.1":
version "50.0.0"
resolved "https://registry.yarnpkg.com/@expo/config-types/-/config-types-50.0.0.tgz#b534d3ec997ec60f8af24f6ad56244c8afc71a0b"
integrity sha512-0kkhIwXRT6EdFDwn+zTg9R2MZIAEYGn1MVkyRohAd+C9cXOb5RA8WLQi7vuxKF9m1SMtNAUrf0pO+ENK0+/KSw==
@@ -13186,16 +13186,7 @@ string-length@^5.0.1:
char-regex "^2.0.0"
strip-ansi "^7.0.1"
"string-width-cjs@npm:string-width@^4.2.0":
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.2.3:
"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -13351,7 +13342,7 @@ string_decoder@~1.1.1:
dependencies:
safe-buffer "~5.1.0"
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -13365,13 +13356,6 @@ strip-ansi@^6.0.0:
dependencies:
ansi-regex "^5.0.0"
strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"
strip-ansi@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2"
@@ -14604,16 +14588,7 @@ wordwrap@^1.0.0:
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
dependencies:
ansi-styles "^4.0.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"
[email protected], wrap-ansi@^7.0.0:
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", [email protected], wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==