mirror of
https://github.com/expo/eas-cli.git
synced 2026-11-14 17:50:32 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dd85d559d7 | ||
|
|
ab10b082e5 | ||
|
|
60b60066f9 | ||
|
|
9e9e517698 | ||
|
|
020c0f2b98 | ||
|
|
dd74ebdc51 | ||
|
|
ddf7381efb | ||
|
|
3b67b912e4 | ||
|
|
37d7fa4510 | ||
|
|
096601473a | ||
|
|
2e25ed81ca | ||
|
|
4e11ea1d77 | ||
|
|
d9d470426b | ||
|
|
119b4ad8b2 | ||
|
|
ae1e9f000d | ||
|
|
eb0505f8f8 | ||
|
|
c8f7800ab5 | ||
|
|
bc4e7becdd | ||
|
|
71ece19c40 | ||
|
|
e9053c0d15 | ||
|
|
cf76296142 | ||
|
|
5e5d3626f4 | ||
|
|
5808c5b412 | ||
|
|
cd64392d44 | ||
|
|
79f889e16c | ||
|
|
595bfecf1c |
No files matched your search
@@ -0,0 +1,58 @@
|
||||
# Changelog
|
||||
|
||||
This is the log of notable changes to EAS CLI and related packages.
|
||||
|
||||
## main
|
||||
|
||||
### 🛠 Breaking changes
|
||||
|
||||
### 🎉 New features
|
||||
|
||||
- Add support for build cache. ([#247](https://github.com/expo/eas-cli/pull/247) by [@wkozyra95](https://github.com/wkozyra95))
|
||||
- Enable internal distribution support for self-managed credentials. ([#256](https://github.com/expo/eas-cli/pull/256) by [@dsokal](https://github.com/dsokal))
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
- Make sure all files are committed before build. ([#251](https://github.com/expo/eas-cli/pull/251) by [@wkozyra95](https://github.com/wkozyra95))
|
||||
- Fix `eas submit` support for tar.gz files. ([#257](https://github.com/expo/eas-cli/pull/257)) by [@wkozyra95](https://github.com/wkozyra95))
|
||||
- Show untracked files when checking `git status`. ([#259](https://github.com/expo/eas-cli/pull/259) by [@wkozyra95](https://github.com/wkozyra95))
|
||||
|
||||
### 🧹 Chores
|
||||
|
||||
- Upgrade `@expo/eas-build-job` from `0.2.12` to `0.2.13`. ([#245](https://github.com/expo/eas-cli/pull/245) by [@dsokal](https://github.com/dsokal))
|
||||
|
||||
## [0.4.3](https://github.com/expo/eas-cli/releases/tag/v0.4.3) - 2021-02-23
|
||||
|
||||
### 🎉 New features
|
||||
|
||||
- Add support for iOS simulator builds. ([#240](https://github.com/expo/eas-cli/pull/240) by [@dsokal](https://github.com/dsokal))
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
- Use fixed version of `@expo/eas-json`. ([#243](https://github.com/expo/eas-cli/pull/243) by [@wkozyra95](https://github.com/wkozyra95))
|
||||
|
||||
## [0.4.2](https://github.com/expo/eas-cli/releases/tag/v0.4.2) - 2021-02-18
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
- Fix detecting application target (iOS builds). ([#238](https://github.com/expo/eas-cli/pull/238) by [@dsokal](https://github.com/dsokal))
|
||||
|
||||
## [0.4.1](https://github.com/expo/eas-cli/releases/tag/v0.4.1) - 2021-02-16
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
- Fix `"buildType" is not allowed` error. ([#595bf](https://github.com/expo/eas-cli/commit/595bfecf1cbff0f76e7fd2049fe16f6f38bbe150) by [@wkozyra95](https://github.com/wkozyra95))
|
||||
|
||||
## [0.4.0](https://github.com/expo/eas-cli/releases/tag/v0.4.0) - 2021-02-16
|
||||
|
||||
### 🎉 New features
|
||||
|
||||
- Add build:cancel command. ([#219](https://github.com/expo/eas-cli/pull/219) by [@wkozyra95](https://github.com/wkozyra95))
|
||||
- Implement version auto increment for iOS builds. ([#231](https://github.com/expo/eas-cli/pull/231) by [@dsokal](https://github.com/dsokal))
|
||||
- Add support for builder environment customizations. ([#230](https://github.com/expo/eas-cli/pull/230) by [@wkozyra95](https://github.com/wkozyra95))
|
||||
- Add `schemeBuildConfiguration` option for generic iOS builds. ([#234](https://github.com/expo/eas-cli/pull/234) by [@dsokal](https://github.com/dsokal))
|
||||
|
||||
### 🐛 Bug fixes
|
||||
|
||||
- Fix `--no-wait` flag for `eas build`. ([#226](https://github.com/expo/eas-cli/pull/226) by [@paul-ridgway](https://github.com/paul-ridgway))
|
||||
- Fix running builds from project subdirectories. ([#229](https://github.com/expo/eas-cli/pull/229) by [@wkozyra95](https://github.com/wkozyra95))
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true,
|
||||
"version": "0.4.0"
|
||||
"version": "0.5.0"
|
||||
}
|
||||
+14
-14
@@ -21,7 +21,7 @@ $ npm install -g eas-cli
|
||||
$ eas COMMAND
|
||||
running command...
|
||||
$ eas (-v|--version|version)
|
||||
eas-cli/0.4.0 darwin-x64 node-v14.15.4
|
||||
eas-cli/0.5.0 darwin-x64 node-v14.15.4
|
||||
$ eas --help [COMMAND]
|
||||
USAGE
|
||||
$ eas COMMAND
|
||||
@@ -59,7 +59,7 @@ ALIASES
|
||||
$ eas login
|
||||
```
|
||||
|
||||
_See code: [build/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v0.4.0/build/commands/account/login.ts)_
|
||||
_See code: [build/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v0.5.0/build/commands/account/login.ts)_
|
||||
|
||||
## `eas account:logout`
|
||||
|
||||
@@ -73,7 +73,7 @@ ALIASES
|
||||
$ eas logout
|
||||
```
|
||||
|
||||
_See code: [build/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v0.4.0/build/commands/account/logout.ts)_
|
||||
_See code: [build/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v0.5.0/build/commands/account/logout.ts)_
|
||||
|
||||
## `eas account:view`
|
||||
|
||||
@@ -87,7 +87,7 @@ ALIASES
|
||||
$ eas whoami
|
||||
```
|
||||
|
||||
_See code: [build/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v0.4.0/build/commands/account/view.ts)_
|
||||
_See code: [build/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v0.5.0/build/commands/account/view.ts)_
|
||||
|
||||
## `eas build`
|
||||
|
||||
@@ -106,7 +106,7 @@ OPTIONS
|
||||
--[no-]wait Wait for build(s) to complete
|
||||
```
|
||||
|
||||
_See code: [build/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v0.4.0/build/commands/build/index.ts)_
|
||||
_See code: [build/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v0.5.0/build/commands/build/index.ts)_
|
||||
|
||||
## `eas build:cancel [BUILD_ID]`
|
||||
|
||||
@@ -117,7 +117,7 @@ USAGE
|
||||
$ eas build:cancel [BUILD_ID]
|
||||
```
|
||||
|
||||
_See code: [build/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v0.4.0/build/commands/build/cancel.ts)_
|
||||
_See code: [build/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v0.5.0/build/commands/build/cancel.ts)_
|
||||
|
||||
## `eas build:configure`
|
||||
|
||||
@@ -132,7 +132,7 @@ OPTIONS
|
||||
--allow-experimental Enable experimental configuration steps.
|
||||
```
|
||||
|
||||
_See code: [build/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v0.4.0/build/commands/build/configure.ts)_
|
||||
_See code: [build/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v0.5.0/build/commands/build/configure.ts)_
|
||||
|
||||
## `eas build:list`
|
||||
|
||||
@@ -148,7 +148,7 @@ OPTIONS
|
||||
--status=(in-queue|in-progress|errored|finished|canceled)
|
||||
```
|
||||
|
||||
_See code: [build/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v0.4.0/build/commands/build/list.ts)_
|
||||
_See code: [build/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v0.5.0/build/commands/build/list.ts)_
|
||||
|
||||
## `eas build:view [BUILD_ID]`
|
||||
|
||||
@@ -159,7 +159,7 @@ USAGE
|
||||
$ eas build:view [BUILD_ID]
|
||||
```
|
||||
|
||||
_See code: [build/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v0.4.0/build/commands/build/view.ts)_
|
||||
_See code: [build/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v0.5.0/build/commands/build/view.ts)_
|
||||
|
||||
## `eas credentials`
|
||||
|
||||
@@ -170,7 +170,7 @@ USAGE
|
||||
$ eas credentials
|
||||
```
|
||||
|
||||
_See code: [build/commands/credentials.ts](https://github.com/expo/eas-cli/blob/v0.4.0/build/commands/credentials.ts)_
|
||||
_See code: [build/commands/credentials.ts](https://github.com/expo/eas-cli/blob/v0.5.0/build/commands/credentials.ts)_
|
||||
|
||||
## `eas device:create`
|
||||
|
||||
@@ -181,7 +181,7 @@ USAGE
|
||||
$ eas device:create
|
||||
```
|
||||
|
||||
_See code: [build/commands/device/create.ts](https://github.com/expo/eas-cli/blob/v0.4.0/build/commands/device/create.ts)_
|
||||
_See code: [build/commands/device/create.ts](https://github.com/expo/eas-cli/blob/v0.5.0/build/commands/device/create.ts)_
|
||||
|
||||
## `eas device:list`
|
||||
|
||||
@@ -195,7 +195,7 @@ OPTIONS
|
||||
--apple-team-id=apple-team-id
|
||||
```
|
||||
|
||||
_See code: [build/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v0.4.0/build/commands/device/list.ts)_
|
||||
_See code: [build/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v0.5.0/build/commands/device/list.ts)_
|
||||
|
||||
## `eas device:view [UDID]`
|
||||
|
||||
@@ -206,7 +206,7 @@ USAGE
|
||||
$ eas device:view [UDID]
|
||||
```
|
||||
|
||||
_See code: [build/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v0.4.0/build/commands/device/view.ts)_
|
||||
_See code: [build/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v0.5.0/build/commands/device/view.ts)_
|
||||
|
||||
## `eas help [COMMAND]`
|
||||
|
||||
@@ -303,5 +303,5 @@ EXAMPLES
|
||||
and provide its App ID
|
||||
```
|
||||
|
||||
_See code: [build/commands/submit.ts](https://github.com/expo/eas-cli/blob/v0.4.0/build/commands/submit.ts)_
|
||||
_See code: [build/commands/submit.ts](https://github.com/expo/eas-cli/blob/v0.5.0/build/commands/submit.ts)_
|
||||
<!-- commandsstop -->
|
||||
@@ -1378,6 +1378,49 @@
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "environmentSecrets",
|
||||
"description": "Environment secrets for an account",
|
||||
"args": [
|
||||
{
|
||||
"name": "filterNames",
|
||||
"description": null,
|
||||
"type": {
|
||||
"kind": "LIST",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultValue": null
|
||||
}
|
||||
],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "LIST",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "OBJECT",
|
||||
"name": "EnvironmentSecret",
|
||||
"ofType": null
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"inputFields": null,
|
||||
@@ -2682,11 +2725,11 @@
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "updateChannelByChannelName",
|
||||
"description": "get an EAS channel owned by the app by channelName",
|
||||
"name": "updateChannelByName",
|
||||
"description": "get an EAS channel owned by the app by name",
|
||||
"args": [
|
||||
{
|
||||
"name": "channelName",
|
||||
"name": "name",
|
||||
"description": null,
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
@@ -2766,11 +2809,11 @@
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "updateBranchByBranchName",
|
||||
"description": "get an EAS branch owned by the app by branchName",
|
||||
"name": "updateBranchByName",
|
||||
"description": "get an EAS branch owned by the app by name",
|
||||
"args": [
|
||||
{
|
||||
"name": "branchName",
|
||||
"name": "name",
|
||||
"description": null,
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
@@ -2844,6 +2887,49 @@
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "environmentSecrets",
|
||||
"description": "Environment secrets for an app",
|
||||
"args": [
|
||||
{
|
||||
"name": "filterNames",
|
||||
"description": null,
|
||||
"type": {
|
||||
"kind": "LIST",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultValue": null
|
||||
}
|
||||
],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "LIST",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "OBJECT",
|
||||
"name": "EnvironmentSecret",
|
||||
"ofType": null
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"inputFields": null,
|
||||
@@ -4830,6 +4916,12 @@
|
||||
"description": "",
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "SIMULATOR",
|
||||
"description": "",
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"possibleTypes": null
|
||||
@@ -7299,7 +7391,7 @@
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "channelName",
|
||||
"name": "name",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": {
|
||||
@@ -7459,7 +7551,7 @@
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "branchName",
|
||||
"name": "name",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": {
|
||||
@@ -7679,7 +7771,7 @@
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "updateGroup",
|
||||
"name": "group",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": {
|
||||
@@ -7727,7 +7819,7 @@
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "updateMessage",
|
||||
"name": "message",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": {
|
||||
@@ -7739,15 +7831,15 @@
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "branchName",
|
||||
"name": "branch",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"kind": "OBJECT",
|
||||
"name": "UpdateBranch",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
@@ -7766,6 +7858,81 @@
|
||||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "EnvironmentSecret",
|
||||
"description": "",
|
||||
"fields": [
|
||||
{
|
||||
"name": "id",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "ID",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "name",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "createdAt",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "DateTime",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "updatedAt",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "DateTime",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"inputFields": null,
|
||||
"interfaces": [],
|
||||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "UserPermission",
|
||||
@@ -10327,6 +10494,22 @@
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "environmentSecret",
|
||||
"description": "Mutations that create and delete EnvironmentSecrets",
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "OBJECT",
|
||||
"name": "EnvironmentSecretMutation",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"inputFields": null,
|
||||
@@ -13919,7 +14102,7 @@
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "channelName",
|
||||
"name": "name",
|
||||
"description": null,
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
@@ -14149,7 +14332,7 @@
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "branchName",
|
||||
"name": "name",
|
||||
"description": null,
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
@@ -14173,7 +14356,7 @@
|
||||
},
|
||||
{
|
||||
"name": "editUpdateBranch",
|
||||
"description": "Edit an EAS branch. The branch can be specified either by its ID or\nwith the combination of (appId, branchName).",
|
||||
"description": "Edit an EAS branch. The branch can be specified either by its ID or\nwith the combination of (appId, name).",
|
||||
"args": [
|
||||
{
|
||||
"name": "input",
|
||||
@@ -14297,7 +14480,7 @@
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "branchName",
|
||||
"name": "name",
|
||||
"description": "",
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
@@ -14307,7 +14490,7 @@
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "newBranchName",
|
||||
"name": "newName",
|
||||
"description": "",
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
@@ -14401,7 +14584,7 @@
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "updateMessage",
|
||||
"name": "message",
|
||||
"description": "",
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
@@ -14506,7 +14689,7 @@
|
||||
"fields": null,
|
||||
"inputFields": [
|
||||
{
|
||||
"name": "fileHash",
|
||||
"name": "fileSHA256",
|
||||
"description": "",
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
@@ -16144,6 +16327,196 @@
|
||||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "EnvironmentSecretMutation",
|
||||
"description": "",
|
||||
"fields": [
|
||||
{
|
||||
"name": "createEnvironmentSecretForAccount",
|
||||
"description": "Create an environment secret for an Account",
|
||||
"args": [
|
||||
{
|
||||
"name": "environmentSecretData",
|
||||
"description": null,
|
||||
"type": {
|
||||
"kind": "INPUT_OBJECT",
|
||||
"name": "CreateEnvironmentSecretInput",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "accountId",
|
||||
"description": null,
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"defaultValue": null
|
||||
}
|
||||
],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "OBJECT",
|
||||
"name": "EnvironmentSecret",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "createEnvironmentSecretForApp",
|
||||
"description": "Create an environment secret for an App",
|
||||
"args": [
|
||||
{
|
||||
"name": "environmentSecretData",
|
||||
"description": null,
|
||||
"type": {
|
||||
"kind": "INPUT_OBJECT",
|
||||
"name": "CreateEnvironmentSecretInput",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "appId",
|
||||
"description": null,
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"defaultValue": null
|
||||
}
|
||||
],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "OBJECT",
|
||||
"name": "EnvironmentSecret",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "deleteEnvironmentSecret",
|
||||
"description": "Delete an environment secret",
|
||||
"args": [
|
||||
{
|
||||
"name": "id",
|
||||
"description": null,
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"defaultValue": null
|
||||
}
|
||||
],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "OBJECT",
|
||||
"name": "DeleteEnvironmentSecretResult",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"inputFields": null,
|
||||
"interfaces": [],
|
||||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "INPUT_OBJECT",
|
||||
"name": "CreateEnvironmentSecretInput",
|
||||
"description": "",
|
||||
"fields": null,
|
||||
"inputFields": [
|
||||
{
|
||||
"name": "name",
|
||||
"description": "",
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "value",
|
||||
"description": "",
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"defaultValue": null
|
||||
}
|
||||
],
|
||||
"interfaces": null,
|
||||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "DeleteEnvironmentSecretResult",
|
||||
"description": "",
|
||||
"fields": [
|
||||
{
|
||||
"name": "id",
|
||||
"description": "",
|
||||
"args": [],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "ID",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"inputFields": null,
|
||||
"interfaces": [],
|
||||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "BaseSearchResult",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "eas-cli",
|
||||
"description": "EAS command line tool",
|
||||
"version": "0.4.0",
|
||||
"version": "0.5.0",
|
||||
"author": "Expo <[email protected]>",
|
||||
"bin": {
|
||||
"eas": "./bin/run"
|
||||
@@ -10,9 +10,9 @@
|
||||
"dependencies": {
|
||||
"@expo/apple-utils": "0.0.0-alpha.17",
|
||||
"@expo/config": "~3.3.19",
|
||||
"@expo/config-plugins": "1.0.18",
|
||||
"@expo/eas-build-job": "0.2.10",
|
||||
"@expo/eas-json": "^0.4.0",
|
||||
"@expo/config-plugins": "1.0.19-alpha.0",
|
||||
"@expo/eas-build-job": "0.2.14",
|
||||
"@expo/eas-json": "^0.5.0",
|
||||
"@expo/json-file": "^8.2.24",
|
||||
"@expo/plist": "^0.0.11",
|
||||
"@expo/plugin-warn-if-update-available": "^1.7.0",
|
||||
|
||||
@@ -48,7 +48,7 @@ describe(ensureCredentialsAsync, () => {
|
||||
});
|
||||
const src = await ensureCredentialsAsync(
|
||||
provider,
|
||||
Workflow.Generic,
|
||||
Workflow.GENERIC,
|
||||
CredentialsSource.AUTO,
|
||||
false
|
||||
);
|
||||
@@ -61,7 +61,7 @@ describe(ensureCredentialsAsync, () => {
|
||||
});
|
||||
const src = await ensureCredentialsAsync(
|
||||
provider,
|
||||
Workflow.Generic,
|
||||
Workflow.GENERIC,
|
||||
CredentialsSource.AUTO,
|
||||
false
|
||||
);
|
||||
@@ -75,7 +75,7 @@ describe(ensureCredentialsAsync, () => {
|
||||
});
|
||||
const src = await ensureCredentialsAsync(
|
||||
provider,
|
||||
Workflow.Generic,
|
||||
Workflow.GENERIC,
|
||||
CredentialsSource.AUTO,
|
||||
false
|
||||
);
|
||||
@@ -93,7 +93,7 @@ describe(ensureCredentialsAsync, () => {
|
||||
});
|
||||
const src = await ensureCredentialsAsync(
|
||||
provider,
|
||||
Workflow.Generic,
|
||||
Workflow.GENERIC,
|
||||
CredentialsSource.AUTO,
|
||||
false
|
||||
);
|
||||
@@ -111,7 +111,7 @@ describe(ensureCredentialsAsync, () => {
|
||||
});
|
||||
const src = await ensureCredentialsAsync(
|
||||
provider,
|
||||
Workflow.Generic,
|
||||
Workflow.GENERIC,
|
||||
CredentialsSource.AUTO,
|
||||
false
|
||||
);
|
||||
@@ -126,7 +126,7 @@ describe(ensureCredentialsAsync, () => {
|
||||
});
|
||||
|
||||
try {
|
||||
await ensureCredentialsAsync(provider, Workflow.Generic, CredentialsSource.AUTO, true);
|
||||
await ensureCredentialsAsync(provider, Workflow.GENERIC, CredentialsSource.AUTO, true);
|
||||
throw new Error('ensureCredentialsAsync should throw an Error');
|
||||
} catch (e) {
|
||||
expect(e.message).toMatch(
|
||||
@@ -147,7 +147,7 @@ describe(ensureCredentialsAsync, () => {
|
||||
});
|
||||
const src = await ensureCredentialsAsync(
|
||||
provider,
|
||||
Workflow.Generic,
|
||||
Workflow.GENERIC,
|
||||
CredentialsSource.AUTO,
|
||||
false
|
||||
);
|
||||
@@ -165,7 +165,7 @@ describe(ensureCredentialsAsync, () => {
|
||||
});
|
||||
|
||||
try {
|
||||
await ensureCredentialsAsync(provider, Workflow.Generic, CredentialsSource.AUTO, false);
|
||||
await ensureCredentialsAsync(provider, Workflow.GENERIC, CredentialsSource.AUTO, false);
|
||||
throw new Error('ensureCredentialsAsync should throw an Error');
|
||||
} catch (e) {
|
||||
expect(e.message).toMatch(
|
||||
@@ -186,7 +186,7 @@ describe(ensureCredentialsAsync, () => {
|
||||
});
|
||||
|
||||
try {
|
||||
await ensureCredentialsAsync(provider, Workflow.Generic, CredentialsSource.AUTO, true);
|
||||
await ensureCredentialsAsync(provider, Workflow.GENERIC, CredentialsSource.AUTO, true);
|
||||
throw new Error('ensureCredentialsAsync should throw an Error');
|
||||
} catch (e) {
|
||||
expect(e.message).toMatch('Credentials for this app are not configured');
|
||||
@@ -204,7 +204,7 @@ describe(ensureCredentialsAsync, () => {
|
||||
});
|
||||
const src = await ensureCredentialsAsync(
|
||||
provider,
|
||||
Workflow.Managed,
|
||||
Workflow.MANAGED,
|
||||
CredentialsSource.AUTO,
|
||||
false
|
||||
);
|
||||
@@ -217,7 +217,7 @@ describe(ensureCredentialsAsync, () => {
|
||||
});
|
||||
const src = await ensureCredentialsAsync(
|
||||
provider,
|
||||
Workflow.Managed,
|
||||
Workflow.MANAGED,
|
||||
CredentialsSource.AUTO,
|
||||
false
|
||||
);
|
||||
@@ -231,7 +231,7 @@ describe(ensureCredentialsAsync, () => {
|
||||
});
|
||||
const src = await ensureCredentialsAsync(
|
||||
provider,
|
||||
Workflow.Managed,
|
||||
Workflow.MANAGED,
|
||||
CredentialsSource.AUTO,
|
||||
false
|
||||
);
|
||||
@@ -247,7 +247,7 @@ describe(ensureCredentialsAsync, () => {
|
||||
});
|
||||
const src = await ensureCredentialsAsync(
|
||||
provider,
|
||||
Workflow.Managed,
|
||||
Workflow.MANAGED,
|
||||
CredentialsSource.AUTO,
|
||||
false
|
||||
);
|
||||
@@ -265,7 +265,7 @@ describe(ensureCredentialsAsync, () => {
|
||||
});
|
||||
const src = await ensureCredentialsAsync(
|
||||
provider,
|
||||
Workflow.Generic,
|
||||
Workflow.GENERIC,
|
||||
CredentialsSource.LOCAL,
|
||||
false
|
||||
);
|
||||
@@ -283,7 +283,7 @@ describe(ensureCredentialsAsync, () => {
|
||||
});
|
||||
const src = await ensureCredentialsAsync(
|
||||
provider,
|
||||
Workflow.Generic,
|
||||
Workflow.GENERIC,
|
||||
CredentialsSource.REMOTE,
|
||||
false
|
||||
);
|
||||
|
||||
@@ -25,7 +25,7 @@ function isApplicationIdValid(applicationId: string): boolean {
|
||||
}
|
||||
|
||||
export async function ensureApplicationIdIsValidAsync(projectDir: string) {
|
||||
const applicationId = await ensureAppIdentifierIsDefinedAsync(projectDir, Platform.Android);
|
||||
const applicationId = await ensureAppIdentifierIsDefinedAsync(projectDir, Platform.ANDROID);
|
||||
if (!isApplicationIdValid(applicationId)) {
|
||||
const configDescription = getProjectConfigDescription(projectDir);
|
||||
Log.error(
|
||||
|
||||
@@ -22,15 +22,15 @@ export async function prepareAndroidBuildAsync(
|
||||
commandCtx: CommandContext,
|
||||
easConfig: EasConfig
|
||||
): Promise<() => Promise<string>> {
|
||||
const buildCtx = createBuildContext<Platform.Android>({
|
||||
const buildCtx = createBuildContext<Platform.ANDROID>({
|
||||
commandCtx,
|
||||
platform: Platform.Android,
|
||||
platform: Platform.ANDROID,
|
||||
easConfig,
|
||||
});
|
||||
const { buildProfile } = buildCtx;
|
||||
|
||||
if (
|
||||
buildProfile.workflow === Workflow.Generic &&
|
||||
buildProfile.workflow === Workflow.GENERIC &&
|
||||
!(await fs.pathExists(path.join(commandCtx.projectDir, 'android')))
|
||||
) {
|
||||
throw new Error(
|
||||
@@ -41,7 +41,7 @@ export async function prepareAndroidBuildAsync(
|
||||
}
|
||||
|
||||
if (
|
||||
buildProfile.workflow === Workflow.Generic &&
|
||||
buildProfile.workflow === Workflow.GENERIC &&
|
||||
buildProfile.distribution === 'internal' &&
|
||||
buildProfile.gradleCommand?.match(/bundle/)
|
||||
) {
|
||||
@@ -67,7 +67,7 @@ This means that it will most likely produce an AAB and you will not be able to i
|
||||
projectConfiguration: {},
|
||||
ensureCredentialsAsync: ensureAndroidCredentialsAsync,
|
||||
ensureProjectConfiguredAsync: async () => {
|
||||
if (buildCtx.buildProfile.workflow === Workflow.Generic) {
|
||||
if (buildCtx.buildProfile.workflow === Workflow.GENERIC) {
|
||||
await validateAndSyncProjectConfigurationAsync(commandCtx.projectDir, commandCtx.exp);
|
||||
}
|
||||
},
|
||||
@@ -75,15 +75,15 @@ This means that it will most likely produce an AAB and you will not be able to i
|
||||
});
|
||||
}
|
||||
|
||||
function shouldProvideCredentials(ctx: BuildContext<Platform.Android>): boolean {
|
||||
function shouldProvideCredentials(ctx: BuildContext<Platform.ANDROID>): boolean {
|
||||
return (
|
||||
ctx.buildProfile.workflow === Workflow.Managed ||
|
||||
(ctx.buildProfile.workflow === Workflow.Generic && !ctx.buildProfile.withoutCredentials)
|
||||
ctx.buildProfile.workflow === Workflow.MANAGED ||
|
||||
(ctx.buildProfile.workflow === Workflow.GENERIC && !ctx.buildProfile.withoutCredentials)
|
||||
);
|
||||
}
|
||||
|
||||
async function ensureAndroidCredentialsAsync(
|
||||
ctx: BuildContext<Platform.Android>
|
||||
ctx: BuildContext<Platform.ANDROID>
|
||||
): Promise<CredentialsResult<AndroidCredentials> | undefined> {
|
||||
if (!shouldProvideCredentials(ctx)) {
|
||||
return;
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
Android,
|
||||
ArchiveSource,
|
||||
ArchiveSourceType,
|
||||
Cache,
|
||||
Job,
|
||||
Workflow,
|
||||
sanitizeJob,
|
||||
@@ -22,13 +23,13 @@ interface JobData {
|
||||
}
|
||||
|
||||
export async function prepareJobAsync(
|
||||
ctx: BuildContext<Platform.Android>,
|
||||
ctx: BuildContext<Platform.ANDROID>,
|
||||
jobData: JobData
|
||||
): Promise<Job> {
|
||||
if (ctx.buildProfile.workflow === Workflow.Generic) {
|
||||
if (ctx.buildProfile.workflow === Workflow.GENERIC) {
|
||||
const partialJob = await prepareGenericJobAsync(ctx, jobData, ctx.buildProfile);
|
||||
return sanitizeJob(partialJob);
|
||||
} else if (ctx.buildProfile.workflow === Workflow.Managed) {
|
||||
} else if (ctx.buildProfile.workflow === Workflow.MANAGED) {
|
||||
const partialJob = await prepareManagedJobAsync(ctx, jobData, ctx.buildProfile);
|
||||
return sanitizeJob(partialJob);
|
||||
} else {
|
||||
@@ -37,9 +38,10 @@ export async function prepareJobAsync(
|
||||
}
|
||||
|
||||
interface CommonJobProperties {
|
||||
platform: Platform.Android;
|
||||
platform: Platform.ANDROID;
|
||||
projectArchive: ArchiveSource;
|
||||
builderEnvironment: Android.BuilderEnvironment;
|
||||
cache: Cache | null;
|
||||
secrets: {
|
||||
buildCredentials?: {
|
||||
keystore: Android.Keystore;
|
||||
@@ -49,7 +51,7 @@ interface CommonJobProperties {
|
||||
}
|
||||
|
||||
async function prepareJobCommonAsync(
|
||||
ctx: BuildContext<Platform.Android>,
|
||||
ctx: BuildContext<Platform.ANDROID>,
|
||||
jobData: JobData
|
||||
): Promise<Partial<CommonJobProperties>> {
|
||||
const secretEnvs = await readSecretEnvsAsync(ctx.commandCtx.projectDir);
|
||||
@@ -68,7 +70,7 @@ async function prepareJobCommonAsync(
|
||||
: {};
|
||||
|
||||
return {
|
||||
platform: Platform.Android,
|
||||
platform: Platform.ANDROID,
|
||||
projectArchive: {
|
||||
type: ArchiveSourceType.S3,
|
||||
bucketKey: jobData.archiveBucketKey,
|
||||
@@ -80,6 +82,7 @@ async function prepareJobCommonAsync(
|
||||
ndk: ctx.buildProfile.ndk,
|
||||
env: ctx.buildProfile.env,
|
||||
},
|
||||
cache: ctx.buildProfile.cache,
|
||||
secrets: {
|
||||
...(secretEnvs ? { secretEnvs } : {}),
|
||||
...buildCredentials,
|
||||
@@ -88,7 +91,7 @@ async function prepareJobCommonAsync(
|
||||
}
|
||||
|
||||
async function prepareGenericJobAsync(
|
||||
ctx: BuildContext<Platform.Android>,
|
||||
ctx: BuildContext<Platform.ANDROID>,
|
||||
jobData: JobData,
|
||||
buildProfile: AndroidGenericBuildProfile
|
||||
): Promise<Partial<Android.GenericJob>> {
|
||||
@@ -96,7 +99,7 @@ async function prepareGenericJobAsync(
|
||||
path.relative(await gitRootDirectoryAsync(), ctx.commandCtx.projectDir) || '.';
|
||||
return {
|
||||
...(await prepareJobCommonAsync(ctx, jobData)),
|
||||
type: Workflow.Generic,
|
||||
type: Workflow.GENERIC,
|
||||
gradleCommand: buildProfile.gradleCommand,
|
||||
artifactPath: buildProfile.artifactPath,
|
||||
releaseChannel: buildProfile.releaseChannel,
|
||||
@@ -105,7 +108,7 @@ async function prepareGenericJobAsync(
|
||||
}
|
||||
|
||||
async function prepareManagedJobAsync(
|
||||
ctx: BuildContext<Platform.Android>,
|
||||
ctx: BuildContext<Platform.ANDROID>,
|
||||
jobData: JobData,
|
||||
buildProfile: AndroidManagedBuildProfile
|
||||
): Promise<Partial<Android.ManagedJob>> {
|
||||
@@ -114,7 +117,7 @@ async function prepareManagedJobAsync(
|
||||
const accountName = await getProjectAccountNameAsync(ctx.commandCtx.projectDir);
|
||||
return {
|
||||
...(await prepareJobCommonAsync(ctx, jobData)),
|
||||
type: Workflow.Managed,
|
||||
type: Workflow.MANAGED,
|
||||
username: accountName,
|
||||
buildType: buildProfile.buildType,
|
||||
releaseChannel: buildProfile.releaseChannel,
|
||||
|
||||
@@ -112,8 +112,7 @@ export async function prepareBuildRequestForPlatformAsync<
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
const body = error?.response?.body;
|
||||
if (body && JSON.parse(body)?.errors?.[0]?.code === 'TURTLE_DEPRECATED_JOB_FORMAT') {
|
||||
if (error?.expoApiV2ErrorCode === 'TURTLE_DEPRECATED_JOB_FORMAT') {
|
||||
Log.error('EAS Build API has changed, please upgrade to the latest eas-cli');
|
||||
}
|
||||
throw error;
|
||||
@@ -183,7 +182,7 @@ enum ShouldCommitChanges {
|
||||
}
|
||||
|
||||
async function reviewAndCommitChangesAsync(
|
||||
commitMessage: string,
|
||||
initialCommitMessage: string,
|
||||
{ nonInteractive, askedFirstTime = true }: { nonInteractive: boolean; askedFirstTime?: boolean }
|
||||
): Promise<void> {
|
||||
if (nonInteractive) {
|
||||
@@ -212,10 +211,13 @@ async function reviewAndCommitChangesAsync(
|
||||
"Aborting, run the command again once you're ready. Make sure to commit any changes you've made."
|
||||
);
|
||||
} else if (selected === ShouldCommitChanges.Yes) {
|
||||
await commitPromptAsync(commitMessage);
|
||||
await commitPromptAsync({ initialCommitMessage });
|
||||
Log.withTick('Committed changes.');
|
||||
} else if (selected === ShouldCommitChanges.ShowDiffFirst) {
|
||||
await showDiffAsync();
|
||||
await reviewAndCommitChangesAsync(commitMessage, { nonInteractive, askedFirstTime: false });
|
||||
await reviewAndCommitChangesAsync(initialCommitMessage, {
|
||||
nonInteractive,
|
||||
askedFirstTime: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -132,7 +132,7 @@ enum ShouldCommitChanges {
|
||||
}
|
||||
|
||||
async function reviewAndCommitChangesAsync(
|
||||
commitMessage: string,
|
||||
initialCommitMessage: string,
|
||||
askedFirstTime: boolean = true
|
||||
): Promise<void> {
|
||||
const { selected } = await promptAsync({
|
||||
@@ -152,10 +152,10 @@ async function reviewAndCommitChangesAsync(
|
||||
});
|
||||
|
||||
if (selected === ShouldCommitChanges.Yes) {
|
||||
await commitPromptAsync(commitMessage);
|
||||
await commitPromptAsync({ initialCommitMessage });
|
||||
Log.withTick('Committed changes');
|
||||
} else if (selected === ShouldCommitChanges.ShowDiffFirst) {
|
||||
await showDiffAsync();
|
||||
await reviewAndCommitChangesAsync(commitMessage, false);
|
||||
await reviewAndCommitChangesAsync(initialCommitMessage, false);
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,6 @@ export const platformDisplayNames = {
|
||||
};
|
||||
|
||||
export const platformEmojis = {
|
||||
[Platform.iOS]: '🍎',
|
||||
[Platform.Android]: '🤖',
|
||||
[Platform.IOS]: '🍎',
|
||||
[Platform.ANDROID]: '🤖',
|
||||
};
|
||||
@@ -77,7 +77,7 @@ export interface ConfigureContext {
|
||||
hasIosNativeProject: boolean;
|
||||
}
|
||||
|
||||
type PlatformBuildProfile<T extends Platform> = T extends Platform.Android
|
||||
type PlatformBuildProfile<T extends Platform> = T extends Platform.ANDROID
|
||||
? AndroidBuildProfile
|
||||
: iOSBuildProfile;
|
||||
|
||||
|
||||
@@ -51,11 +51,11 @@ async function startBuildsAsync(
|
||||
}[] = [];
|
||||
if (shouldBuildAndroid) {
|
||||
const sendBuildRequestAsync = await prepareAndroidBuildAsync(commandCtx, easConfig);
|
||||
builds.push({ platform: Platform.Android, sendBuildRequestAsync });
|
||||
builds.push({ platform: Platform.ANDROID, sendBuildRequestAsync });
|
||||
}
|
||||
if (shouldBuildiOS) {
|
||||
const sendBuildRequestAsync = await prepareIosBuildAsync(commandCtx, easConfig);
|
||||
builds.push({ platform: Platform.iOS, sendBuildRequestAsync });
|
||||
builds.push({ platform: Platform.IOS, sendBuildRequestAsync });
|
||||
}
|
||||
return Promise.all(
|
||||
builds.map(async ({ platform, sendBuildRequestAsync }) => ({
|
||||
|
||||
@@ -21,13 +21,13 @@ async function ensureCredentialsAutoAsync(
|
||||
): Promise<CredentialsSource.LOCAL | CredentialsSource.REMOTE> {
|
||||
const platform = platformDisplayNames[provider.platform];
|
||||
switch (workflow) {
|
||||
case Workflow.Managed:
|
||||
case Workflow.MANAGED:
|
||||
if (await provider.hasLocalAsync()) {
|
||||
return CredentialsSource.LOCAL;
|
||||
} else {
|
||||
return CredentialsSource.REMOTE;
|
||||
}
|
||||
case Workflow.Generic: {
|
||||
case Workflow.GENERIC: {
|
||||
const hasLocal = await provider.hasLocalAsync();
|
||||
const hasRemote = await provider.hasRemoteAsync();
|
||||
if (hasRemote && hasLocal) {
|
||||
|
||||
@@ -20,14 +20,14 @@ export async function prepareIosBuildAsync(
|
||||
commandCtx: CommandContext,
|
||||
easConfig: EasConfig
|
||||
): Promise<() => Promise<string>> {
|
||||
const buildCtx = createBuildContext<Platform.iOS>({
|
||||
const buildCtx = createBuildContext<Platform.IOS>({
|
||||
commandCtx,
|
||||
platform: Platform.iOS,
|
||||
platform: Platform.IOS,
|
||||
easConfig,
|
||||
});
|
||||
|
||||
if (
|
||||
buildCtx.buildProfile.workflow === Workflow.Generic &&
|
||||
buildCtx.buildProfile.workflow === Workflow.GENERIC &&
|
||||
!(await fs.pathExists(path.join(commandCtx.projectDir, 'ios')))
|
||||
) {
|
||||
throw new Error(
|
||||
@@ -39,9 +39,9 @@ export async function prepareIosBuildAsync(
|
||||
|
||||
let iosBuildScheme: string | undefined;
|
||||
let iosApplicationTarget: string | undefined;
|
||||
if (buildCtx.buildProfile.workflow === Workflow.Generic) {
|
||||
if (buildCtx.buildProfile.workflow === Workflow.GENERIC) {
|
||||
iosBuildScheme = buildCtx.buildProfile.scheme ?? (await resolveSchemeAsync(buildCtx));
|
||||
iosApplicationTarget = await IOSConfig.Target.getApplicationTargetForSchemeAsync(
|
||||
iosApplicationTarget = await IOSConfig.BuildScheme.getApplicationTargetForSchemeAsync(
|
||||
buildCtx.commandCtx.projectDir,
|
||||
iosBuildScheme
|
||||
);
|
||||
@@ -67,8 +67,8 @@ export async function prepareIosBuildAsync(
|
||||
});
|
||||
}
|
||||
|
||||
async function resolveSchemeAsync(ctx: BuildContext<Platform.iOS>): Promise<string> {
|
||||
const schemes = IOSConfig.Scheme.getSchemesFromXcodeproj(ctx.commandCtx.projectDir);
|
||||
async function resolveSchemeAsync(ctx: BuildContext<Platform.IOS>): Promise<string> {
|
||||
const schemes = IOSConfig.BuildScheme.getSchemesFromXcodeproj(ctx.commandCtx.projectDir);
|
||||
if (schemes.length === 1) {
|
||||
return schemes[0];
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ function isBundleIdentifierValid(bundleIdentifier: string): boolean {
|
||||
}
|
||||
|
||||
export async function ensureBundleIdentifierIsValidAsync(projectDir: string) {
|
||||
const bundleIdentifier = await ensureAppIdentifierIsDefinedAsync(projectDir, Platform.iOS);
|
||||
const bundleIdentifier = await ensureAppIdentifierIsDefinedAsync(projectDir, Platform.IOS);
|
||||
if (!isBundleIdentifierValid(bundleIdentifier)) {
|
||||
const configDescription = getProjectConfigDescription(projectDir);
|
||||
Log.error(
|
||||
|
||||
@@ -38,7 +38,7 @@ export async function validateAndSyncProjectConfigurationAsync({
|
||||
const { workflow, autoIncrement } = buildProfile;
|
||||
const versionBumpStrategy = resolveVersionBumpStrategy(autoIncrement);
|
||||
|
||||
if (workflow === Workflow.Generic) {
|
||||
if (workflow === Workflow.GENERIC) {
|
||||
const bundleIdentifierFromPbxproj = IOSConfig.BundleIdentifier.getBundleIdentifierFromPbxproj(
|
||||
projectDir
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Workflow } from '@expo/eas-build-job';
|
||||
import { CredentialsSource, DistributionType } from '@expo/eas-json';
|
||||
import { CredentialsSource, iOSDistributionType } from '@expo/eas-json';
|
||||
import assert from 'assert';
|
||||
|
||||
import { createCredentialsContextAsync } from '../../credentials/context';
|
||||
@@ -13,7 +13,7 @@ import { ensureCredentialsAsync } from '../credentials';
|
||||
import { Platform } from '../types';
|
||||
|
||||
export async function ensureIosCredentialsAsync(
|
||||
ctx: BuildContext<Platform.iOS>
|
||||
ctx: BuildContext<Platform.IOS>
|
||||
): Promise<CredentialsResult<IosCredentials> | undefined> {
|
||||
if (!shouldProvideCredentials(ctx)) {
|
||||
return;
|
||||
@@ -27,7 +27,7 @@ export async function ensureIosCredentialsAsync(
|
||||
},
|
||||
workflow: ctx.buildProfile.workflow,
|
||||
credentialsSource: ctx.buildProfile.credentialsSource,
|
||||
distribution: ctx.buildProfile.distribution ?? DistributionType.STORE,
|
||||
distribution: ctx.buildProfile.distribution ?? 'store',
|
||||
nonInteractive: ctx.commandCtx.nonInteractive,
|
||||
skipCredentialsCheck: ctx.commandCtx.skipCredentialsCheck,
|
||||
});
|
||||
@@ -37,7 +37,7 @@ interface ResolveCredentialsParams {
|
||||
app: AppLookupParams;
|
||||
workflow: Workflow;
|
||||
credentialsSource: CredentialsSource;
|
||||
distribution: DistributionType;
|
||||
distribution: iOSDistributionType;
|
||||
nonInteractive: boolean;
|
||||
skipCredentialsCheck: boolean;
|
||||
}
|
||||
@@ -68,6 +68,6 @@ export async function resolveIosCredentialsAsync(
|
||||
};
|
||||
}
|
||||
|
||||
function shouldProvideCredentials(ctx: BuildContext<Platform.iOS>): boolean {
|
||||
return true;
|
||||
function shouldProvideCredentials(ctx: BuildContext<Platform.IOS>): boolean {
|
||||
return ctx.buildProfile.distribution !== 'simulator';
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
import {
|
||||
ArchiveSource,
|
||||
ArchiveSourceType,
|
||||
Cache,
|
||||
Ios,
|
||||
Job,
|
||||
Workflow,
|
||||
iOS,
|
||||
sanitizeJob,
|
||||
} from '@expo/eas-build-job';
|
||||
import { iOSGenericBuildProfile, iOSManagedBuildProfile } from '@expo/eas-json';
|
||||
@@ -31,13 +32,13 @@ interface JobData {
|
||||
}
|
||||
|
||||
export async function prepareJobAsync(
|
||||
ctx: BuildContext<Platform.iOS>,
|
||||
ctx: BuildContext<Platform.IOS>,
|
||||
jobData: JobData
|
||||
): Promise<Job> {
|
||||
if (ctx.buildProfile.workflow === Workflow.Generic) {
|
||||
if (ctx.buildProfile.workflow === Workflow.GENERIC) {
|
||||
const partialJob = await prepareGenericJobAsync(ctx, jobData, ctx.buildProfile);
|
||||
return sanitizeJob(partialJob);
|
||||
} else if (ctx.buildProfile.workflow === Workflow.Managed) {
|
||||
} else if (ctx.buildProfile.workflow === Workflow.MANAGED) {
|
||||
const partialJob = await prepareManagedJobAsync(ctx, jobData, ctx.buildProfile);
|
||||
return sanitizeJob(partialJob);
|
||||
} else {
|
||||
@@ -46,18 +47,20 @@ export async function prepareJobAsync(
|
||||
}
|
||||
|
||||
interface CommonJobProperties {
|
||||
platform: Platform.iOS;
|
||||
platform: Platform.IOS;
|
||||
projectArchive: ArchiveSource;
|
||||
builderEnvironment: iOS.BuilderEnvironment;
|
||||
releaseChannel: string;
|
||||
builderEnvironment: Ios.BuilderEnvironment;
|
||||
releaseChannel?: string;
|
||||
distribution?: Ios.DistributionType;
|
||||
cache: Cache | null;
|
||||
secrets: {
|
||||
buildCredentials: iOS.BuildCredentials;
|
||||
buildCredentials: Ios.BuildCredentials;
|
||||
secretEnvs?: Record<string, string>;
|
||||
};
|
||||
}
|
||||
|
||||
async function prepareJobCommonAsync(
|
||||
ctx: BuildContext<Platform.iOS>,
|
||||
ctx: BuildContext<Platform.IOS>,
|
||||
{
|
||||
archiveBucketKey,
|
||||
credentials,
|
||||
@@ -83,11 +86,12 @@ async function prepareJobCommonAsync(
|
||||
}
|
||||
|
||||
return {
|
||||
platform: Platform.iOS,
|
||||
platform: Platform.IOS,
|
||||
projectArchive: {
|
||||
type: ArchiveSourceType.S3,
|
||||
bucketKey: archiveBucketKey,
|
||||
},
|
||||
distribution: ctx.buildProfile.distribution,
|
||||
builderEnvironment: {
|
||||
image: ctx.buildProfile.image,
|
||||
node: ctx.buildProfile.node,
|
||||
@@ -96,6 +100,7 @@ async function prepareJobCommonAsync(
|
||||
fastlane: ctx.buildProfile.fastlane,
|
||||
env: ctx.buildProfile.env,
|
||||
},
|
||||
cache: ctx.buildProfile.cache,
|
||||
secrets: {
|
||||
...(secretEnvs ? { secretEnvs } : {}),
|
||||
buildCredentials,
|
||||
@@ -103,7 +108,7 @@ async function prepareJobCommonAsync(
|
||||
};
|
||||
}
|
||||
|
||||
function prepareTargetCredentials(targetCredentials: IosTargetCredentials): iOS.TargetCredentials {
|
||||
function prepareTargetCredentials(targetCredentials: IosTargetCredentials): Ios.TargetCredentials {
|
||||
return {
|
||||
provisioningProfileBase64: targetCredentials.provisioningProfile,
|
||||
distributionCertificate: {
|
||||
@@ -114,10 +119,10 @@ function prepareTargetCredentials(targetCredentials: IosTargetCredentials): iOS.
|
||||
}
|
||||
|
||||
async function prepareGenericJobAsync(
|
||||
ctx: BuildContext<Platform.iOS>,
|
||||
ctx: BuildContext<Platform.IOS>,
|
||||
jobData: JobData,
|
||||
buildProfile: iOSGenericBuildProfile
|
||||
): Promise<Partial<iOS.GenericJob>> {
|
||||
): Promise<Partial<Ios.GenericJob>> {
|
||||
const projectRootDirectory =
|
||||
path.relative(await gitRootDirectoryAsync(), ctx.commandCtx.projectDir) || '.';
|
||||
return {
|
||||
@@ -126,7 +131,7 @@ async function prepareGenericJobAsync(
|
||||
credentials: jobData.credentials,
|
||||
targetName: jobData.projectConfiguration.iosApplicationTarget,
|
||||
})),
|
||||
type: Workflow.Generic,
|
||||
type: Workflow.GENERIC,
|
||||
scheme: jobData.projectConfiguration.iosBuildScheme,
|
||||
schemeBuildConfiguration: buildProfile.schemeBuildConfiguration,
|
||||
artifactPath: buildProfile.artifactPath,
|
||||
@@ -136,10 +141,10 @@ async function prepareGenericJobAsync(
|
||||
}
|
||||
|
||||
async function prepareManagedJobAsync(
|
||||
ctx: BuildContext<Platform.iOS>,
|
||||
ctx: BuildContext<Platform.IOS>,
|
||||
jobData: JobData,
|
||||
buildProfile: iOSManagedBuildProfile
|
||||
): Promise<Partial<iOS.ManagedJob>> {
|
||||
): Promise<Partial<Ios.ManagedJob>> {
|
||||
const projectRootDirectory =
|
||||
path.relative(await gitRootDirectoryAsync(), ctx.commandCtx.projectDir) || '.';
|
||||
const accountName = await getProjectAccountNameAsync(ctx.commandCtx.projectDir);
|
||||
@@ -150,7 +155,7 @@ async function prepareManagedJobAsync(
|
||||
credentials: jobData.credentials,
|
||||
targetName,
|
||||
})),
|
||||
type: Workflow.Managed,
|
||||
type: Workflow.MANAGED,
|
||||
buildType: buildProfile.buildType,
|
||||
username: accountName,
|
||||
releaseChannel: buildProfile.releaseChannel,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { CredentialsSource, DistributionType } from '@expo/eas-json';
|
||||
import { CredentialsSource } from '@expo/eas-json';
|
||||
|
||||
import { getAppIdentifierAsync } from '../project/projectUtils';
|
||||
import { BuildContext } from './context';
|
||||
@@ -26,7 +26,7 @@ export async function collectMetadata<T extends Platform>(
|
||||
credentialsSource,
|
||||
sdkVersion: ctx.commandCtx.exp.sdkVersion,
|
||||
trackingContext: ctx.trackingCtx,
|
||||
distribution: ctx.buildProfile.distribution ?? DistributionType.STORE,
|
||||
distribution: ctx.buildProfile.distribution ?? 'store',
|
||||
appName: ctx.commandCtx.exp.name,
|
||||
appIdentifier:
|
||||
(await getAppIdentifierAsync(ctx.commandCtx.projectDir, ctx.platform)) ?? undefined,
|
||||
|
||||
@@ -83,7 +83,7 @@ export type BuildMetadata = {
|
||||
|
||||
/**
|
||||
* Distribution type
|
||||
* Indicates whether this is a build for store or internal distribution.
|
||||
* Indicates whether this is a build for store, internal distribution, or simulator (iOS).
|
||||
*/
|
||||
distribution: DistributionType;
|
||||
|
||||
@@ -100,7 +100,7 @@ export type BuildMetadata = {
|
||||
appIdentifier?: string;
|
||||
};
|
||||
|
||||
export type PlatformBuildProfile<T extends Platform> = T extends Platform.Android
|
||||
export type PlatformBuildProfile<T extends Platform> = T extends Platform.ANDROID
|
||||
? AndroidBuildProfile
|
||||
: iOSBuildProfile;
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { DistributionType } from '@expo/eas-json';
|
||||
import assert from 'assert';
|
||||
import chalk from 'chalk';
|
||||
|
||||
@@ -47,7 +46,7 @@ export function printBuildResults(accountName: string, builds: (Build | null)[])
|
||||
}
|
||||
|
||||
function printBuildResult(accountName: string, build: Build): void {
|
||||
if (build.metadata?.distribution === DistributionType.INTERNAL) {
|
||||
if (build.metadata?.distribution === 'internal') {
|
||||
const logsUrl = getBuildLogsUrl({
|
||||
buildId: build.id,
|
||||
account: accountName,
|
||||
|
||||
@@ -43,12 +43,11 @@ async function ensureGitRepoExistsAsync(): Promise<void> {
|
||||
|
||||
Log.log("We're going to make an initial commit for you repository.");
|
||||
|
||||
await spawnAsync('git', ['add', '-A']);
|
||||
await commitPromptAsync('Initial commit');
|
||||
await commitPromptAsync({ initialCommitMessage: 'Initial commit', commitAllFiles: true });
|
||||
}
|
||||
|
||||
async function isGitStatusCleanAsync(): Promise<boolean> {
|
||||
const changes = await gitStatusAsync();
|
||||
const changes = await gitStatusAsync({ showUntracked: true });
|
||||
return changes.length === 0;
|
||||
}
|
||||
|
||||
@@ -90,7 +89,7 @@ async function ensureGitStatusIsCleanAsync(nonInteractive = false): Promise<void
|
||||
message: `Commit changes to git?`,
|
||||
});
|
||||
if (answer) {
|
||||
await commitPromptAsync();
|
||||
await commitPromptAsync({ commitAllFiles: true });
|
||||
} else {
|
||||
throw new Error('Please commit all changes. Aborting...');
|
||||
}
|
||||
@@ -151,7 +150,13 @@ async function showDiffAsync() {
|
||||
await gitDiffAsync({ withPager: outputTooLarge });
|
||||
}
|
||||
|
||||
async function commitPromptAsync(initialCommitMessage?: string): Promise<void> {
|
||||
async function commitPromptAsync({
|
||||
initialCommitMessage,
|
||||
commitAllFiles,
|
||||
}: {
|
||||
initialCommitMessage?: string;
|
||||
commitAllFiles?: boolean;
|
||||
} = {}): Promise<void> {
|
||||
const { message } = await promptAsync({
|
||||
type: 'text',
|
||||
name: 'message',
|
||||
@@ -159,6 +164,9 @@ async function commitPromptAsync(initialCommitMessage?: string): Promise<void> {
|
||||
initial: initialCommitMessage,
|
||||
validate: (input: string) => input !== '',
|
||||
});
|
||||
if (commitAllFiles) {
|
||||
await spawnAsync('git', ['add', '-A']);
|
||||
}
|
||||
await commitChangedFilesAsync(message);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,30 +14,30 @@ import { getBranchNameAsync } from '../../utils/git';
|
||||
|
||||
export async function createUpdateBranchOnAppAsync({
|
||||
appId,
|
||||
branchName,
|
||||
name,
|
||||
}: {
|
||||
appId: string;
|
||||
branchName: string;
|
||||
}): Promise<Pick<UpdateBranch, 'id' | 'branchName'>> {
|
||||
name: string;
|
||||
}): Promise<Pick<UpdateBranch, 'id' | 'name'>> {
|
||||
const data = await withErrorHandlingAsync(
|
||||
graphqlClient
|
||||
.mutation<
|
||||
{ updateBranch: { createUpdateBranchForApp: Pick<UpdateBranch, 'id' | 'branchName'> } },
|
||||
{ appId: string; branchName: string }
|
||||
{ updateBranch: { createUpdateBranchForApp: Pick<UpdateBranch, 'id' | 'name'> } },
|
||||
{ appId: string; name: string }
|
||||
>(
|
||||
gql`
|
||||
mutation createUpdateBranchForApp($appId: ID!, $branchName: String!) {
|
||||
mutation createUpdateBranchForApp($appId: ID!, $name: String!) {
|
||||
updateBranch {
|
||||
createUpdateBranchForApp(appId: $appId, branchName: $branchName) {
|
||||
createUpdateBranchForApp(appId: $appId, name: $name) {
|
||||
id
|
||||
branchName
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
{
|
||||
appId,
|
||||
branchName,
|
||||
name,
|
||||
}
|
||||
)
|
||||
.toPromise()
|
||||
@@ -51,7 +51,7 @@ export default class BranchCreate extends Command {
|
||||
|
||||
static args = [
|
||||
{
|
||||
name: 'branchName',
|
||||
name: 'name',
|
||||
required: false,
|
||||
description: 'Name of the branch to create',
|
||||
},
|
||||
@@ -66,7 +66,7 @@ export default class BranchCreate extends Command {
|
||||
|
||||
async run() {
|
||||
let {
|
||||
args: { branchName },
|
||||
args: { name },
|
||||
flags,
|
||||
} = this.parse(BranchCreate);
|
||||
|
||||
@@ -82,14 +82,14 @@ export default class BranchCreate extends Command {
|
||||
projectName: exp.slug,
|
||||
});
|
||||
|
||||
if (!branchName) {
|
||||
if (!name) {
|
||||
const validationMessage = 'Branch name may not be empty.';
|
||||
if (flags.json) {
|
||||
throw new Error(validationMessage);
|
||||
}
|
||||
({ branchName } = await promptAsync({
|
||||
({ name } = await promptAsync({
|
||||
type: 'text',
|
||||
name: 'branchName',
|
||||
name: 'name',
|
||||
message: 'Please name the branch:',
|
||||
initial:
|
||||
(await getBranchNameAsync()) || `branch-${Math.random().toString(36).substr(2, 4)}`,
|
||||
@@ -97,7 +97,7 @@ export default class BranchCreate extends Command {
|
||||
}));
|
||||
}
|
||||
|
||||
const newBranch = await createUpdateBranchOnAppAsync({ appId: projectId, branchName });
|
||||
const newBranch = await createUpdateBranchOnAppAsync({ appId: projectId, name });
|
||||
|
||||
if (flags.json) {
|
||||
Log.log(newBranch);
|
||||
@@ -105,7 +105,7 @@ export default class BranchCreate extends Command {
|
||||
}
|
||||
|
||||
Log.withTick(
|
||||
`️Created a new branch: ${chalk.bold(newBranch.branchName)} on project ${chalk.bold(
|
||||
`️Created a new branch: ${chalk.bold(newBranch.name)} on project ${chalk.bold(
|
||||
`@${accountName}/${exp.slug}`
|
||||
)}.`
|
||||
);
|
||||
|
||||
@@ -38,10 +38,7 @@ export default class BranchList extends Command {
|
||||
} else {
|
||||
const table = new CliTable({ head: ['Branch', 'Latest update'] });
|
||||
table.push(
|
||||
...branches.map((branch: UpdateBranch) => [
|
||||
branch.branchName,
|
||||
formatUpdate(branch.updates[0]),
|
||||
])
|
||||
...branches.map((branch: UpdateBranch) => [branch.name, formatUpdate(branch.updates[0])])
|
||||
);
|
||||
Log.log(table.toString());
|
||||
if (branches.length >= BRANCHES_LIMIT) {
|
||||
@@ -61,7 +58,7 @@ export default class BranchList extends Command {
|
||||
fullName
|
||||
updateBranches(offset: 0, limit: $limit) {
|
||||
id
|
||||
branchName
|
||||
name
|
||||
updates(offset: 0, limit: 1) {
|
||||
id
|
||||
actor {
|
||||
@@ -75,7 +72,7 @@ export default class BranchList extends Command {
|
||||
}
|
||||
}
|
||||
updatedAt
|
||||
updateMessage
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,7 +102,7 @@ function formatUpdate(update: Update | undefined): string {
|
||||
if (!update) {
|
||||
return 'N/A';
|
||||
}
|
||||
const message = update.updateMessage ? `"${update.updateMessage}" ` : '';
|
||||
const message = update.message ? `"${update.message}" ` : '';
|
||||
return `${message}(${format(update.updatedAt, 'en_US')} by ${getActorDisplayName(
|
||||
update.actor as any
|
||||
)})`;
|
||||
|
||||
@@ -12,7 +12,12 @@ import {
|
||||
getBranchByNameAsync,
|
||||
getProjectAccountNameAsync,
|
||||
} from '../../project/projectUtils';
|
||||
import { buildUpdateInfoGroupAsync, collectAssets, uploadAssetsAsync } from '../../project/publish';
|
||||
import {
|
||||
buildBundlesAsync,
|
||||
buildUpdateInfoGroupAsync,
|
||||
collectAssets,
|
||||
uploadAssetsAsync,
|
||||
} from '../../project/publish';
|
||||
import { promptAsync } from '../../prompts';
|
||||
import { getLastCommitMessageAsync } from '../../utils/git';
|
||||
|
||||
@@ -37,11 +42,21 @@ export default class BranchPublish extends Command {
|
||||
description: `return a json with the edited branch's ID and name.`,
|
||||
default: false,
|
||||
}),
|
||||
'skip-bundler': flags.boolean({
|
||||
description: `skip running Expo CLI to bundle the app before publishing`,
|
||||
default: false,
|
||||
}),
|
||||
};
|
||||
|
||||
async run() {
|
||||
let {
|
||||
flags: { json: jsonFlag, branch: branchName, message: updateMessage, 'input-dir': inputDir },
|
||||
flags: {
|
||||
json: jsonFlag,
|
||||
branch: name,
|
||||
message,
|
||||
'input-dir': inputDir,
|
||||
'skip-bundler': skipBundler,
|
||||
},
|
||||
} = this.parse(BranchPublish);
|
||||
|
||||
const projectDir = await findProjectRootAsync(process.cwd());
|
||||
@@ -63,25 +78,25 @@ export default class BranchPublish extends Command {
|
||||
projectName: slug,
|
||||
});
|
||||
|
||||
if (!branchName) {
|
||||
if (!name) {
|
||||
const validationMessage = 'branch name may not be empty.';
|
||||
if (jsonFlag) {
|
||||
throw new Error(validationMessage);
|
||||
}
|
||||
({ branchName } = await promptAsync({
|
||||
({ name } = await promptAsync({
|
||||
type: 'text',
|
||||
name: 'branchName',
|
||||
name: 'name',
|
||||
message: 'Please enter the name of the branch to publish on:',
|
||||
validate: value => (value ? true : validationMessage),
|
||||
}));
|
||||
}
|
||||
|
||||
if (!updateMessage) {
|
||||
if (!message) {
|
||||
const validationMessage = 'publish message may not be empty.';
|
||||
if (jsonFlag) {
|
||||
throw new Error(validationMessage);
|
||||
}
|
||||
({ publishMessage: updateMessage } = await promptAsync({
|
||||
({ publishMessage: message } = await promptAsync({
|
||||
type: 'text',
|
||||
name: 'publishMessage',
|
||||
message: `Please enter a publication message.`,
|
||||
@@ -92,9 +107,13 @@ export default class BranchPublish extends Command {
|
||||
|
||||
const { id: branchId } = await getBranchByNameAsync({
|
||||
appId: projectId,
|
||||
branchName: branchName!,
|
||||
name: name!,
|
||||
});
|
||||
|
||||
if (!skipBundler) {
|
||||
await buildBundlesAsync({ projectDir, inputDir });
|
||||
}
|
||||
|
||||
let updateInfoGroup;
|
||||
const assetSpinner = ora('Uploading assets...').start();
|
||||
try {
|
||||
@@ -114,7 +133,7 @@ export default class BranchPublish extends Command {
|
||||
branchId,
|
||||
updateInfoGroup,
|
||||
runtimeVersion,
|
||||
updateMessage,
|
||||
message,
|
||||
});
|
||||
publishSpinner.succeed('Published!');
|
||||
} catch (e) {
|
||||
@@ -123,7 +142,7 @@ export default class BranchPublish extends Command {
|
||||
}
|
||||
|
||||
if (jsonFlag) {
|
||||
Log.log(newUpdateGroup);
|
||||
Log.log(JSON.stringify(newUpdateGroup));
|
||||
} else {
|
||||
const outputMessage = new Table({
|
||||
wordWrap: true,
|
||||
@@ -148,10 +167,10 @@ export default class BranchPublish extends Command {
|
||||
});
|
||||
outputMessage.push(
|
||||
[chalk.dim('project'), `@${accountName}/${slug}`],
|
||||
[chalk.dim('branch'), branchName],
|
||||
[chalk.dim('branch'), name],
|
||||
[chalk.dim('runtimeVersion'), runtimeVersion],
|
||||
[chalk.dim('updateGroupID'), newUpdateGroup.updateGroup],
|
||||
[chalk.dim('message'), updateMessage]
|
||||
[chalk.dim('groupID'), newUpdateGroup.group],
|
||||
[chalk.dim('message'), message]
|
||||
);
|
||||
Log.log(outputMessage.toString());
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ async function renameUpdateBranchOnAppAsync({
|
||||
updateBranch {
|
||||
editUpdateBranch(input: $input) {
|
||||
id
|
||||
branchName
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,8 +41,8 @@ async function renameUpdateBranchOnAppAsync({
|
||||
{
|
||||
input: {
|
||||
appId,
|
||||
branchName: currentName,
|
||||
newBranchName: newName,
|
||||
name: currentName,
|
||||
newName,
|
||||
},
|
||||
}
|
||||
)
|
||||
@@ -119,13 +119,13 @@ export default class BranchRename extends Command {
|
||||
});
|
||||
|
||||
if (jsonFlag) {
|
||||
Log.log(editedBranch);
|
||||
Log.log(JSON.stringify(editedBranch));
|
||||
return;
|
||||
}
|
||||
|
||||
Log.withTick(
|
||||
`️Renamed branch from ${currentName} to ${chalk.bold(
|
||||
editedBranch.branchName
|
||||
editedBranch.name
|
||||
)} on project ${chalk.bold(`@${accountName}/${exp.slug}`)}.`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -14,17 +14,17 @@ import { promptAsync } from '../../prompts';
|
||||
|
||||
const PAGE_LIMIT = 10_000;
|
||||
|
||||
type TruncatedUpdate = Pick<Update, 'updateGroup' | 'updateMessage' | 'createdAt' | 'actor'>;
|
||||
type TruncatedUpdate = Pick<Update, 'group' | 'message' | 'createdAt' | 'actor'>;
|
||||
|
||||
async function viewUpdateBranchAsync({
|
||||
appId,
|
||||
branchName,
|
||||
name,
|
||||
}: {
|
||||
appId: string;
|
||||
branchName: string;
|
||||
name: string;
|
||||
}): Promise<{
|
||||
id: string;
|
||||
branchName: string;
|
||||
name: string;
|
||||
updates: TruncatedUpdate[];
|
||||
}> {
|
||||
const data = await withErrorHandlingAsync(
|
||||
@@ -33,9 +33,9 @@ async function viewUpdateBranchAsync({
|
||||
{
|
||||
app: {
|
||||
byId: {
|
||||
updateBranchByBranchName: {
|
||||
updateBranchByName: {
|
||||
id: string;
|
||||
branchName: string;
|
||||
name: string;
|
||||
updates: TruncatedUpdate[];
|
||||
};
|
||||
};
|
||||
@@ -43,22 +43,22 @@ async function viewUpdateBranchAsync({
|
||||
},
|
||||
{
|
||||
appId: string;
|
||||
branchName: string;
|
||||
name: string;
|
||||
limit: number;
|
||||
}
|
||||
>(
|
||||
gql`
|
||||
query ViewBranch($appId: String!, $branchName: String!, $limit: Int!) {
|
||||
query ViewBranch($appId: String!, $name: String!, $limit: Int!) {
|
||||
app {
|
||||
byId(appId: $appId) {
|
||||
id
|
||||
updateBranchByBranchName(branchName: $branchName) {
|
||||
updateBranchByName(name: $name) {
|
||||
id
|
||||
branchName
|
||||
name
|
||||
updates(offset: 0, limit: $limit) {
|
||||
id
|
||||
updateGroup
|
||||
updateMessage
|
||||
group
|
||||
message
|
||||
createdAt
|
||||
actor {
|
||||
id
|
||||
@@ -77,13 +77,13 @@ async function viewUpdateBranchAsync({
|
||||
`,
|
||||
{
|
||||
appId,
|
||||
branchName,
|
||||
name,
|
||||
limit: PAGE_LIMIT,
|
||||
}
|
||||
)
|
||||
.toPromise()
|
||||
);
|
||||
return data.app.byId.updateBranchByBranchName;
|
||||
return data.app.byId.updateBranchByName;
|
||||
}
|
||||
|
||||
export default class BranchView extends Command {
|
||||
@@ -92,7 +92,7 @@ export default class BranchView extends Command {
|
||||
|
||||
static args = [
|
||||
{
|
||||
name: 'branchName',
|
||||
name: 'name',
|
||||
required: false,
|
||||
description: 'Name of the branch to view',
|
||||
},
|
||||
@@ -107,7 +107,7 @@ export default class BranchView extends Command {
|
||||
|
||||
async run() {
|
||||
let {
|
||||
args: { branchName },
|
||||
args: { name },
|
||||
flags: { json: jsonFlag },
|
||||
} = this.parse(BranchView);
|
||||
|
||||
@@ -124,14 +124,14 @@ export default class BranchView extends Command {
|
||||
projectName: slug,
|
||||
});
|
||||
|
||||
if (!branchName) {
|
||||
if (!name) {
|
||||
const validationMessage = 'Branch name may not be empty.';
|
||||
if (jsonFlag) {
|
||||
throw new Error(validationMessage);
|
||||
}
|
||||
({ branchName } = await promptAsync({
|
||||
({ name } = await promptAsync({
|
||||
type: 'text',
|
||||
name: 'branchName',
|
||||
name: 'name',
|
||||
message: 'Please enter the name of the branch to view:',
|
||||
validate: value => (value ? true : validationMessage),
|
||||
}));
|
||||
@@ -139,38 +139,38 @@ export default class BranchView extends Command {
|
||||
|
||||
const UpdateBranch = await viewUpdateBranchAsync({
|
||||
appId: projectId,
|
||||
branchName,
|
||||
name,
|
||||
});
|
||||
|
||||
const updates = Object.values(groupBy(UpdateBranch.updates, u => u.updateGroup)).map(
|
||||
updateGroup => updateGroup[0]
|
||||
const updates = Object.values(groupBy(UpdateBranch.updates, u => u.group)).map(
|
||||
group => group[0]
|
||||
);
|
||||
|
||||
if (jsonFlag) {
|
||||
Log.log({ ...UpdateBranch, updates });
|
||||
Log.log(JSON.stringify({ ...UpdateBranch, updates }));
|
||||
return;
|
||||
}
|
||||
|
||||
const updateGroupTable = new Table({
|
||||
head: ['createdAt', 'updateMessage', 'updateGroup', 'actor'],
|
||||
const groupTable = new Table({
|
||||
head: ['createdAt', 'message', 'group', 'actor'],
|
||||
wordWrap: true,
|
||||
});
|
||||
|
||||
for (const update of updates) {
|
||||
updateGroupTable.push([
|
||||
groupTable.push([
|
||||
new Date(update.createdAt).toLocaleString(),
|
||||
update.updateMessage,
|
||||
update.updateGroup,
|
||||
update.message,
|
||||
update.group,
|
||||
update.actor?.firstName,
|
||||
]);
|
||||
}
|
||||
|
||||
Log.withTick(
|
||||
`️Branch: ${chalk.bold(UpdateBranch.branchName)} on project ${chalk.bold(
|
||||
`️Branch: ${chalk.bold(UpdateBranch.name)} on project ${chalk.bold(
|
||||
`@${accountName}/${slug}`
|
||||
)}. Branch ID: ${chalk.bold(UpdateBranch.id)}`
|
||||
);
|
||||
Log.log(chalk.bold('Recent update groups published on this branch:'));
|
||||
Log.log(updateGroupTable.toString());
|
||||
Log.log(groupTable.toString());
|
||||
}
|
||||
}
|
||||
@@ -38,8 +38,8 @@ async function cancelBuildAsync(buildId: string): Promise<Pick<Build, 'id' | 'st
|
||||
}
|
||||
|
||||
const appPlatformMap = {
|
||||
[AppPlatform.Android]: Platform.Android,
|
||||
[AppPlatform.Ios]: Platform.iOS,
|
||||
[AppPlatform.Android]: Platform.ANDROID,
|
||||
[AppPlatform.Ios]: Platform.IOS,
|
||||
};
|
||||
|
||||
function formatUnfinishedBuild(
|
||||
|
||||
@@ -33,22 +33,14 @@ async function createUpdateChannelOnAppAsync({
|
||||
graphqlClient
|
||||
.mutation<
|
||||
{ updateChannel: { createUpdateChannelForApp: UpdateChannel } },
|
||||
{ appId: string; channelName: string; branchMapping: string }
|
||||
{ appId: string; name: string; branchMapping: string }
|
||||
>(
|
||||
gql`
|
||||
mutation CreateUpdateChannelForApp(
|
||||
$appId: ID!
|
||||
$channelName: String!
|
||||
$branchMapping: String!
|
||||
) {
|
||||
mutation CreateUpdateChannelForApp($appId: ID!, $name: String!, $branchMapping: String!) {
|
||||
updateChannel {
|
||||
createUpdateChannelForApp(
|
||||
appId: $appId
|
||||
channelName: $channelName
|
||||
branchMapping: $branchMapping
|
||||
) {
|
||||
createUpdateChannelForApp(appId: $appId, name: $name, branchMapping: $branchMapping) {
|
||||
id
|
||||
channelName
|
||||
name
|
||||
branchMapping
|
||||
}
|
||||
}
|
||||
@@ -56,7 +48,7 @@ async function createUpdateChannelOnAppAsync({
|
||||
`,
|
||||
{
|
||||
appId,
|
||||
channelName,
|
||||
name: channelName,
|
||||
branchMapping,
|
||||
}
|
||||
)
|
||||
@@ -71,7 +63,7 @@ export default class ChannelCreate extends Command {
|
||||
|
||||
static args = [
|
||||
{
|
||||
name: 'channelName',
|
||||
name: 'name',
|
||||
required: false,
|
||||
description: 'Name of the channel to create',
|
||||
},
|
||||
@@ -87,7 +79,7 @@ export default class ChannelCreate extends Command {
|
||||
|
||||
async run() {
|
||||
let {
|
||||
args: { channelName },
|
||||
args: { name: channelName },
|
||||
flags: { json: jsonFlag },
|
||||
} = this.parse(ChannelCreate);
|
||||
|
||||
@@ -109,9 +101,9 @@ export default class ChannelCreate extends Command {
|
||||
if (jsonFlag) {
|
||||
throw new Error(validationMessage);
|
||||
}
|
||||
({ channelName } = await promptAsync({
|
||||
({ name: channelName } = await promptAsync({
|
||||
type: 'text',
|
||||
name: 'channelName',
|
||||
name: 'name',
|
||||
message: 'Please name the channel:',
|
||||
validate: value => (value ? true : validationMessage),
|
||||
}));
|
||||
@@ -122,14 +114,14 @@ export default class ChannelCreate extends Command {
|
||||
try {
|
||||
const existingBranch = await getBranchByNameAsync({
|
||||
appId: projectId,
|
||||
branchName: channelName,
|
||||
name: channelName,
|
||||
});
|
||||
branchId = existingBranch.id;
|
||||
branchMessage = `We found a branch with the same name`;
|
||||
} catch (e) {
|
||||
const newBranch = await createUpdateBranchOnAppAsync({
|
||||
appId: projectId,
|
||||
branchName: channelName,
|
||||
name: channelName,
|
||||
});
|
||||
branchId = newBranch.id;
|
||||
branchMessage = `We also went ahead and made a branch with the same name`;
|
||||
@@ -142,12 +134,12 @@ export default class ChannelCreate extends Command {
|
||||
});
|
||||
|
||||
if (jsonFlag) {
|
||||
Log.log(newChannel);
|
||||
Log.log(JSON.stringify(newChannel));
|
||||
return;
|
||||
}
|
||||
|
||||
Log.withTick(
|
||||
`️Created a new channel ${chalk.bold(newChannel.channelName)} on project ${chalk.bold(
|
||||
`️Created a new channel ${chalk.bold(newChannel.name)} on project ${chalk.bold(
|
||||
`@${accountName}/${slug}`
|
||||
)}. ${branchMessage} and have pointed the channel at it. You can now update your app by publishing!`
|
||||
);
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
import { getConfig } from '@expo/config';
|
||||
import { Command, flags } from '@oclif/command';
|
||||
import chalk from 'chalk';
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
import { graphqlClient, withErrorHandlingAsync } from '../../graphql/client';
|
||||
import { UpdateChannel } from '../../graphql/generated';
|
||||
import Log from '../../log';
|
||||
import { ensureProjectExistsAsync } from '../../project/ensureProjectExists';
|
||||
import {
|
||||
findProjectRootAsync,
|
||||
getBranchByNameAsync,
|
||||
getProjectAccountNameAsync,
|
||||
} from '../../project/projectUtils';
|
||||
import { promptAsync } from '../../prompts';
|
||||
|
||||
async function getChannelByNameForAppAsync(variables: {
|
||||
appId: string;
|
||||
channelName: string;
|
||||
}): Promise<UpdateChannel> {
|
||||
const data = await withErrorHandlingAsync(
|
||||
graphqlClient
|
||||
.query(
|
||||
gql`
|
||||
query GetChannelByNameForApp($appId: String!, $channelName: String!) {
|
||||
app {
|
||||
byId(appId: $appId) {
|
||||
id
|
||||
updateChannelByName(name: $channelName) {
|
||||
id
|
||||
name
|
||||
updateBranches(offset: 0, limit: 1) {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables
|
||||
)
|
||||
.toPromise()
|
||||
);
|
||||
return data.app.byId.updateChannelByName;
|
||||
}
|
||||
|
||||
async function updateChannelBranchMappingAsync(variables: {
|
||||
channelId: string;
|
||||
branchMapping: string;
|
||||
}): Promise<UpdateChannel> {
|
||||
const data = await withErrorHandlingAsync(
|
||||
graphqlClient
|
||||
.mutation(
|
||||
gql`
|
||||
mutation UpdateChannelBranchMapping($channelId: ID!, $branchMapping: String!) {
|
||||
updateChannel {
|
||||
editUpdateChannel(channelId: $channelId, branchMapping: $branchMapping) {
|
||||
id
|
||||
name
|
||||
createdAt
|
||||
branchMapping
|
||||
updateBranches(offset: 0, limit: 1) {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables
|
||||
)
|
||||
.toPromise()
|
||||
);
|
||||
return data.updateChannel.editUpdateChannel;
|
||||
}
|
||||
|
||||
export default class ChannelEdit extends Command {
|
||||
static hidden = true;
|
||||
static description = 'Point a channel at a new branch.';
|
||||
|
||||
static args = [
|
||||
{
|
||||
name: 'name',
|
||||
required: false,
|
||||
description: 'Name of the channel to edit',
|
||||
},
|
||||
];
|
||||
|
||||
static flags = {
|
||||
branch: flags.string({
|
||||
description: 'Name of the branch to point to',
|
||||
}),
|
||||
json: flags.boolean({
|
||||
description: 'print output as a JSON object with the channel ID, name and branch mapping.',
|
||||
default: false,
|
||||
}),
|
||||
};
|
||||
|
||||
async run() {
|
||||
let {
|
||||
args: { name: channelName },
|
||||
flags: { branch: branchName, json: jsonFlag },
|
||||
} = this.parse(ChannelEdit);
|
||||
|
||||
const projectDir = await findProjectRootAsync(process.cwd());
|
||||
if (!projectDir) {
|
||||
throw new Error('Please run this command inside a project directory.');
|
||||
}
|
||||
const accountName = await getProjectAccountNameAsync(projectDir);
|
||||
const {
|
||||
exp: { slug },
|
||||
} = getConfig(projectDir, { skipSDKVersionRequirement: true });
|
||||
const projectId = await ensureProjectExistsAsync({
|
||||
accountName,
|
||||
projectName: slug,
|
||||
});
|
||||
|
||||
if (!channelName) {
|
||||
const validationMessage = 'A channel name is required to edit a specific channel.';
|
||||
if (jsonFlag) {
|
||||
throw new Error(validationMessage);
|
||||
}
|
||||
({ name: channelName } = await promptAsync({
|
||||
type: 'text',
|
||||
name: 'name',
|
||||
message: 'Please enter the name of the channel to edit:',
|
||||
validate: value => (value ? true : validationMessage),
|
||||
}));
|
||||
}
|
||||
|
||||
const existingChannel = await getChannelByNameForAppAsync({ appId: projectId, channelName });
|
||||
// todo: refactor when multiple branches per channel are available
|
||||
const existingBranch = existingChannel.updateBranches[0];
|
||||
|
||||
Log.addNewLineIfNone();
|
||||
Log.log(
|
||||
chalk`Channel {bold ${existingChannel.name}} is currently set to branch {bold ${existingBranch.name}}`
|
||||
);
|
||||
Log.addNewLineIfNone();
|
||||
|
||||
if (!branchName) {
|
||||
const validationMessage = 'branch name may not be empty.';
|
||||
if (jsonFlag) {
|
||||
throw new Error(validationMessage);
|
||||
}
|
||||
({ name: branchName } = await promptAsync({
|
||||
type: 'text',
|
||||
name: 'name',
|
||||
message: chalk`What branch should it change to?`,
|
||||
validate: value => (value ? true : validationMessage),
|
||||
}));
|
||||
}
|
||||
|
||||
const branch = await getBranchByNameAsync({
|
||||
appId: projectId,
|
||||
name: branchName!,
|
||||
});
|
||||
|
||||
const channel = await updateChannelBranchMappingAsync({
|
||||
channelId: existingChannel.id,
|
||||
// todo: move branch mapping logic to utility
|
||||
branchMapping: JSON.stringify({
|
||||
data: [{ branchId: branch.id, branchMappingLogic: 'true' }],
|
||||
version: 0,
|
||||
}),
|
||||
});
|
||||
|
||||
if (jsonFlag) {
|
||||
Log.log(JSON.stringify(channel));
|
||||
return;
|
||||
}
|
||||
|
||||
Log.withTick(
|
||||
chalk`Channel {bold ${channel.name}} is now set to branch {bold ${branch.name}}.\n`
|
||||
);
|
||||
Log.log(
|
||||
chalk`Users with builds on channel {bold ${channel.name}} will now receive the active update on {bold ${branch.name}}.`
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
import { getConfig } from '@expo/config';
|
||||
import { Command, flags } from '@oclif/command';
|
||||
import chalk from 'chalk';
|
||||
import Table from 'cli-table3';
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
import { graphqlClient, withErrorHandlingAsync } from '../../graphql/client';
|
||||
import { UpdateChannel } from '../../graphql/generated';
|
||||
import Log from '../../log';
|
||||
import { ensureProjectExistsAsync } from '../../project/ensureProjectExists';
|
||||
import { findProjectRootAsync, getProjectAccountNameAsync } from '../../project/projectUtils';
|
||||
|
||||
const CHANNEL_LIMIT = 10_000;
|
||||
|
||||
async function getAllUpdateChannelForAppAsync({
|
||||
appId,
|
||||
}: {
|
||||
appId: string;
|
||||
}): Promise<UpdateChannel[]> {
|
||||
const data = await withErrorHandlingAsync(
|
||||
graphqlClient
|
||||
.query(
|
||||
gql`
|
||||
query GetAllChannelsForApp($appId: String!, $offset: Int!, $limit: Int!) {
|
||||
app {
|
||||
byId(appId: $appId) {
|
||||
id
|
||||
updateChannels(offset: $offset, limit: $limit) {
|
||||
id
|
||||
name
|
||||
updateBranches(offset: 0, limit: 1) {
|
||||
id
|
||||
name
|
||||
updates(offset: 0, limit: 1) {
|
||||
id
|
||||
group
|
||||
message
|
||||
createdAt
|
||||
actor {
|
||||
id
|
||||
... on User {
|
||||
firstName
|
||||
}
|
||||
... on Robot {
|
||||
firstName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
{ appId, limit: CHANNEL_LIMIT }
|
||||
)
|
||||
.toPromise()
|
||||
);
|
||||
return data.app.byId.updateChannels;
|
||||
}
|
||||
|
||||
export default class ChannelList extends Command {
|
||||
static hidden = true;
|
||||
static description = 'List all channels on the current project.';
|
||||
|
||||
static flags = {
|
||||
json: flags.boolean({
|
||||
description: 'print output as a JSON object with the channel ID, name and branch mapping.',
|
||||
default: false,
|
||||
}),
|
||||
};
|
||||
|
||||
async run() {
|
||||
const {
|
||||
flags: { json: jsonFlag },
|
||||
} = this.parse(ChannelList);
|
||||
|
||||
const projectDir = await findProjectRootAsync(process.cwd());
|
||||
if (!projectDir) {
|
||||
throw new Error('Please run this command inside a project directory.');
|
||||
}
|
||||
const accountName = await getProjectAccountNameAsync(projectDir);
|
||||
const {
|
||||
exp: { slug },
|
||||
} = getConfig(projectDir, { skipSDKVersionRequirement: true });
|
||||
const projectId = await ensureProjectExistsAsync({
|
||||
accountName,
|
||||
projectName: slug,
|
||||
});
|
||||
|
||||
const channels = await getAllUpdateChannelForAppAsync({ appId: projectId });
|
||||
|
||||
if (jsonFlag) {
|
||||
Log.log(JSON.stringify(channels));
|
||||
return;
|
||||
}
|
||||
|
||||
const table = new Table({
|
||||
head: ['channel', 'branch', 'update', 'message', 'created-at', 'actor'],
|
||||
wordWrap: true,
|
||||
});
|
||||
|
||||
for (const channel of channels) {
|
||||
// TODO (cedric): refactor when multiple branches per channel are available
|
||||
const branch = channel.updateBranches[0];
|
||||
const update = branch.updates[0];
|
||||
|
||||
table.push([
|
||||
channel.name,
|
||||
branch.name,
|
||||
update?.group,
|
||||
update?.message,
|
||||
update?.createdAt && new Date(update.createdAt).toLocaleString(),
|
||||
update?.actor?.firstName,
|
||||
]);
|
||||
}
|
||||
|
||||
Log.log(chalk`{bold Channels for this app:}`);
|
||||
Log.log(table.toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
import { getConfig } from '@expo/config';
|
||||
import { Command, flags } from '@oclif/command';
|
||||
import chalk from 'chalk';
|
||||
import Table from 'cli-table3';
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
import { graphqlClient, withErrorHandlingAsync } from '../../graphql/client';
|
||||
import { UpdateChannel } from '../../graphql/generated';
|
||||
import Log from '../../log';
|
||||
import { ensureProjectExistsAsync } from '../../project/ensureProjectExists';
|
||||
import { findProjectRootAsync, getProjectAccountNameAsync } from '../../project/projectUtils';
|
||||
import { promptAsync } from '../../prompts';
|
||||
|
||||
async function getUpdateChannelByNameForAppAsync(variables: {
|
||||
appId: string;
|
||||
channelName: string;
|
||||
}): Promise<UpdateChannel> {
|
||||
const data = await withErrorHandlingAsync(
|
||||
graphqlClient
|
||||
.query(
|
||||
gql`
|
||||
query GetChannelByNameForApp($appId: String!, $channelName: String!) {
|
||||
app {
|
||||
byId(appId: $appId) {
|
||||
id
|
||||
updateChannelByName(name: $channelName) {
|
||||
id
|
||||
name
|
||||
createdAt
|
||||
updateBranches(offset: 0, limit: 1) {
|
||||
id
|
||||
name
|
||||
updates(offset: 0, limit: 1) {
|
||||
id
|
||||
group
|
||||
message
|
||||
createdAt
|
||||
actor {
|
||||
id
|
||||
... on User {
|
||||
firstName
|
||||
}
|
||||
... on Robot {
|
||||
firstName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables
|
||||
)
|
||||
.toPromise()
|
||||
);
|
||||
return data.app.byId.updateChannelByName;
|
||||
}
|
||||
|
||||
export default class ChannelView extends Command {
|
||||
static hidden = true;
|
||||
static description = 'View a channel on the current project.';
|
||||
|
||||
static args = [
|
||||
{
|
||||
name: 'name',
|
||||
required: false,
|
||||
description: 'Name of the channel to view',
|
||||
},
|
||||
];
|
||||
|
||||
static flags = {
|
||||
json: flags.boolean({
|
||||
description: 'print output as a JSON object with the channel ID, name and branch mapping.',
|
||||
default: false,
|
||||
}),
|
||||
};
|
||||
|
||||
async run() {
|
||||
let {
|
||||
args: { name: channelName },
|
||||
flags: { json: jsonFlag },
|
||||
} = this.parse(ChannelView);
|
||||
|
||||
const projectDir = await findProjectRootAsync(process.cwd());
|
||||
if (!projectDir) {
|
||||
throw new Error('Please run this command inside a project directory.');
|
||||
}
|
||||
const accountName = await getProjectAccountNameAsync(projectDir);
|
||||
const {
|
||||
exp: { slug },
|
||||
} = getConfig(projectDir, { skipSDKVersionRequirement: true });
|
||||
const projectId = await ensureProjectExistsAsync({
|
||||
accountName,
|
||||
projectName: slug,
|
||||
});
|
||||
|
||||
if (!channelName) {
|
||||
const validationMessage = 'A channel name is required to view a specific channel.';
|
||||
if (jsonFlag) {
|
||||
throw new Error(validationMessage);
|
||||
}
|
||||
({ name: channelName } = await promptAsync({
|
||||
type: 'text',
|
||||
name: 'name',
|
||||
message: 'Please name the channel:',
|
||||
validate: value => (value ? true : validationMessage),
|
||||
}));
|
||||
}
|
||||
|
||||
const channel = await getUpdateChannelByNameForAppAsync({ appId: projectId, channelName });
|
||||
|
||||
if (jsonFlag) {
|
||||
Log.log(JSON.stringify(channel));
|
||||
return;
|
||||
}
|
||||
|
||||
const table = new Table({
|
||||
head: ['branch', 'update', 'message', 'created-at', 'actor'],
|
||||
wordWrap: true,
|
||||
});
|
||||
|
||||
for (const branch of channel.updateBranches) {
|
||||
// TODO (cedric): refactor when multiple branches per channel are available
|
||||
const update = branch.updates[0];
|
||||
|
||||
table.push([
|
||||
branch.name,
|
||||
update?.group,
|
||||
update?.message,
|
||||
update?.createdAt && new Date(update.createdAt).toLocaleString(),
|
||||
update?.actor?.firstName,
|
||||
]);
|
||||
}
|
||||
|
||||
Log.withTick(
|
||||
chalk`Channel: {bold ${channel.name}} on project {bold ${accountName}/${slug}}. Channel ID: {bold ${channel.id}}`
|
||||
);
|
||||
Log.log(chalk`{bold Recent update groups published on this branch:}`);
|
||||
Log.log(table.toString());
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ interface Options {
|
||||
}
|
||||
|
||||
export default class AndroidCredentialsProvider implements CredentialsProvider {
|
||||
public readonly platform = Platform.Android;
|
||||
public readonly platform = Platform.ANDROID;
|
||||
|
||||
constructor(private ctx: Context, private options: Options) {}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Platform } from '@expo/eas-build-job';
|
||||
import { CredentialsSource, DistributionType } from '@expo/eas-json';
|
||||
import { CredentialsSource, iOSDistributionType } from '@expo/eas-json';
|
||||
|
||||
import { IosDistributionType } from '../../graphql/generated';
|
||||
import Log from '../../log';
|
||||
@@ -10,6 +10,7 @@ import { Context } from '../context';
|
||||
import * as credentialsJsonReader from '../credentialsJson/read';
|
||||
import type { IosCredentials } from '../credentialsJson/read';
|
||||
import { SetupBuildCredentials } from './actions/SetupBuildCredentials';
|
||||
import { isAdHocProfile } from './utils/provisioningProfile';
|
||||
|
||||
export { IosCredentials };
|
||||
|
||||
@@ -23,7 +24,7 @@ interface PartialIosCredentials {
|
||||
|
||||
interface Options {
|
||||
app: AppLookupParams;
|
||||
distribution: DistributionType;
|
||||
distribution: iOSDistributionType;
|
||||
skipCredentialsCheck?: boolean;
|
||||
}
|
||||
|
||||
@@ -34,11 +35,16 @@ interface AppLookupParams {
|
||||
}
|
||||
|
||||
export default class IosCredentialsProvider implements CredentialsProvider {
|
||||
public readonly platform = Platform.iOS;
|
||||
public readonly platform = Platform.IOS;
|
||||
|
||||
constructor(private ctx: Context, private options: Options) {}
|
||||
|
||||
public async hasRemoteAsync(): Promise<boolean> {
|
||||
// TODO: this is temporary
|
||||
// remove this check when we implement syncing local credentials for internal distribution
|
||||
if (this.options.distribution === 'internal' && (await this.hasLocalAsync())) {
|
||||
return false;
|
||||
}
|
||||
const { distributionCertificate, provisioningProfile } = await this.fetchRemoteAsync();
|
||||
return !!(
|
||||
distributionCertificate?.certP12 ||
|
||||
@@ -48,10 +54,6 @@ export default class IosCredentialsProvider implements CredentialsProvider {
|
||||
}
|
||||
|
||||
public async hasLocalAsync(): Promise<boolean> {
|
||||
if (this.options.distribution === DistributionType.INTERNAL) {
|
||||
// TODO: add support for using credentials.json for internal distribution
|
||||
return false;
|
||||
}
|
||||
if (!(await credentialsJsonReader.fileExistsAsync(this.ctx.projectDir))) {
|
||||
return false;
|
||||
}
|
||||
@@ -102,11 +104,32 @@ export default class IosCredentialsProvider implements CredentialsProvider {
|
||||
}
|
||||
|
||||
private async getLocalAsync(): Promise<IosCredentials> {
|
||||
if (this.options.distribution === DistributionType.INTERNAL) {
|
||||
// TODO: add support for using credentials.json for internal distribution
|
||||
throw new Error('Using credentials.json for internal distribution is not supported yet.');
|
||||
const credentials = await credentialsJsonReader.readIosCredentialsAsync(this.ctx.projectDir);
|
||||
if (credentialsJsonReader.isCredentialsMap(credentials)) {
|
||||
for (const targetName of Object.keys(credentials)) {
|
||||
this.assertProvisioningProfileType(credentials[targetName].provisioningProfile, targetName);
|
||||
}
|
||||
} else {
|
||||
this.assertProvisioningProfileType(credentials.provisioningProfile);
|
||||
}
|
||||
return credentials;
|
||||
}
|
||||
|
||||
private assertProvisioningProfileType(provisionigProfile: string, targetName?: string) {
|
||||
const isAdHoc = isAdHocProfile(provisionigProfile);
|
||||
if (this.options.distribution === 'internal' && !isAdHoc) {
|
||||
throw new Error(
|
||||
`You must use an adhoc provisioning profile${
|
||||
targetName && ` (target '${targetName})'`
|
||||
} for internal distribution`
|
||||
);
|
||||
} else if (this.options.distribution !== 'internal' && isAdHoc) {
|
||||
throw new Error(
|
||||
`You can't use an adhoc provisioning profile${
|
||||
targetName && ` (target '${targetName})'`
|
||||
} for app store distribution`
|
||||
);
|
||||
}
|
||||
return await credentialsJsonReader.readIosCredentialsAsync(this.ctx.projectDir);
|
||||
}
|
||||
|
||||
private async getRemoteAsync(): Promise<IosCredentials> {
|
||||
@@ -147,7 +170,7 @@ export default class IosCredentialsProvider implements CredentialsProvider {
|
||||
}
|
||||
|
||||
private async fetchRemoteAsync(): Promise<PartialIosCredentials> {
|
||||
if (this.options.distribution === DistributionType.INTERNAL) {
|
||||
if (this.options.distribution === 'internal') {
|
||||
const { app } = this.options;
|
||||
const account = findAccountByName(this.ctx.user.accounts, app.accountName);
|
||||
if (!account) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { DistributionType } from '@expo/eas-json';
|
||||
import { iOSDistributionType } from '@expo/eas-json';
|
||||
import assert from 'assert';
|
||||
import chalk from 'chalk';
|
||||
|
||||
@@ -21,7 +21,7 @@ type AppCredentialsAndDistCert = {
|
||||
};
|
||||
|
||||
export class SetupBuildCredentials implements Action {
|
||||
constructor(private app: AppLookupParams, private distribution: DistributionType) {}
|
||||
constructor(private app: AppLookupParams, private distribution: iOSDistributionType) {}
|
||||
|
||||
async runAsync(manager: CredentialsManager, ctx: Context): Promise<void> {
|
||||
await ctx.bestEffortAppStoreAuthenticateAsync();
|
||||
@@ -32,7 +32,7 @@ export class SetupBuildCredentials implements Action {
|
||||
|
||||
let iosAppBuildCredentials: IosAppBuildCredentialsFragment | null = null;
|
||||
try {
|
||||
if (this.distribution === DistributionType.INTERNAL) {
|
||||
if (this.distribution === 'internal') {
|
||||
const account = findAccountByName(ctx.user.accounts, this.app.accountName);
|
||||
if (!account) {
|
||||
throw new Error(`You do not have access to the ${this.app.accountName} account`);
|
||||
|
||||
@@ -11,7 +11,7 @@ export class UpdateCredentialsJson implements Action {
|
||||
constructor(private app: AppLookupParams) {}
|
||||
|
||||
async runAsync(manager: CredentialsManager, ctx: Context): Promise<void> {
|
||||
const bundleIdentifer = await ensureAppIdentifierIsDefinedAsync(ctx.projectDir, Platform.iOS);
|
||||
const bundleIdentifer = await ensureAppIdentifierIsDefinedAsync(ctx.projectDir, Platform.IOS);
|
||||
Log.log('Updating iOS credentials in credentials.json');
|
||||
await updateIosCredentialsAsync(ctx, bundleIdentifer);
|
||||
Log.succeed(
|
||||
|
||||
@@ -20,6 +20,12 @@ function readProfileName(dataBase64: string): string {
|
||||
return profilePlist['Name'] as string;
|
||||
}
|
||||
|
||||
function isAdHocProfile(dataBase64: string): boolean {
|
||||
const profilePlist = parse(dataBase64);
|
||||
const provisionedDevices = profilePlist['ProvisionedDevices'] as string[] | undefined;
|
||||
return Array.isArray(provisionedDevices);
|
||||
}
|
||||
|
||||
function parse(dataBase64: string): PlistObject {
|
||||
try {
|
||||
const buffer = Buffer.from(dataBase64, 'base64');
|
||||
@@ -30,4 +36,4 @@ function parse(dataBase64: string): PlistObject {
|
||||
}
|
||||
}
|
||||
|
||||
export { readAppleTeam, readProfileName, parse };
|
||||
export { readAppleTeam, readProfileName, isAdHocProfile, parse };
|
||||
@@ -1,5 +1,3 @@
|
||||
import { DistributionType } from '@expo/eas-json';
|
||||
|
||||
import Log from '../../log';
|
||||
import { getProjectAccountName } from '../../project/projectUtils';
|
||||
import { promptAsync } from '../../prompts';
|
||||
@@ -135,7 +133,7 @@ export class ManageIos implements Action {
|
||||
}
|
||||
case ActionType.SetupBuildCredentials: {
|
||||
const app = this.getAppLookupParamsFromContext(ctx);
|
||||
return new SetupBuildCredentials(app, DistributionType.STORE);
|
||||
return new SetupBuildCredentials(app, 'store');
|
||||
}
|
||||
case ActionType.RemoveSpecificProvisioningProfile: {
|
||||
const app = this.getAppLookupParamsFromContext(ctx);
|
||||
|
||||
@@ -195,6 +195,8 @@ export type Account = {
|
||||
applePushKeys: Array<ApplePushKey>;
|
||||
appleProvisioningProfiles: Array<AppleProvisioningProfile>;
|
||||
appleDevices: Array<AppleDevice>;
|
||||
/** Environment secrets for an account */
|
||||
environmentSecrets: Array<EnvironmentSecret>;
|
||||
};
|
||||
|
||||
|
||||
@@ -277,6 +279,15 @@ export type AccountAppleDevicesArgs = {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An account is a container owning projects, credentials, billing and other organization
|
||||
* data and settings. Actors may own and be members of accounts.
|
||||
*/
|
||||
export type AccountEnvironmentSecretsArgs = {
|
||||
filterNames?: Maybe<Array<Scalars['String']>>;
|
||||
};
|
||||
|
||||
|
||||
export type Offer = {
|
||||
__typename?: 'Offer';
|
||||
id: Scalars['ID'];
|
||||
@@ -396,14 +407,16 @@ export type App = Project & {
|
||||
androidAppCredentials: Array<AndroidAppCredentials>;
|
||||
/** EAS channels owned by an app */
|
||||
updateChannels: Array<UpdateChannel>;
|
||||
/** get an EAS channel owned by the app by channelName */
|
||||
updateChannelByChannelName: UpdateChannel;
|
||||
/** get an EAS channel owned by the app by name */
|
||||
updateChannelByName: UpdateChannel;
|
||||
/** EAS branches owned by an app */
|
||||
updateBranches: Array<UpdateBranch>;
|
||||
/** get an EAS branch owned by the app by branchName */
|
||||
updateBranchByBranchName: UpdateBranch;
|
||||
/** get an EAS branch owned by the app by name */
|
||||
updateBranchByName: UpdateBranch;
|
||||
/** Coalesced project activity for an app. Use "createdBefore" to offset a query. */
|
||||
activityTimelineProjectActivities: Array<ActivityTimelineProjectActivity>;
|
||||
/** Environment secrets for an app */
|
||||
environmentSecrets: Array<EnvironmentSecret>;
|
||||
};
|
||||
|
||||
|
||||
@@ -458,8 +471,8 @@ export type AppUpdateChannelsArgs = {
|
||||
|
||||
|
||||
/** Represents an Exponent App (or Experience in legacy terms) */
|
||||
export type AppUpdateChannelByChannelNameArgs = {
|
||||
channelName: Scalars['String'];
|
||||
export type AppUpdateChannelByNameArgs = {
|
||||
name: Scalars['String'];
|
||||
};
|
||||
|
||||
|
||||
@@ -471,8 +484,8 @@ export type AppUpdateBranchesArgs = {
|
||||
|
||||
|
||||
/** Represents an Exponent App (or Experience in legacy terms) */
|
||||
export type AppUpdateBranchByBranchNameArgs = {
|
||||
branchName: Scalars['String'];
|
||||
export type AppUpdateBranchByNameArgs = {
|
||||
name: Scalars['String'];
|
||||
};
|
||||
|
||||
|
||||
@@ -482,6 +495,12 @@ export type AppActivityTimelineProjectActivitiesArgs = {
|
||||
createdBefore?: Maybe<Scalars['DateTime']>;
|
||||
};
|
||||
|
||||
|
||||
/** Represents an Exponent App (or Experience in legacy terms) */
|
||||
export type AppEnvironmentSecretsArgs = {
|
||||
filterNames?: Maybe<Array<Scalars['String']>>;
|
||||
};
|
||||
|
||||
export type AppIcon = {
|
||||
__typename?: 'AppIcon';
|
||||
url: Scalars['String'];
|
||||
@@ -730,7 +749,8 @@ export type BuildMetrics = {
|
||||
|
||||
export enum DistributionType {
|
||||
Store = 'STORE',
|
||||
Internal = 'INTERNAL'
|
||||
Internal = 'INTERNAL',
|
||||
Simulator = 'SIMULATOR'
|
||||
}
|
||||
|
||||
/** Represents an Standalone App build job */
|
||||
@@ -1011,7 +1031,7 @@ export type UpdateChannel = {
|
||||
__typename?: 'UpdateChannel';
|
||||
id: Scalars['ID'];
|
||||
appId: Scalars['ID'];
|
||||
channelName: Scalars['String'];
|
||||
name: Scalars['String'];
|
||||
branchMapping: Scalars['String'];
|
||||
createdAt: Scalars['DateTime'];
|
||||
updatedAt: Scalars['DateTime'];
|
||||
@@ -1028,7 +1048,7 @@ export type UpdateBranch = {
|
||||
__typename?: 'UpdateBranch';
|
||||
id: Scalars['ID'];
|
||||
appId: Scalars['ID'];
|
||||
branchName: Scalars['String'];
|
||||
name: Scalars['String'];
|
||||
createdAt: Scalars['DateTime'];
|
||||
updatedAt: Scalars['DateTime'];
|
||||
updates: Array<Update>;
|
||||
@@ -1049,11 +1069,19 @@ export type Update = ActivityTimelineProjectActivity & {
|
||||
platform: Scalars['String'];
|
||||
manifestFragment: Scalars['String'];
|
||||
runtimeVersion: Scalars['String'];
|
||||
updateGroup: Scalars['String'];
|
||||
group: Scalars['String'];
|
||||
updatedAt: Scalars['DateTime'];
|
||||
createdAt: Scalars['DateTime'];
|
||||
updateMessage?: Maybe<Scalars['String']>;
|
||||
branchName: Scalars['String'];
|
||||
message?: Maybe<Scalars['String']>;
|
||||
branch: UpdateBranch;
|
||||
};
|
||||
|
||||
export type EnvironmentSecret = {
|
||||
__typename?: 'EnvironmentSecret';
|
||||
id: Scalars['ID'];
|
||||
name: Scalars['String'];
|
||||
createdAt: Scalars['DateTime'];
|
||||
updatedAt: Scalars['DateTime'];
|
||||
};
|
||||
|
||||
export type UserPermission = {
|
||||
@@ -1475,6 +1503,8 @@ export type RootMutation = {
|
||||
me?: Maybe<MeMutation>;
|
||||
/** Mutations that modify an EmailSubscription */
|
||||
emailSubscription: EmailSubscriptionMutation;
|
||||
/** Mutations that create and delete EnvironmentSecrets */
|
||||
environmentSecret: EnvironmentSecretMutation;
|
||||
};
|
||||
|
||||
|
||||
@@ -2201,7 +2231,7 @@ export type UpdateChannelMutation = {
|
||||
|
||||
export type UpdateChannelMutationCreateUpdateChannelForAppArgs = {
|
||||
appId: Scalars['ID'];
|
||||
channelName: Scalars['String'];
|
||||
name: Scalars['String'];
|
||||
branchMapping?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
@@ -2243,7 +2273,7 @@ export type UpdateBranchMutation = {
|
||||
createUpdateBranchForApp?: Maybe<UpdateBranch>;
|
||||
/**
|
||||
* Edit an EAS branch. The branch can be specified either by its ID or
|
||||
* with the combination of (appId, branchName).
|
||||
* with the combination of (appId, name).
|
||||
*/
|
||||
editUpdateBranch: UpdateBranch;
|
||||
/** Delete an EAS branch and all of its updates as long as the branch is not being used by any channels */
|
||||
@@ -2255,7 +2285,7 @@ export type UpdateBranchMutation = {
|
||||
|
||||
export type UpdateBranchMutationCreateUpdateBranchForAppArgs = {
|
||||
appId: Scalars['ID'];
|
||||
branchName: Scalars['String'];
|
||||
name: Scalars['String'];
|
||||
};
|
||||
|
||||
|
||||
@@ -2276,8 +2306,8 @@ export type UpdateBranchMutationPublishUpdateGroupArgs = {
|
||||
export type EditUpdateBranchInput = {
|
||||
id?: Maybe<Scalars['ID']>;
|
||||
appId?: Maybe<Scalars['ID']>;
|
||||
branchName?: Maybe<Scalars['String']>;
|
||||
newBranchName: Scalars['String'];
|
||||
name?: Maybe<Scalars['String']>;
|
||||
newName: Scalars['String'];
|
||||
};
|
||||
|
||||
export type DeleteUpdateBranchResult = {
|
||||
@@ -2289,7 +2319,7 @@ export type PublishUpdateGroupInput = {
|
||||
branchId: Scalars['String'];
|
||||
updateInfoGroup: UpdateInfoGroup;
|
||||
runtimeVersion: Scalars['String'];
|
||||
updateMessage?: Maybe<Scalars['String']>;
|
||||
message?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type UpdateInfoGroup = {
|
||||
@@ -2304,7 +2334,7 @@ export type PartialManifest = {
|
||||
};
|
||||
|
||||
export type PartialManifestAsset = {
|
||||
fileHash: Scalars['String'];
|
||||
fileSHA256: Scalars['String'];
|
||||
bundleKey: Scalars['String'];
|
||||
contentType: Scalars['String'];
|
||||
storageBucket: Scalars['String'];
|
||||
@@ -2598,6 +2628,43 @@ export type MailchimpTagPayload = {
|
||||
name?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type EnvironmentSecretMutation = {
|
||||
__typename?: 'EnvironmentSecretMutation';
|
||||
/** Create an environment secret for an Account */
|
||||
createEnvironmentSecretForAccount: EnvironmentSecret;
|
||||
/** Create an environment secret for an App */
|
||||
createEnvironmentSecretForApp: EnvironmentSecret;
|
||||
/** Delete an environment secret */
|
||||
deleteEnvironmentSecret: DeleteEnvironmentSecretResult;
|
||||
};
|
||||
|
||||
|
||||
export type EnvironmentSecretMutationCreateEnvironmentSecretForAccountArgs = {
|
||||
environmentSecretData?: Maybe<CreateEnvironmentSecretInput>;
|
||||
accountId: Scalars['String'];
|
||||
};
|
||||
|
||||
|
||||
export type EnvironmentSecretMutationCreateEnvironmentSecretForAppArgs = {
|
||||
environmentSecretData?: Maybe<CreateEnvironmentSecretInput>;
|
||||
appId: Scalars['String'];
|
||||
};
|
||||
|
||||
|
||||
export type EnvironmentSecretMutationDeleteEnvironmentSecretArgs = {
|
||||
id: Scalars['String'];
|
||||
};
|
||||
|
||||
export type CreateEnvironmentSecretInput = {
|
||||
name: Scalars['String'];
|
||||
value: Scalars['String'];
|
||||
};
|
||||
|
||||
export type DeleteEnvironmentSecretResult = {
|
||||
__typename?: 'DeleteEnvironmentSecretResult';
|
||||
id: Scalars['ID'];
|
||||
};
|
||||
|
||||
export type BaseSearchResult = SearchResult & {
|
||||
__typename?: 'BaseSearchResult';
|
||||
/** @deprecated Use SearchResult instead */
|
||||
@@ -3248,6 +3315,45 @@ export type CommonIosAppCredentialsWithBuildCredentialsByAppIdentifierIdQuery =
|
||||
)> }
|
||||
);
|
||||
|
||||
export type CreateUpdateChannelForAppMutationVariables = Exact<{
|
||||
appId: Scalars['ID'];
|
||||
name: Scalars['String'];
|
||||
branchMapping: Scalars['String'];
|
||||
}>;
|
||||
|
||||
|
||||
export type CreateUpdateChannelForAppMutation = (
|
||||
{ __typename?: 'RootMutation' }
|
||||
& { updateChannel: (
|
||||
{ __typename?: 'UpdateChannelMutation' }
|
||||
& { createUpdateChannelForApp?: Maybe<(
|
||||
{ __typename?: 'UpdateChannel' }
|
||||
& Pick<UpdateChannel, 'id' | 'name' | 'branchMapping'>
|
||||
)> }
|
||||
) }
|
||||
);
|
||||
|
||||
export type UpdateChannelBranchMappingMutationVariables = Exact<{
|
||||
channelId: Scalars['ID'];
|
||||
branchMapping: Scalars['String'];
|
||||
}>;
|
||||
|
||||
|
||||
export type UpdateChannelBranchMappingMutation = (
|
||||
{ __typename?: 'RootMutation' }
|
||||
& { updateChannel: (
|
||||
{ __typename?: 'UpdateChannelMutation' }
|
||||
& { editUpdateChannel?: Maybe<(
|
||||
{ __typename?: 'UpdateChannel' }
|
||||
& Pick<UpdateChannel, 'id' | 'name' | 'createdAt' | 'branchMapping'>
|
||||
& { updateBranches: Array<(
|
||||
{ __typename?: 'UpdateBranch' }
|
||||
& Pick<UpdateBranch, 'id' | 'name'>
|
||||
)> }
|
||||
)> }
|
||||
) }
|
||||
);
|
||||
|
||||
export type GetSignedUploadMutationVariables = Exact<{
|
||||
contentTypes: Array<Scalars['String']>;
|
||||
}>;
|
||||
@@ -3275,7 +3381,7 @@ export type UpdatePublishMutation = (
|
||||
{ __typename?: 'UpdateBranchMutation' }
|
||||
& { publishUpdateGroup: Array<Maybe<(
|
||||
{ __typename?: 'Update' }
|
||||
& Pick<Update, 'id' | 'updateGroup'>
|
||||
& Pick<Update, 'id' | 'group'>
|
||||
)>> }
|
||||
) }
|
||||
);
|
||||
@@ -3348,6 +3454,79 @@ export type PendingBuildsForAccountAndPlatformQuery = (
|
||||
) }
|
||||
);
|
||||
|
||||
export type GetChannelByNameForApp123213QueryVariables = Exact<{
|
||||
appId: Scalars['String'];
|
||||
name: Scalars['String'];
|
||||
}>;
|
||||
|
||||
|
||||
export type GetChannelByNameForApp123213Query = (
|
||||
{ __typename?: 'RootQuery' }
|
||||
& { app?: Maybe<(
|
||||
{ __typename?: 'AppQuery' }
|
||||
& { byId: (
|
||||
{ __typename?: 'App' }
|
||||
& Pick<App, 'id' | 'name'>
|
||||
& { updateChannelByName: (
|
||||
{ __typename?: 'UpdateChannel' }
|
||||
& Pick<UpdateChannel, 'id' | 'name' | 'createdAt'>
|
||||
& { updateBranches: Array<(
|
||||
{ __typename?: 'UpdateBranch' }
|
||||
& Pick<UpdateBranch, 'id' | 'name'>
|
||||
& { updates: Array<(
|
||||
{ __typename?: 'Update' }
|
||||
& Pick<Update, 'id' | 'group' | 'message' | 'createdAt'>
|
||||
& { actor?: Maybe<(
|
||||
{ __typename?: 'User' }
|
||||
& Pick<User, 'firstName' | 'id'>
|
||||
) | (
|
||||
{ __typename?: 'Robot' }
|
||||
& Pick<Robot, 'firstName' | 'id'>
|
||||
)> }
|
||||
)> }
|
||||
)> }
|
||||
) }
|
||||
) }
|
||||
)> }
|
||||
);
|
||||
|
||||
export type ListChannelsForAppQueryVariables = Exact<{
|
||||
appId: Scalars['String'];
|
||||
offset: Scalars['Int'];
|
||||
limit: Scalars['Int'];
|
||||
}>;
|
||||
|
||||
|
||||
export type ListChannelsForAppQuery = (
|
||||
{ __typename?: 'RootQuery' }
|
||||
& { app?: Maybe<(
|
||||
{ __typename?: 'AppQuery' }
|
||||
& { byId: (
|
||||
{ __typename?: 'App' }
|
||||
& Pick<App, 'id' | 'name'>
|
||||
& { updateChannels: Array<(
|
||||
{ __typename?: 'UpdateChannel' }
|
||||
& Pick<UpdateChannel, 'id' | 'name'>
|
||||
& { updateBranches: Array<(
|
||||
{ __typename?: 'UpdateBranch' }
|
||||
& Pick<UpdateBranch, 'id' | 'name'>
|
||||
& { updates: Array<(
|
||||
{ __typename?: 'Update' }
|
||||
& Pick<Update, 'id' | 'group' | 'message' | 'createdAt'>
|
||||
& { actor?: Maybe<(
|
||||
{ __typename?: 'User' }
|
||||
& Pick<User, 'firstName' | 'id'>
|
||||
) | (
|
||||
{ __typename?: 'Robot' }
|
||||
& Pick<Robot, 'firstName' | 'id'>
|
||||
)> }
|
||||
)> }
|
||||
)> }
|
||||
)> }
|
||||
) }
|
||||
)> }
|
||||
);
|
||||
|
||||
export type ProjectByUsernameAndSlugQueryVariables = Exact<{
|
||||
username: Scalars['String'];
|
||||
slug: Scalars['String'];
|
||||
|
||||
@@ -31,7 +31,7 @@ const PublishMutation = {
|
||||
|
||||
async publishUpdateGroupAsync(
|
||||
publishUpdateGroupInput: PublishUpdateGroupInput
|
||||
): Promise<Pick<Update, 'id' | 'updateGroup'>> {
|
||||
): Promise<Pick<Update, 'id' | 'group'>> {
|
||||
const data = await withErrorHandlingAsync(
|
||||
graphqlClient
|
||||
.mutation<UpdatePublishMutation>(
|
||||
@@ -40,7 +40,7 @@ const PublishMutation = {
|
||||
updateBranch {
|
||||
publishUpdateGroup(publishUpdateGroupInput: $publishUpdateGroupInput) {
|
||||
id
|
||||
updateGroup
|
||||
group
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ describe(convertAssetToUpdateInfoGroupFormatAsync, () => {
|
||||
await expect(convertAssetToUpdateInfoGroupFormatAsync(asset)).resolves.toEqual({
|
||||
bundleKey: `c939e759656f577c058f445bfb19182e.${type}`,
|
||||
contentType: 'image/jpeg',
|
||||
fileHash: 'tzD6J-OQZaHCKnL3GHWV9RbnrpyojnagiOE7r3mSkU4',
|
||||
fileSHA256: 'tzD6J-OQZaHCKnL3GHWV9RbnrpyojnagiOE7r3mSkU4',
|
||||
storageBucket: 'update-assets-production',
|
||||
storageKey: 'fo8Y08LktVk6qLtGbn8GRWpOUyD13ABMUnbtRCN1L7Y',
|
||||
});
|
||||
@@ -177,7 +177,7 @@ describe(buildUpdateInfoGroupAsync, () => {
|
||||
{
|
||||
bundleKey: 'c939e759656f577c058f445bfb19182e.jpg',
|
||||
contentType: 'image/jpeg',
|
||||
fileHash: 'tzD6J-OQZaHCKnL3GHWV9RbnrpyojnagiOE7r3mSkU4',
|
||||
fileSHA256: 'tzD6J-OQZaHCKnL3GHWV9RbnrpyojnagiOE7r3mSkU4',
|
||||
storageBucket: 'update-assets-production',
|
||||
storageKey: 'fo8Y08LktVk6qLtGbn8GRWpOUyD13ABMUnbtRCN1L7Y',
|
||||
},
|
||||
@@ -186,7 +186,7 @@ describe(buildUpdateInfoGroupAsync, () => {
|
||||
launchAsset: {
|
||||
bundleKey: 'ec0dd14670aae108f99a810df9c1482c.bundle',
|
||||
contentType: 'bundle/javascript',
|
||||
fileHash: 'KEw79FnKTLOyVbRT1SlohSTjPe5e8FpULy2ST-I5BUg',
|
||||
fileSHA256: 'KEw79FnKTLOyVbRT1SlohSTjPe5e8FpULy2ST-I5BUg',
|
||||
storageBucket: 'update-assets-production',
|
||||
storageKey: 'aC9N6RZlcHoIYjIsoJd2KUcigBKy98RHvZacDyPNjCQ',
|
||||
},
|
||||
@@ -206,7 +206,9 @@ describe(resolveInputDirectory, () => {
|
||||
expect(() => {
|
||||
resolveInputDirectory(nonExistentPath);
|
||||
}).toThrow(`The input directory "${nonExistentPath}" does not exist.
|
||||
You'll need to run a command to build the JS bundle first (e.g. 'expo export').
|
||||
You can allow us to build it for you by not setting the --skip-bundler flag.
|
||||
If you chose to build it yourself you'll need to run a command to build the JS
|
||||
bundle first.
|
||||
You can use '--input-dir' to specify a different input directory.`);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -71,7 +71,7 @@ export async function getAppIdentifierAsync(
|
||||
): Promise<string | null> {
|
||||
const { exp } = getConfig(projectDir, { skipSDKVersionRequirement: true });
|
||||
switch (platform) {
|
||||
case Platform.Android: {
|
||||
case Platform.ANDROID: {
|
||||
const packageNameFromConfig = AndroidConfig.Package.getPackage(exp);
|
||||
if (packageNameFromConfig) {
|
||||
return packageNameFromConfig;
|
||||
@@ -80,7 +80,7 @@ export async function getAppIdentifierAsync(
|
||||
? await getAndroidApplicationIdAsync(projectDir)
|
||||
: null;
|
||||
}
|
||||
case Platform.iOS: {
|
||||
case Platform.IOS: {
|
||||
return (
|
||||
IOSConfig.BundleIdentifier.getBundleIdentifier(exp) ??
|
||||
IOSConfig.BundleIdentifier.getBundleIdentifierFromPbxproj(projectDir)
|
||||
@@ -96,7 +96,7 @@ export async function ensureAppIdentifierIsDefinedAsync(
|
||||
const appIdentifier = await getAppIdentifierAsync(projectDir, platform);
|
||||
if (!appIdentifier) {
|
||||
const desc = getProjectConfigDescription(projectDir);
|
||||
const fieldStr = platform === Platform.Android ? 'android.package' : 'ios.bundleIdentifier';
|
||||
const fieldStr = platform === Platform.ANDROID ? 'android.package' : 'ios.bundleIdentifier';
|
||||
throw new Error(`Please define "${fieldStr}" in your ${desc}.`);
|
||||
}
|
||||
return appIdentifier;
|
||||
@@ -125,10 +125,10 @@ export function getProjectConfigDescription(projectDir: string): string {
|
||||
|
||||
export async function getBranchByNameAsync({
|
||||
appId,
|
||||
branchName,
|
||||
name,
|
||||
}: {
|
||||
appId: string;
|
||||
branchName: string;
|
||||
name: string;
|
||||
}): Promise<UpdateBranch> {
|
||||
const data = await withErrorHandlingAsync(
|
||||
graphqlClient
|
||||
@@ -136,23 +136,23 @@ export async function getBranchByNameAsync({
|
||||
{
|
||||
app: {
|
||||
byId: {
|
||||
updateBranchByBranchName: UpdateBranch;
|
||||
updateBranchByName: UpdateBranch;
|
||||
};
|
||||
};
|
||||
},
|
||||
{
|
||||
appId: string;
|
||||
branchName: string;
|
||||
name: string;
|
||||
}
|
||||
>(
|
||||
gql`
|
||||
query ViewBranch($appId: String!, $branchName: String!) {
|
||||
query ViewBranch($appId: String!, $name: String!) {
|
||||
app {
|
||||
byId(appId: $appId) {
|
||||
id
|
||||
updateBranchByBranchName(branchName: $branchName) {
|
||||
updateBranchByName(name: $name) {
|
||||
id
|
||||
branchName
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,10 +160,10 @@ export async function getBranchByNameAsync({
|
||||
`,
|
||||
{
|
||||
appId,
|
||||
branchName,
|
||||
name,
|
||||
}
|
||||
)
|
||||
.toPromise()
|
||||
);
|
||||
return data.app.byId.updateBranchByBranchName;
|
||||
return data.app.byId.updateBranchByName;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Platform } from '@expo/config';
|
||||
import JsonFile from '@expo/json-file';
|
||||
import spawnAsync from '@expo/spawn-async';
|
||||
import Joi from '@hapi/joi';
|
||||
import crypto from 'crypto';
|
||||
import fs from 'fs';
|
||||
@@ -10,6 +11,7 @@ import path from 'path';
|
||||
import { AssetMetadataStatus, PartialManifestAsset } from '../graphql/generated';
|
||||
import { PublishMutation } from '../graphql/mutations/PublishMutation';
|
||||
import { PublishQuery } from '../graphql/queries/PublishQuery';
|
||||
import Log from '../log';
|
||||
import { PresignedPost, uploadWithPresignedPostAsync } from '../uploads';
|
||||
|
||||
export const TIMEOUT_LIMIT = 60_000; // 1 minute
|
||||
@@ -102,23 +104,23 @@ async function calculateFileHashAsync(filePath: string, algorithm: string): Prom
|
||||
* Convenience function that computes an assets storage key starting from its buffer.
|
||||
*/
|
||||
export async function getStorageKeyForAssetAsync(asset: RawAsset): Promise<string> {
|
||||
const fileHash = getBase64URLEncoding(await calculateFileHashAsync(asset.path, 'sha256'));
|
||||
return getStorageKey(asset.contentType, fileHash);
|
||||
const fileSHA256 = getBase64URLEncoding(await calculateFileHashAsync(asset.path, 'sha256'));
|
||||
return getStorageKey(asset.contentType, fileSHA256);
|
||||
}
|
||||
|
||||
export async function convertAssetToUpdateInfoGroupFormatAsync(
|
||||
asset: RawAsset
|
||||
): Promise<PartialManifestAsset> {
|
||||
const fileHash = getBase64URLEncoding(await calculateFileHashAsync(asset.path, 'sha256'));
|
||||
const fileSHA256 = getBase64URLEncoding(await calculateFileHashAsync(asset.path, 'sha256'));
|
||||
const contentType = asset.contentType;
|
||||
const storageKey = getStorageKey(contentType, fileHash);
|
||||
const storageKey = getStorageKey(contentType, fileSHA256);
|
||||
const bundleKey = [
|
||||
(await calculateFileHashAsync(asset.path, 'md5')).toString('hex'),
|
||||
asset.type,
|
||||
].join('.');
|
||||
|
||||
return {
|
||||
fileHash,
|
||||
fileSHA256,
|
||||
contentType,
|
||||
storageBucket: STORAGE_BUCKET,
|
||||
storageKey,
|
||||
@@ -140,11 +142,50 @@ export async function buildUpdateInfoGroupAsync(assets: CollectedAssets): Promis
|
||||
return updateInfoGroup as UpdateInfoGroup;
|
||||
}
|
||||
|
||||
export async function buildBundlesAsync({
|
||||
projectDir,
|
||||
inputDir,
|
||||
}: {
|
||||
projectDir: string;
|
||||
inputDir: string;
|
||||
}) {
|
||||
const packageJSON = JsonFile.read(path.resolve(projectDir, 'package.json'));
|
||||
if (!packageJSON) {
|
||||
throw new Error('Could not locate package.json');
|
||||
}
|
||||
|
||||
Log.withTick(`Building bundle with expo-cli...`);
|
||||
const spawnPromise = spawnAsync(
|
||||
'yarn',
|
||||
['expo', 'export', '--output-dir', inputDir, '--experimental-bundle', '--force'],
|
||||
{ stdio: ['inherit', 'pipe', 'pipe'] } // inherit stdin so user can install a missing expo-cli from inside this command
|
||||
);
|
||||
const {
|
||||
child: { stdout, stderr },
|
||||
} = spawnPromise;
|
||||
if (!(stdout && stderr)) {
|
||||
throw new Error('Failed to spawn expo-cli');
|
||||
}
|
||||
stdout.on('data', data => {
|
||||
for (const line of data.toString().trim().split('\n')) {
|
||||
Log.log(`[expo-cli]${line}`);
|
||||
}
|
||||
});
|
||||
stderr.on('data', data => {
|
||||
for (const line of data.toString().trim().split('\n')) {
|
||||
Log.warn(`[expo-cli]${line}`);
|
||||
}
|
||||
});
|
||||
await spawnPromise;
|
||||
}
|
||||
|
||||
export function resolveInputDirectory(customInputDirectory: string): string {
|
||||
const distRoot = path.resolve(customInputDirectory);
|
||||
if (!fs.existsSync(distRoot)) {
|
||||
throw new Error(`The input directory "${customInputDirectory}" does not exist.
|
||||
You'll need to run a command to build the JS bundle first (e.g. 'expo export').
|
||||
You can allow us to build it for you by not setting the --skip-bundler flag.
|
||||
If you chose to build it yourself you'll need to run a command to build the JS
|
||||
bundle first.
|
||||
You can use '--input-dir' to specify a different input directory.`);
|
||||
}
|
||||
return distRoot;
|
||||
|
||||
@@ -85,7 +85,7 @@ export async function pressAnyKeyToContinueAsync() {
|
||||
process.stdin.resume();
|
||||
process.stdin.setEncoding('utf8');
|
||||
|
||||
await new Promise(res => {
|
||||
await new Promise<void>(res => {
|
||||
process.stdin.on('data', key => {
|
||||
if (String(key) === '\u0003') {
|
||||
process.exit(constants.signals.SIGINT + 128); // ctrl-c
|
||||
|
||||
@@ -39,7 +39,7 @@ export async function ensureAppStoreConnectAppExistsAsync(
|
||||
const { bundleIdentifier, appName, language } = ctx.commandFlags;
|
||||
|
||||
const resolvedBundleId =
|
||||
bundleIdentifier ?? (await getAppIdentifierAsync(ctx.projectDir, Platform.iOS));
|
||||
bundleIdentifier ?? (await getAppIdentifierAsync(ctx.projectDir, Platform.IOS));
|
||||
if (!resolvedBundleId) {
|
||||
throw new Error(
|
||||
`Please define "expo.ios.bundleIdentifier" in your app config or provide it using --bundle-identifier param.
|
||||
|
||||
@@ -26,7 +26,7 @@ async function moveFileOfTypeAsync(
|
||||
extension: string,
|
||||
dest: string
|
||||
): Promise<string> {
|
||||
const [matching] = await glob(`*.${extension}`, {
|
||||
const [matching] = await glob(`**/*.${extension}`, {
|
||||
absolute: true,
|
||||
cwd: directory,
|
||||
});
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "@expo/eas-json",
|
||||
"description": "A library for interacting with the eas.json",
|
||||
"version": "0.4.0",
|
||||
"version": "0.5.0",
|
||||
"author": "Expo <[email protected]>",
|
||||
"bugs": "https://github.com/expo/eas-cli/issues",
|
||||
"dependencies": {
|
||||
"@expo/eas-build-job": "0.2.10",
|
||||
"@expo/eas-build-job": "0.2.14",
|
||||
"@hapi/joi": "^17.1.1",
|
||||
"fs-extra": "^9.0.1",
|
||||
"tslib": "^1"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Android, Workflow, iOS } from '@expo/eas-build-job';
|
||||
import { Android, Cache, Ios, Workflow } from '@expo/eas-build-job';
|
||||
|
||||
export enum CredentialsSource {
|
||||
LOCAL = 'local',
|
||||
@@ -6,49 +6,52 @@ export enum CredentialsSource {
|
||||
AUTO = 'auto',
|
||||
}
|
||||
|
||||
export enum DistributionType {
|
||||
STORE = 'store',
|
||||
INTERNAL = 'internal',
|
||||
}
|
||||
export type AndroidDistributionType = 'store' | 'internal';
|
||||
export type iOSDistributionType = 'store' | 'internal' | 'simulator';
|
||||
export type DistributionType = AndroidDistributionType | iOSDistributionType;
|
||||
|
||||
export type VersionAutoIncrement = boolean | 'version' | 'buildNumber';
|
||||
|
||||
export interface AndroidManagedBuildProfile extends Android.BuilderEnvironment {
|
||||
workflow: Workflow.Managed;
|
||||
workflow: Workflow.MANAGED;
|
||||
credentialsSource: CredentialsSource;
|
||||
buildType?: Android.ManagedBuildType;
|
||||
releaseChannel?: string;
|
||||
distribution?: DistributionType;
|
||||
distribution?: AndroidDistributionType;
|
||||
cache: Cache | null;
|
||||
}
|
||||
|
||||
export interface AndroidGenericBuildProfile extends Android.BuilderEnvironment {
|
||||
workflow: Workflow.Generic;
|
||||
workflow: Workflow.GENERIC;
|
||||
credentialsSource: CredentialsSource;
|
||||
gradleCommand?: string;
|
||||
releaseChannel?: string;
|
||||
artifactPath?: string;
|
||||
withoutCredentials?: boolean;
|
||||
distribution?: DistributionType;
|
||||
distribution?: AndroidDistributionType;
|
||||
cache: Cache | null;
|
||||
}
|
||||
|
||||
export interface iOSManagedBuildProfile extends iOS.BuilderEnvironment {
|
||||
workflow: Workflow.Managed;
|
||||
export interface iOSManagedBuildProfile extends Ios.BuilderEnvironment {
|
||||
workflow: Workflow.MANAGED;
|
||||
credentialsSource: CredentialsSource;
|
||||
buildType?: iOS.ManagedBuildType;
|
||||
buildType?: Ios.ManagedBuildType;
|
||||
releaseChannel?: string;
|
||||
distribution?: DistributionType;
|
||||
distribution?: iOSDistributionType;
|
||||
autoIncrement: VersionAutoIncrement;
|
||||
cache: Cache | null;
|
||||
}
|
||||
|
||||
export interface iOSGenericBuildProfile extends iOS.BuilderEnvironment {
|
||||
workflow: Workflow.Generic;
|
||||
export interface iOSGenericBuildProfile extends Ios.BuilderEnvironment {
|
||||
workflow: Workflow.GENERIC;
|
||||
credentialsSource: CredentialsSource;
|
||||
scheme?: string;
|
||||
schemeBuildConfiguration?: iOS.GenericSchemeBuildConfiguration;
|
||||
schemeBuildConfiguration?: Ios.SchemeBuildConfiguration;
|
||||
releaseChannel?: string;
|
||||
artifactPath?: string;
|
||||
distribution?: DistributionType;
|
||||
distribution?: iOSDistributionType;
|
||||
autoIncrement: VersionAutoIncrement;
|
||||
cache: Cache | null;
|
||||
}
|
||||
|
||||
export type AndroidBuildProfile = AndroidManagedBuildProfile | AndroidGenericBuildProfile;
|
||||
|
||||
@@ -26,7 +26,7 @@ export class EasJsonReader {
|
||||
let androidConfig;
|
||||
if (['android', 'all'].includes(this.platform)) {
|
||||
androidConfig = this.validateBuildProfile<AndroidBuildProfile>(
|
||||
Platform.Android,
|
||||
Platform.ANDROID,
|
||||
buildProfileName,
|
||||
easJson.builds?.android || {}
|
||||
);
|
||||
@@ -34,7 +34,7 @@ export class EasJsonReader {
|
||||
let iosConfig;
|
||||
if (['ios', 'all'].includes(this.platform)) {
|
||||
iosConfig = this.validateBuildProfile<iOSBuildProfile>(
|
||||
Platform.iOS,
|
||||
Platform.IOS,
|
||||
buildProfileName,
|
||||
easJson.builds?.ios || {}
|
||||
);
|
||||
@@ -53,8 +53,8 @@ export class EasJsonReader {
|
||||
const androidProfiles = easJson.builds?.android ?? {};
|
||||
for (const name of Object.keys(androidProfiles)) {
|
||||
try {
|
||||
if (this.isWorkflowKeySpecified(Platform.Android, name, androidProfiles)) {
|
||||
await this.validateBuildProfile(Platform.Android, name, androidProfiles);
|
||||
if (this.isWorkflowKeySpecified(Platform.ANDROID, name, androidProfiles)) {
|
||||
await this.validateBuildProfile(Platform.ANDROID, name, androidProfiles);
|
||||
}
|
||||
} catch (err) {
|
||||
err.msg = `Failed to validate Android build profile "${name}"\n${err.msg}`;
|
||||
@@ -64,8 +64,8 @@ export class EasJsonReader {
|
||||
const iosProfiles = easJson.builds?.ios ?? {};
|
||||
for (const name of Object.keys(iosProfiles)) {
|
||||
try {
|
||||
if (this.isWorkflowKeySpecified(Platform.iOS, name, iosProfiles)) {
|
||||
await this.validateBuildProfile(Platform.iOS, name, iosProfiles);
|
||||
if (this.isWorkflowKeySpecified(Platform.IOS, name, iosProfiles)) {
|
||||
await this.validateBuildProfile(Platform.IOS, name, iosProfiles);
|
||||
}
|
||||
} catch (err) {
|
||||
err.msg = `Failed to validate iOS build profile "${name}"\n${err.msg}`;
|
||||
@@ -94,7 +94,7 @@ export class EasJsonReader {
|
||||
buildProfiles: Record<string, BuildProfilePreValidation>
|
||||
): T {
|
||||
const buildProfile = this.resolveBuildProfile(platform, buildProfileName, buildProfiles);
|
||||
if (![Workflow.Generic, Workflow.Managed].includes(buildProfile.workflow)) {
|
||||
if (![Workflow.GENERIC, Workflow.MANAGED].includes(buildProfile.workflow)) {
|
||||
throw new Error(
|
||||
'"workflow" key is required in a build profile and has to be one of ["generic", "managed"].'
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Android, iOS } from '@expo/eas-build-job';
|
||||
import { Android, Ios } from '@expo/eas-build-job';
|
||||
import Joi, { CustomHelpers } from '@hapi/joi';
|
||||
|
||||
const semverSchemaCheck = (value: any, helpers: CustomHelpers) => {
|
||||
@@ -13,21 +13,27 @@ const AndroidBuilderEnvironmentSchema = Joi.object({
|
||||
image: Joi.string()
|
||||
.valid(...Android.builderBaseImages)
|
||||
.default('default'),
|
||||
node: Joi.string().custom(semverSchemaCheck),
|
||||
yarn: Joi.string().custom(semverSchemaCheck),
|
||||
ndk: Joi.string(),
|
||||
env: Joi.object().pattern(Joi.string(), Joi.string()).default({}),
|
||||
node: Joi.string().empty(null).custom(semverSchemaCheck),
|
||||
yarn: Joi.string().empty(null).custom(semverSchemaCheck),
|
||||
ndk: Joi.string().empty(null).custom(semverSchemaCheck),
|
||||
env: Joi.object().pattern(Joi.string(), Joi.string().empty(null)).default({}),
|
||||
});
|
||||
|
||||
const IosBuilderEnvironmentSchema = Joi.object({
|
||||
image: Joi.string()
|
||||
.valid(...iOS.builderBaseImages)
|
||||
.valid(...Ios.builderBaseImages)
|
||||
.default('default'),
|
||||
node: Joi.string().custom(semverSchemaCheck),
|
||||
yarn: Joi.string().custom(semverSchemaCheck),
|
||||
fastlane: Joi.string().custom(semverSchemaCheck),
|
||||
cocoapods: Joi.string().custom(semverSchemaCheck),
|
||||
env: Joi.object().pattern(Joi.string(), Joi.string()).default({}),
|
||||
node: Joi.string().empty(null).custom(semverSchemaCheck),
|
||||
yarn: Joi.string().empty(null).custom(semverSchemaCheck),
|
||||
fastlane: Joi.string().empty(null).custom(semverSchemaCheck),
|
||||
cocoapods: Joi.string().empty(null).custom(semverSchemaCheck),
|
||||
env: Joi.object().pattern(Joi.string(), Joi.string().empty(null)).default({}),
|
||||
});
|
||||
|
||||
const CacheSchema = Joi.object({
|
||||
key: Joi.string().allow('').default('').max(128),
|
||||
cacheDefaultPaths: Joi.boolean().default(true),
|
||||
customPaths: Joi.array().items(Joi.string()).default([]),
|
||||
});
|
||||
|
||||
const AndroidGenericSchema = Joi.object({
|
||||
@@ -40,8 +46,9 @@ const AndroidGenericSchema = Joi.object({
|
||||
}),
|
||||
releaseChannel: Joi.string(),
|
||||
artifactPath: Joi.string(),
|
||||
withoutCredentials: Joi.boolean(),
|
||||
withoutCredentials: Joi.boolean().default(false),
|
||||
distribution: Joi.string().valid('store', 'internal').default('store'),
|
||||
cache: CacheSchema.allow(null).default({ key: '', cacheDefaultPaths: true, customPaths: [] }),
|
||||
}).concat(AndroidBuilderEnvironmentSchema);
|
||||
|
||||
const AndroidManagedSchema = Joi.object({
|
||||
@@ -54,6 +61,7 @@ const AndroidManagedSchema = Joi.object({
|
||||
otherwise: Joi.string().valid('apk', 'app-bundle', 'development-client').default('app-bundle'),
|
||||
}),
|
||||
distribution: Joi.string().valid('store', 'internal').default('store'),
|
||||
cache: CacheSchema.allow(null).default({ key: '', cacheDefaultPaths: true, customPaths: [] }),
|
||||
}).concat(AndroidBuilderEnvironmentSchema);
|
||||
|
||||
const iOSGenericSchema = Joi.object({
|
||||
@@ -63,21 +71,23 @@ const iOSGenericSchema = Joi.object({
|
||||
schemeBuildConfiguration: Joi.string().valid('Debug', 'Release'),
|
||||
releaseChannel: Joi.string(),
|
||||
artifactPath: Joi.string(),
|
||||
distribution: Joi.string().valid('store', 'internal').default('store'),
|
||||
distribution: Joi.string().valid('store', 'internal', 'simulator').default('store'),
|
||||
autoIncrement: Joi.alternatives()
|
||||
.try(Joi.boolean(), Joi.string().valid('version', 'buildNumber'))
|
||||
.default(false),
|
||||
cache: CacheSchema.allow(null).default({ key: '', cacheDefaultPaths: true, customPaths: [] }),
|
||||
}).concat(IosBuilderEnvironmentSchema);
|
||||
|
||||
const iOSManagedSchema = Joi.object({
|
||||
workflow: Joi.string().valid('managed').required(),
|
||||
credentialsSource: Joi.string().valid('local', 'remote', 'auto').default('auto'),
|
||||
buildType: Joi.string().valid('release', 'development-client'),
|
||||
buildType: Joi.string().valid('release', 'development-client').default('release'),
|
||||
releaseChannel: Joi.string(),
|
||||
distribution: Joi.string().valid('store', 'internal').default('store'),
|
||||
distribution: Joi.string().valid('store', 'internal', 'simulator').default('store'),
|
||||
autoIncrement: Joi.alternatives()
|
||||
.try(Joi.boolean(), Joi.string().valid('version', 'buildNumber'))
|
||||
.default(false),
|
||||
cache: CacheSchema.allow(null).default({ key: '', cacheDefaultPaths: true, customPaths: [] }),
|
||||
}).concat(IosBuilderEnvironmentSchema);
|
||||
|
||||
const schemaBuildProfileMap: Record<string, Record<string, Joi.Schema>> = {
|
||||
|
||||
@@ -28,6 +28,8 @@ test('minimal valid android eas.json', async () => {
|
||||
distribution: 'store',
|
||||
credentialsSource: 'auto',
|
||||
env: {},
|
||||
withoutCredentials: false,
|
||||
cache: { key: '', cacheDefaultPaths: true, customPaths: [] },
|
||||
image: 'default',
|
||||
},
|
||||
},
|
||||
@@ -53,6 +55,7 @@ test('minimal valid ios eas.json', async () => {
|
||||
workflow: 'generic',
|
||||
autoIncrement: false,
|
||||
env: {},
|
||||
cache: { key: '', cacheDefaultPaths: true, customPaths: [] },
|
||||
image: 'default',
|
||||
},
|
||||
},
|
||||
@@ -80,6 +83,8 @@ test('minimal valid eas.json for both platforms', async () => {
|
||||
distribution: 'store',
|
||||
credentialsSource: 'auto',
|
||||
env: {},
|
||||
withoutCredentials: false,
|
||||
cache: { key: '', cacheDefaultPaths: true, customPaths: [] },
|
||||
image: 'default',
|
||||
},
|
||||
ios: {
|
||||
@@ -88,6 +93,7 @@ test('minimal valid eas.json for both platforms', async () => {
|
||||
credentialsSource: 'auto',
|
||||
autoIncrement: false,
|
||||
env: {},
|
||||
cache: { key: '', cacheDefaultPaths: true, customPaths: [] },
|
||||
image: 'default',
|
||||
},
|
||||
},
|
||||
@@ -115,6 +121,8 @@ test('valid eas.json with both platform, but reading only android', async () =>
|
||||
distribution: 'store',
|
||||
credentialsSource: 'auto',
|
||||
env: {},
|
||||
withoutCredentials: false,
|
||||
cache: { key: '', cacheDefaultPaths: true, customPaths: [] },
|
||||
image: 'default',
|
||||
},
|
||||
},
|
||||
@@ -148,6 +156,7 @@ test('valid eas.json for development client builds', async () => {
|
||||
distribution: 'store',
|
||||
env: {},
|
||||
image: 'default',
|
||||
cache: { key: '', cacheDefaultPaths: true, customPaths: [] },
|
||||
buildType: 'development-client',
|
||||
},
|
||||
ios: {
|
||||
@@ -157,6 +166,7 @@ test('valid eas.json for development client builds', async () => {
|
||||
autoIncrement: false,
|
||||
env: {},
|
||||
image: 'default',
|
||||
cache: { key: '', cacheDefaultPaths: true, customPaths: [] },
|
||||
buildType: 'development-client',
|
||||
},
|
||||
},
|
||||
@@ -185,6 +195,8 @@ test('valid generic profile for internal distribution on Android', async () => {
|
||||
credentialsSource: 'auto',
|
||||
gradleCommand: ':app:assembleRelease',
|
||||
env: {},
|
||||
withoutCredentials: false,
|
||||
cache: { key: '', cacheDefaultPaths: true, customPaths: [] },
|
||||
image: 'default',
|
||||
},
|
||||
},
|
||||
@@ -213,6 +225,7 @@ test('valid managed profile for internal distribution on Android', async () => {
|
||||
distribution: 'internal',
|
||||
credentialsSource: 'auto',
|
||||
env: {},
|
||||
cache: { key: '', cacheDefaultPaths: true, customPaths: [] },
|
||||
image: 'default',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
export {
|
||||
CredentialsSource,
|
||||
DistributionType,
|
||||
AndroidDistributionType,
|
||||
AndroidManagedBuildProfile,
|
||||
AndroidGenericBuildProfile,
|
||||
AndroidBuildProfile,
|
||||
iOSDistributionType,
|
||||
iOSManagedBuildProfile,
|
||||
iOSGenericBuildProfile,
|
||||
iOSBuildProfile,
|
||||
DistributionType,
|
||||
EasConfig,
|
||||
VersionAutoIncrement,
|
||||
} from './Config.types';
|
||||
|
||||
@@ -1093,15 +1093,15 @@
|
||||
"@babel/preset-env" "^7.4.4"
|
||||
"@babel/preset-typescript" "^7.3.3"
|
||||
|
||||
"@expo/[email protected]8":
|
||||
version "1.0.18"
|
||||
resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-1.0.18.tgz#f0f7d36316d60ea67b4cc6394bffef6d6904345d"
|
||||
integrity sha512-8Ey+22cEAOxK+SBJY+OazaLsPyL5FXdsykfBg/QQJE2Y/DTFebUVlr5bQyeqavbASDvmDxg3Fd71A8Se8+qT1g==
|
||||
"@expo/[email protected]9-alpha.0":
|
||||
version "1.0.19-alpha.0"
|
||||
resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-1.0.19-alpha.0.tgz#3d57c266bfae0c7b310ac99e9949c9d03120c103"
|
||||
integrity sha512-mOPIvi1tanMftgeEjDB4vckLKY5dKdJ80R2cg27YyaP4IS1pYGaHtJKBKb6Pr1w5xvyRxd2AlX6C7L8lEzTBaw==
|
||||
dependencies:
|
||||
"@expo/config-types" "^40.0.0-beta.2"
|
||||
"@expo/configure-splash-screen" "0.3.3"
|
||||
"@expo/configure-splash-screen" "0.3.4"
|
||||
"@expo/image-utils" "0.3.10"
|
||||
"@expo/json-file" "8.2.27"
|
||||
"@expo/json-file" "8.2.28-alpha.0"
|
||||
"@expo/plist" "0.0.11"
|
||||
find-up "~5.0.0"
|
||||
fs-extra "9.0.0"
|
||||
@@ -1135,26 +1135,26 @@
|
||||
semver "^7.1.3"
|
||||
slugify "^1.3.4"
|
||||
|
||||
"@expo/[email protected].3":
|
||||
version "0.3.3"
|
||||
resolved "https://registry.yarnpkg.com/@expo/configure-splash-screen/-/configure-splash-screen-0.3.3.tgz#ef44ba4d62443297f9d8a9326a71b40b8b413528"
|
||||
integrity sha512-fWy6Z52Mj2a7yjdvpIJkP9G3kfkoXE79aHvTDwgggIE0KLhwnPF27v+KS0wJUf7b4JM6w0zKOlUZjQhn0kSNyA==
|
||||
"@expo/[email protected].4":
|
||||
version "0.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@expo/configure-splash-screen/-/configure-splash-screen-0.3.4.tgz#b91d8f08fd96272bd3d7aaa9b51d6189b932c7cc"
|
||||
integrity sha512-HsukM03X5/EXSucVsLN/oLqyFq/1jAjpADkgU1HLaezFpkr+TOquI6yDwdDp1450kcm891PE/SYJ+mCdPxzDLw==
|
||||
dependencies:
|
||||
"@react-native-community/cli-platform-ios" "^4.10.0"
|
||||
color-string "^1.5.3"
|
||||
commander "^5.1.0"
|
||||
core-js "^3.6.5"
|
||||
deep-equal "^2.0.3"
|
||||
fs-extra "^9.0.0"
|
||||
glob "^7.1.6"
|
||||
lodash "^4.17.15"
|
||||
pngjs "^5.0.0"
|
||||
xcode "^3.0.0"
|
||||
xml-js "^1.6.11"
|
||||
|
||||
"@expo/[email protected]0":
|
||||
version "0.2.10"
|
||||
resolved "https://registry.yarnpkg.com/@expo/eas-build-job/-/eas-build-job-0.2.10.tgz#ed6ac5e094e62167c0afeaae929aab6be68b48b4"
|
||||
integrity sha512-AEbMlvbF/ugZFHDuMY9Bpojm8LgZIL7IIES+jevkG1ftzoPpRXP+q1Ioch+KPFdG6SyPrqvGa2NBK5Oyq/MtTA==
|
||||
"@expo/[email protected]4":
|
||||
version "0.2.14"
|
||||
resolved "https://registry.yarnpkg.com/@expo/eas-build-job/-/eas-build-job-0.2.14.tgz#10402f8c2cdd3e8c7ebc6f8773270295e7993771"
|
||||
integrity sha512-+msVy5CgyQwZrUJeiV6hvg3Sjx4Fc1CHDF0jY0LxXSsRDGQDM7qde6ukHRyPvGuGxv/+PzwlWolv2kOP6GFcFQ==
|
||||
dependencies:
|
||||
"@hapi/joi" "^17.1.1"
|
||||
|
||||
@@ -1186,15 +1186,14 @@
|
||||
lodash "^4.17.15"
|
||||
write-file-atomic "^2.3.0"
|
||||
|
||||
"@expo/[email protected]7":
|
||||
version "8.2.27"
|
||||
resolved "https://registry.yarnpkg.com/@expo/json-file/-/json-file-8.2.27.tgz#548ff0a9989f9f789cdb2b689d17a4faf491de67"
|
||||
integrity sha512-Iyqg1jbXOTg0JfCGwMrkaaRmVFjQrWDBQAhYLTdvOD3GrXYuKI1vUV+3Wqw0NnU+TYoNUpi7aB8dNzPvLj0oag==
|
||||
"@expo/[email protected]8-alpha.0":
|
||||
version "8.2.28-alpha.0"
|
||||
resolved "https://registry.yarnpkg.com/@expo/json-file/-/json-file-8.2.28-alpha.0.tgz#0e5280c82a17165be12c6a95cd95ec108c6dfe7b"
|
||||
integrity sha512-cCQdw/Nfw8doXjN3onvUnWkuJjtVxx2iUjSOLMydvgI87YpW3x05uUXOVs4P+77YFVoFS6xbki+fmKK2JSCf8w==
|
||||
dependencies:
|
||||
"@babel/code-frame" "~7.10.4"
|
||||
fs-extra "9.0.0"
|
||||
json5 "^1.0.1"
|
||||
lodash "^4.17.19"
|
||||
write-file-atomic "^2.3.0"
|
||||
|
||||
"@expo/[email protected]":
|
||||
@@ -3073,31 +3072,6 @@
|
||||
dependencies:
|
||||
"@types/node" ">= 8"
|
||||
|
||||
"@react-native-community/cli-platform-ios@^4.10.0":
|
||||
version "4.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-4.13.0.tgz#a738915c68cac86df54e578b59a1311ea62b1aef"
|
||||
integrity sha512-6THlTu8zp62efkzimfGr3VIuQJ2514o+vScZERJCV1xgEi8XtV7mb/ZKt9o6Y9WGxKKkc0E0b/aVAtgy+L27CA==
|
||||
dependencies:
|
||||
"@react-native-community/cli-tools" "^4.13.0"
|
||||
chalk "^3.0.0"
|
||||
glob "^7.1.3"
|
||||
js-yaml "^3.13.1"
|
||||
lodash "^4.17.15"
|
||||
plist "^3.0.1"
|
||||
xcode "^2.0.0"
|
||||
|
||||
"@react-native-community/cli-tools@^4.13.0":
|
||||
version "4.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-4.13.0.tgz#b406463d33af16cedc4305a9a9257ed32845cf1b"
|
||||
integrity sha512-s4f489h5+EJksn4CfheLgv5PGOM0CDmK1UEBLw2t/ncWs3cW2VI7vXzndcd/WJHTv3GntJhXDcJMuL+Z2IAOgg==
|
||||
dependencies:
|
||||
chalk "^3.0.0"
|
||||
lodash "^4.17.15"
|
||||
mime "^2.4.1"
|
||||
node-fetch "^2.6.0"
|
||||
open "^6.2.0"
|
||||
shell-quote "1.6.1"
|
||||
|
||||
"@samverschueren/stream-to-observable@^0.3.0":
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.1.tgz#a21117b19ee9be70c379ec1877537ef2e1c63301"
|
||||
@@ -3784,11 +3758,6 @@ array-filter@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83"
|
||||
integrity sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=
|
||||
|
||||
array-filter@~0.0.0:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec"
|
||||
integrity sha1-fajPLiZijtcygDWB/SH2fKzS7uw=
|
||||
|
||||
array-find-index@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
|
||||
@@ -3808,16 +3777,6 @@ array-includes@^3.1.1:
|
||||
es-abstract "^1.17.0"
|
||||
is-string "^1.0.5"
|
||||
|
||||
array-map@~0.0.0:
|
||||
version "0.0.0"
|
||||
resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662"
|
||||
integrity sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=
|
||||
|
||||
array-reduce@~0.0.0:
|
||||
version "0.0.0"
|
||||
resolved "https://registry.yarnpkg.com/array-reduce/-/array-reduce-0.0.0.tgz#173899d3ffd1c7d9383e4479525dbe278cab5f2b"
|
||||
integrity sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=
|
||||
|
||||
array-union@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
|
||||
@@ -7509,11 +7468,6 @@ is-windows@^1.0.0, is-windows@^1.0.1, is-windows@^1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
|
||||
integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
|
||||
|
||||
is-wsl@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
|
||||
integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=
|
||||
|
||||
is-wsl@^2.1.1, is-wsl@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271"
|
||||
@@ -8842,7 +8796,7 @@ mime@^1.3.4:
|
||||
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
|
||||
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
|
||||
|
||||
mime@^2.4.1, mime@^2.4.4, mime@^2.4.7:
|
||||
mime@^2.4.4, mime@^2.4.7:
|
||||
version "2.4.7"
|
||||
resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.7.tgz#962aed9be0ed19c91fd7dc2ece5d7f4e89a90d74"
|
||||
integrity sha512-dhNd1uA2u397uQk3Nv5LM4lm93WYDUXFn3Fu291FJerns4jyTudqhIWe4W04YLy7Uk1tm1Ore04NpjRvQp/NPA==
|
||||
@@ -9450,13 +9404,6 @@ onetime@^5.1.0:
|
||||
dependencies:
|
||||
mimic-fn "^2.1.0"
|
||||
|
||||
open@^6.2.0:
|
||||
version "6.4.0"
|
||||
resolved "https://registry.yarnpkg.com/open/-/open-6.4.0.tgz#5c13e96d0dc894686164f18965ecfe889ecfc8a9"
|
||||
integrity sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==
|
||||
dependencies:
|
||||
is-wsl "^1.1.0"
|
||||
|
||||
optionator@^0.8.1, optionator@^0.8.3:
|
||||
version "0.8.3"
|
||||
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495"
|
||||
@@ -10865,16 +10812,6 @@ shebang-regex@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
|
||||
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
|
||||
|
||||
[email protected]:
|
||||
version "1.6.1"
|
||||
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.6.1.tgz#f4781949cce402697127430ea3b3c5476f481767"
|
||||
integrity sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=
|
||||
dependencies:
|
||||
array-filter "~0.0.0"
|
||||
array-map "~0.0.0"
|
||||
array-reduce "~0.0.0"
|
||||
jsonify "~0.0.0"
|
||||
|
||||
shellwords@^0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
|
||||
@@ -12422,7 +12359,7 @@ ws@^7.2.3:
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.1.tgz#d0547bf67f7ce4f12a72dfe31262c68d7dc551c8"
|
||||
integrity sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA==
|
||||
|
||||
xcode@^2.0.0, xcode@^2.1.0:
|
||||
xcode@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/xcode/-/xcode-2.1.0.tgz#bab64a7e954bb50ca8d19da7e09531c65a43ecfe"
|
||||
integrity sha512-uCrmPITrqTEzhn0TtT57fJaNaw8YJs1aCzs+P/QqxsDbvPZSv7XMPPwXrKvHtD6pLjBM/NaVwraWJm8q83Y4iQ==
|
||||
|
||||
Reference in new issue
Block a user