Compare commits

...
25 Commits
Author SHA1 Message Date
Dominik Sokal 32aa46ac69 v0.24.0 2021-08-25 11:15:02 +02:00
339cae2532 Bump apple-utils to v25 (#574)
* Bump apple-utils to v25

* Update CHANGELOG.md

* Apply suggestions from code review

Co-authored-by: Evan Bacon <[email protected]>
Co-authored-by: Dominik Sokal <[email protected]>
2021-08-25 09:48:03 +02:00
Axel DelafosseandDominik Sokal e6ec3bfe6a [eas-cli] update QR code url for Android internal distribution build and generate smaller QR code (#573)
* [eas-cli] update qr code url and generate smaller qr code

* [eas-cli] update changelog

* [eas-cli] fix prettier

* [eas-cli] update changelog

Co-authored-by: Dominik Sokal <[email protected]>

* [eas-cli] update changelog

Co-authored-by: Dominik Sokal <[email protected]>

* [eas-cli] clean code

Co-authored-by: Dominik Sokal <[email protected]>
2021-08-24 17:45:32 +02:00
Juwan Wheatley 012518c375 Update expo.io references to expo.dev (#568)
* Update expo.io references to expo.dev

* fix snapshot
2021-08-23 19:48:37 -04:00
Brent Vatne cc8c8584d9 [eas-cli] Link to project page and add archive FYI link to build command output (#562) 2021-08-20 13:58:53 -07:00
jkh d1910b3c42 [eas-cli] add ability to double publish (#566) 2021-08-20 11:16:43 -07:00
Wojciech KozyraandDominik Sokal 4a1fa3d4fa [eas-cli] warn if NODE_ENV or googleServicesFile is missing (#569)
* [eas-cli] warn if NODE_ENV or googleServicesFile is missing

* update CHANGELOG

* Apply suggestions from code review

Co-authored-by: Dominik Sokal <[email protected]>

Co-authored-by: Dominik Sokal <[email protected]>
2021-08-20 12:31:46 +02:00
Wojciech Kozyra 61178c9d06 add changesNotSentForReview option to android submissions (#560)
* add changesNotSentForReview option to android submits

* update CHANGELOG

* fix types in tests

* review feedback
2021-08-19 15:01:14 +02:00
Wojciech KozyraandDominik Sokal 094c04c7f0 [eas-cli] support --json flag for build commands (#567)
* [eas-cli] support --json flag for build commands

* sanitize json object

* update CHANGELOG

* Apply suggestions from code review

Co-authored-by: Dominik Sokal <[email protected]>

Co-authored-by: Dominik Sokal <[email protected]>
2021-08-19 14:58:19 +02:00
kgc00 37cca4878d [eas-cli] Introduce RudderStack (#563)
- adds RudderStack to the analytics file
- reworks some of the existing amplitude tracking event structure to properly record data
2021-08-18 10:46:19 -07:00
Wojciech Kozyra 2b40e1ec05 [eas-cli] support submit profiles (#555)
* [eas-cli] support submit profiles

* Update CHANGELOG

* review feedback
2021-08-13 11:53:58 +02:00
Bartłomiej Klocek 6e95d3afcc [eas cli] Fix SKU not being applied to App Store Connect (#559)
* [eas submit] Fix SKU not being applied to App Store Connect

* Update CHANGELOG
2021-08-13 10:36:09 +02:00
Wojciech Kozyra 6b9b9f0be2 [eas-cli] fix metadata for simulator builds (#556)
* [eas-cli] fix metadata for simulator builds

* Update CHANGELOG
2021-08-13 10:08:27 +02:00
Brent Vatne f14b963b29 [eas-cli] Stop using project name in build details URL (#554) 2021-08-12 21:53:47 -07:00
andy ddd2814e8f [submit] log submissions link at end of eas-submit (#553) 2021-08-11 11:00:22 -07:00
jkh 36f15a81a9 [changelog] fix formatting (#552) 2021-08-06 07:47:31 -07:00
jkh ece93dac20 [eas-cli] add --auto flag to publish (#549) 2021-08-06 05:58:04 -07:00
Brent Vatne 0226dbba5a Update CHANGELOG and README 2021-08-05 15:34:16 -07:00
Brent Vatne e773e77185 v0.23.0 2021-08-05 15:19:01 -07:00
Brent Vatne 893cbb2ec5 [eas-cli] Pass through build settings metadata context to app version resolver (#550) 2021-08-05 15:17:30 -07:00
jkh 1898de2609 [eas-cli] add type to generated manifest fragment (#535) 2021-08-05 06:50:20 -07:00
jkh fe03cc28c4 [eas-cli] stop sending deprecated storageBucket field (#547) 2021-08-03 13:55:00 -07:00
Wojciech Kozyra 5309b7b6ce Update CHANGELOG 2021-08-02 13:23:20 +02:00
Wojciech Kozyra bc9b8442d7 v0.22.4 2021-08-02 13:07:52 +02:00
Wojciech Kozyra a84762b00d [eas-cli] override distribution when building for simulator 2021-08-02 12:57:59 +02:00
63 changed files with 2056 additions and 451 deletions

No files matched your search

+35 -2
View File
@@ -6,14 +6,45 @@ This is the log of notable changes to EAS CLI and related packages.
### 🛠 Breaking changes
- Allow publishing of multiple update groups ([#566](https://github.com/expo/eas-cli/pull/566) by [@jkhales](https://github.com/jkhales))
### 🎉 New features
- Retry status code 500-600 server errors from Apple servers with cookies auth. ([#574](https://github.com/expo/eas-cli/pull/574) by [@EvanBacon](https://github.com/EvanBacon))
- Throw internal server errors when Apple servers fail to authenticate. ([#574](https://github.com/expo/eas-cli/pull/574) by [@EvanBacon](https://github.com/EvanBacon))
- Add --auto flag for eas branch:publish ([#549](https://github.com/expo/eas-cli/pull/549) by [@jkhales](https://github.com/jkhales))
- Add submissions link in output of `eas submit`([#553](https://github.com/expo/eas-cli/pull/553) by [@ajsmth](https://github.com/ajsmth))
- Add submit profiles. ([#555](https://github.com/expo/eas-cli/pull/555) by [@wkozyra95](https://github.com/wkozyra95))
- Add `changesNotSentForReview` option to android submissions. ([#560](https://github.com/expo/eas-cli/pull/560) by [@wkozyra95](https://github.com/wkozyra95))
- Support `--json` flag in build commands. ([#567](https://github.com/expo/eas-cli/pull/567) by [@wkozyra95](https://github.com/wkozyra95))
- Add link to https://expo.fyi/eas-build-archive in `eas build` output to make it easier to understand what is going on in the archive/upload phase of the build. ([#562](https://github.com/expo/eas-cli/pull/562) by [@brentvatne](https://github.com/brentvatne))
- Update QR code url for Android internal distribution build and generate smaller QR code. ([#573](https://github.com/expo/eas-cli/pull/573) by [@axeldelafosse](https://github.com/axeldelafosse))
### 🐛 Bug fixes
- Fix `--sku` flag being ignored when running `eas submit -p ios`. ([#559](https://github.com/expo/eas-cli/pull/559) by [@barthap](https://github.com/barthap))
- Set correct distribution for simulator builds. ([#556](https://github.com/expo/eas-cli/pull/556) by [@wkozyra95](https://github.com/wkozyra95))
### 🧹 Chores
- Add warnings around common issues (`NODE_ENV=production`, git ignored `googleServicesFile`). ([#569](https://github.com/expo/eas-cli/pull/569) by [@wkozyra95](https://github.com/wkozyra95))
## [0.23.0](https://github.com/expo/eas-cli/releases/tag/v0.23.0) - 2021-08-05
### 🛠 Breaking changes
- Stop including deprecated storageBucket field when publishing ([#547](https://github.com/expo/eas-cli/pull/547) by [@jkhales](https://github.com/jkhales))
### 🐛 Bug fixes
- Pass through metadata context to app version resolver. ([#550](https://github.com/expo/eas-cli/pull/550) by [@brentvatne](https://github.com/brentvatne))
## [0.22.4](https://github.com/expo/eas-cli/releases/tag/v0.22.4) - 2021-08-02
### 🐛 Bug fixes
- Fix build profile schema validation when `simulator` key is present for iOS ([#546](https://github.com/expo/eas-cli/pull/546) by [@sallar](https://github.com/sallar))
### 🧹 Chores
## [0.22.2](https://github.com/expo/eas-cli/releases/tag/v0.22.2) - 2021-08-02
### 🛠 Breaking changes
@@ -30,11 +61,13 @@ This is the log of notable changes to EAS CLI and related packages.
- Validate metadata client side to print better errors. ([#542](https://github.com/expo/eas-cli/pull/542) by [@wkozyra95](https://github.com/wkozyra95))
- Fix `new` build status when building both paltforms. ([#543](https://github.com/expo/eas-cli/pull/543) by [@wkozyra95](https://github.com/wkozyra95))
- Fix link to build details page where previously we used `project.name` instead of `project.slug` - leave out project segment entirely and depend on redirect. ([#554](https://github.com/expo/eas-cli/pull/554) by [@brentvatne](https://github.com/brentvatne))
## [0.22.1](https://github.com/expo/eas-cli/releases/tag/v0.22.1) - 2021-07-28
### 🎉 New features
- Include the file extension for update's assets in the manifest fragment. ([#532](https://github.com/expo/eas-cli/pull/535) by [@jkhales](https://github.com/jkhales))
- Use env variables from `eas.json` when evaluating `app.config.js`. ([#532](https://github.com/expo/eas-cli/pull/532) by [@dsokal](https://github.com/dsokal))
### 🐛 Bug fixes
+1 -1
View File
@@ -1,5 +1,5 @@
{
"npmClient": "yarn",
"useWorkspaces": true,
"version": "0.22.3"
"version": "0.24.0"
}
+46 -27
View File
@@ -72,7 +72,7 @@ ALIASES
$ eas login
```
_See code: [src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v0.22.3/packages/eas-cli/src/commands/account/login.ts)_
_See code: [src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v0.24.0/packages/eas-cli/src/commands/account/login.ts)_
## `eas account:logout`
@@ -86,7 +86,7 @@ ALIASES
$ eas logout
```
_See code: [src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v0.22.3/packages/eas-cli/src/commands/account/logout.ts)_
_See code: [src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v0.24.0/packages/eas-cli/src/commands/account/logout.ts)_
## `eas account:view`
@@ -100,7 +100,7 @@ ALIASES
$ eas whoami
```
_See code: [src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v0.22.3/packages/eas-cli/src/commands/account/view.ts)_
_See code: [src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v0.24.0/packages/eas-cli/src/commands/account/view.ts)_
## `eas analytics [STATUS]`
@@ -111,7 +111,7 @@ USAGE
$ eas analytics [STATUS]
```
_See code: [src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v0.22.3/packages/eas-cli/src/commands/analytics.ts)_
_See code: [src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v0.24.0/packages/eas-cli/src/commands/analytics.ts)_
## `eas build`
@@ -124,6 +124,7 @@ USAGE
OPTIONS
-p, --platform=(android|ios|all)
--clear-cache Clear cache before the build
--json Enable JSON output, non-JSON messages will be printed to stderr
--local Run build locally [experimental]
--non-interactive Run command in --non-interactive mode
--profile=profile [default: release] Name of the build profile from eas.json
@@ -131,7 +132,7 @@ OPTIONS
--[no-]wait Wait for build(s) to complete
```
_See code: [src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v0.22.3/packages/eas-cli/src/commands/build/index.ts)_
_See code: [src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v0.24.0/packages/eas-cli/src/commands/build/index.ts)_
## `eas build:cancel [BUILD_ID]`
@@ -142,7 +143,7 @@ USAGE
$ eas build:cancel [BUILD_ID]
```
_See code: [src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v0.22.3/packages/eas-cli/src/commands/build/cancel.ts)_
_See code: [src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v0.24.0/packages/eas-cli/src/commands/build/cancel.ts)_
## `eas build:configure`
@@ -156,7 +157,7 @@ OPTIONS
-p, --platform=(android|ios|all) Platform to configure
```
_See code: [src/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v0.22.3/packages/eas-cli/src/commands/build/configure.ts)_
_See code: [src/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v0.24.0/packages/eas-cli/src/commands/build/configure.ts)_
## `eas build:list`
@@ -174,14 +175,22 @@ OPTIONS
--channel=channel
--distribution=(store|internal|simulator)
--gitCommitHash=gitCommitHash
--json Enable JSON output, non-JSON messages will be printed
to stderr
--limit=limit
--platform=(all|android|ios)
--runtimeVersion=runtimeVersion
--sdkVersion=sdkVersion
--status=(new|in-queue|in-progress|errored|finished|canceled)
```
_See code: [src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v0.22.3/packages/eas-cli/src/commands/build/list.ts)_
_See code: [src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v0.24.0/packages/eas-cli/src/commands/build/list.ts)_
## `eas build:view [BUILD_ID]`
@@ -190,9 +199,12 @@ view a build for your project
```
USAGE
$ eas build:view [BUILD_ID]
OPTIONS
--json Enable JSON output, non-JSON messages will be printed to stderr
```
_See code: [src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v0.22.3/packages/eas-cli/src/commands/build/view.ts)_
_See code: [src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v0.24.0/packages/eas-cli/src/commands/build/view.ts)_
## `eas config`
@@ -207,7 +219,7 @@ OPTIONS
--profile=profile
```
_See code: [src/commands/config.ts](https://github.com/expo/eas-cli/blob/v0.22.3/packages/eas-cli/src/commands/config.ts)_
_See code: [src/commands/config.ts](https://github.com/expo/eas-cli/blob/v0.24.0/packages/eas-cli/src/commands/config.ts)_
## `eas credentials`
@@ -218,7 +230,7 @@ USAGE
$ eas credentials
```
_See code: [src/commands/credentials.ts](https://github.com/expo/eas-cli/blob/v0.22.3/packages/eas-cli/src/commands/credentials.ts)_
_See code: [src/commands/credentials.ts](https://github.com/expo/eas-cli/blob/v0.24.0/packages/eas-cli/src/commands/credentials.ts)_
## `eas device:create`
@@ -229,7 +241,7 @@ USAGE
$ eas device:create
```
_See code: [src/commands/device/create.ts](https://github.com/expo/eas-cli/blob/v0.22.3/packages/eas-cli/src/commands/device/create.ts)_
_See code: [src/commands/device/create.ts](https://github.com/expo/eas-cli/blob/v0.24.0/packages/eas-cli/src/commands/device/create.ts)_
## `eas device:list`
@@ -243,7 +255,7 @@ OPTIONS
--apple-team-id=apple-team-id
```
_See code: [src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v0.22.3/packages/eas-cli/src/commands/device/list.ts)_
_See code: [src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v0.24.0/packages/eas-cli/src/commands/device/list.ts)_
## `eas device:view [UDID]`
@@ -254,7 +266,7 @@ USAGE
$ eas device:view [UDID]
```
_See code: [src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v0.22.3/packages/eas-cli/src/commands/device/view.ts)_
_See code: [src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v0.24.0/packages/eas-cli/src/commands/device/view.ts)_
## `eas help [COMMAND]`
@@ -282,7 +294,7 @@ USAGE
$ eas project:info
```
_See code: [src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v0.22.3/packages/eas-cli/src/commands/project/info.ts)_
_See code: [src/commands/project/info.ts](https://github.com/expo/eas-cli/blob/v0.24.0/packages/eas-cli/src/commands/project/info.ts)_
## `eas project:init`
@@ -296,7 +308,7 @@ ALIASES
$ eas init
```
_See code: [src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v0.22.3/packages/eas-cli/src/commands/project/init.ts)_
_See code: [src/commands/project/init.ts](https://github.com/expo/eas-cli/blob/v0.24.0/packages/eas-cli/src/commands/project/init.ts)_
## `eas secret:create`
@@ -313,7 +325,7 @@ OPTIONS
--value=value Value of the secret
```
_See code: [src/commands/secret/create.ts](https://github.com/expo/eas-cli/blob/v0.22.3/packages/eas-cli/src/commands/secret/create.ts)_
_See code: [src/commands/secret/create.ts](https://github.com/expo/eas-cli/blob/v0.24.0/packages/eas-cli/src/commands/secret/create.ts)_
## `eas secret:delete`
@@ -330,7 +342,7 @@ DESCRIPTION
Unsure where to find the secret's ID? Run eas secrets:list
```
_See code: [src/commands/secret/delete.ts](https://github.com/expo/eas-cli/blob/v0.22.3/packages/eas-cli/src/commands/secret/delete.ts)_
_See code: [src/commands/secret/delete.ts](https://github.com/expo/eas-cli/blob/v0.24.0/packages/eas-cli/src/commands/secret/delete.ts)_
## `eas secret:list`
@@ -341,7 +353,7 @@ USAGE
$ eas secret:list
```
_See code: [src/commands/secret/list.ts](https://github.com/expo/eas-cli/blob/v0.22.3/packages/eas-cli/src/commands/secret/list.ts)_
_See code: [src/commands/secret/list.ts](https://github.com/expo/eas-cli/blob/v0.24.0/packages/eas-cli/src/commands/secret/list.ts)_
## `eas submit --platform=(android|ios)`
@@ -373,13 +385,18 @@ OPTIONS
iOS specific options=bundle-identifier Your iOS Bundle Identifier (default:
expo.ios.bundleIdentifier from app config)
Android specific options [default: false] Indicates that the changes sent
with this submission will not be reviewed until
they are explicitly sent for review from the Google
Play Console UI
iOS specific options=company-name The name of your company, needed only for the first
upload of any app to App Store
--id=id ID of the build to submit
Android specific options=key Path to the JSON key used to authenticate with
Google Play
Android specific options=key Path to the JSON file with service account key used
to authenticate with Google Play
iOS specific options=language [default: en-US] Primary language (e.g. English,
German, ...)
@@ -388,6 +405,8 @@ OPTIONS
--path=path Path to the .apk/.aab file
--profile=profile Name of the submit profile from eas.json
Android specific options=(completed|draft|halted|inProgress) [default: completed] Release status (used when
uploading new APKs/AABs)
@@ -421,7 +440,7 @@ EXAMPLES
and provide its App ID
```
_See code: [src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v0.22.3/packages/eas-cli/src/commands/submit.ts)_
_See code: [src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v0.24.0/packages/eas-cli/src/commands/submit.ts)_
## `eas webhook:create`
@@ -440,7 +459,7 @@ OPTIONS
--url=url Webhook URL
```
_See code: [src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v0.22.3/packages/eas-cli/src/commands/webhook/create.ts)_
_See code: [src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v0.24.0/packages/eas-cli/src/commands/webhook/create.ts)_
## `eas webhook:delete [ID]`
@@ -454,7 +473,7 @@ ARGUMENTS
ID ID of the webhook to delete
```
_See code: [src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v0.22.3/packages/eas-cli/src/commands/webhook/delete.ts)_
_See code: [src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v0.24.0/packages/eas-cli/src/commands/webhook/delete.ts)_
## `eas webhook:list`
@@ -468,7 +487,7 @@ OPTIONS
--event=(BUILD) Event type that triggers the webhook
```
_See code: [src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v0.22.3/packages/eas-cli/src/commands/webhook/list.ts)_
_See code: [src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v0.24.0/packages/eas-cli/src/commands/webhook/list.ts)_
## `eas webhook:update`
@@ -488,7 +507,7 @@ OPTIONS
--url=url Webhook URL
```
_See code: [src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v0.22.3/packages/eas-cli/src/commands/webhook/update.ts)_
_See code: [src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v0.24.0/packages/eas-cli/src/commands/webhook/update.ts)_
## `eas webhook:view ID`
@@ -502,5 +521,5 @@ ARGUMENTS
ID ID of the webhook to view
```
_See code: [src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v0.22.3/packages/eas-cli/src/commands/webhook/view.ts)_
_See code: [src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v0.24.0/packages/eas-cli/src/commands/webhook/view.ts)_
<!-- commandsstop -->
+467 -67
View File
@@ -3047,20 +3047,6 @@
},
"defaultValue": null
},
{
"name": "buildListMaxSize",
"description": "Max number of associated builds to return",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "mostRecentlyUpdatedAt",
"description": "Offset the query",
@@ -3070,6 +3056,16 @@
"ofType": null
},
"defaultValue": null
},
{
"name": "options",
"description": "",
"type": {
"kind": "INPUT_OBJECT",
"name": "DeploymentOptions",
"ofType": null
},
"defaultValue": null
}
],
"type": {
@@ -3092,6 +3088,57 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "deployment",
"description": "",
"args": [
{
"name": "channel",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "runtimeVersion",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "options",
"description": null,
"type": {
"kind": "INPUT_OBJECT",
"name": "DeploymentOptions",
"ofType": null
},
"defaultValue": null
}
],
"type": {
"kind": "OBJECT",
"name": "Deployment",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "iosAppCredentials",
"description": "iOS app credentials for the project",
@@ -6982,6 +7029,27 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "INPUT_OBJECT",
"name": "DeploymentOptions",
"description": "",
"fields": null,
"inputFields": [
{
"name": "buildListMaxSize",
"description": "Max number of associated builds to return",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
},
"defaultValue": null
}
],
"interfaces": null,
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "Deployment",
@@ -6992,9 +7060,13 @@
"description": "",
"args": [],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
@@ -7004,9 +7076,13 @@
"description": "",
"args": [],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
@@ -7016,9 +7092,13 @@
"description": "",
"args": [],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
@@ -7028,19 +7108,27 @@
"description": "",
"args": [],
"type": {
"kind": "LIST",
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "Build",
"ofType": null
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "Build",
"ofType": null
}
}
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "branchToReceive",
"name": "branchMapping",
"description": "",
"args": [],
"type": {
@@ -7204,30 +7292,6 @@
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "mostRecentUpdateForEachPlatform",
"description": "",
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "Update",
"ofType": null
}
}
}
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
@@ -8813,6 +8877,18 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "googleServiceAccountKeyForSubmissions",
"description": "",
"args": [],
"type": {
"kind": "OBJECT",
"name": "GoogleServiceAccountKey",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "androidAppBuildCredentialsList",
"description": "",
@@ -9164,6 +9240,145 @@
],
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "GoogleServiceAccountKey",
"description": "",
"fields": [
{
"name": "id",
"description": "",
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "account",
"description": "",
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "Account",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "projectIdentifier",
"description": "",
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "privateKeyIdentifier",
"description": "",
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "clientEmail",
"description": "",
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "clientIdentifier",
"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": "AndroidAppBuildCredentials",
@@ -18923,6 +19138,37 @@
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "createAndroidSubmission",
"description": "Create an Android EAS Submit submission",
"args": [
{
"name": "input",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "INPUT_OBJECT",
"name": "CreateAndroidSubmissionInput",
"ofType": null
}
},
"defaultValue": null
}
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "CreateSubmissionResult",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
@@ -19048,7 +19294,7 @@
"name": null,
"ofType": {
"kind": "INPUT_OBJECT",
"name": "NewIosSubmissionConfig",
"name": "IosSubmissionConfigInput",
"ofType": null
}
},
@@ -19071,7 +19317,7 @@
},
{
"kind": "INPUT_OBJECT",
"name": "NewIosSubmissionConfig",
"name": "IosSubmissionConfigInput",
"description": "",
"fields": null,
"inputFields": [
@@ -19142,6 +19388,152 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "INPUT_OBJECT",
"name": "CreateAndroidSubmissionInput",
"description": "",
"fields": null,
"inputFields": [
{
"name": "appId",
"description": "",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "config",
"description": "",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "INPUT_OBJECT",
"name": "AndroidSubmissionConfigInput",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "submittedBuildId",
"description": "",
"type": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
},
"defaultValue": null
}
],
"interfaces": null,
"enumValues": null,
"possibleTypes": null
},
{
"kind": "INPUT_OBJECT",
"name": "AndroidSubmissionConfigInput",
"description": "",
"fields": null,
"inputFields": [
{
"name": "googleServiceAccountKeyId",
"description": "",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "googleServiceAccountKeyJson",
"description": "",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
{
"name": "archiveUrl",
"description": "",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "archiveType",
"description": "",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "ENUM",
"name": "SubmissionAndroidArchiveType",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "applicationIdentifier",
"description": "",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "track",
"description": "",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "ENUM",
"name": "SubmissionAndroidTrack",
"ofType": null
}
},
"defaultValue": null
},
{
"name": "releaseStatus",
"description": "",
"type": {
"kind": "ENUM",
"name": "SubmissionAndroidReleaseStatus",
"ofType": null
},
"defaultValue": null
}
],
"interfaces": null,
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "UpdateChannelMutation",
@@ -19481,16 +19873,28 @@
"deprecationReason": null
},
{
"name": "publishUpdateGroup",
"name": "publishUpdateGroups",
"description": "Publish an update group to a branch",
"args": [
{
"name": "publishUpdateGroupInput",
"name": "publishUpdateGroupsInput",
"description": null,
"type": {
"kind": "INPUT_OBJECT",
"name": "PublishUpdateGroupInput",
"ofType": null
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "LIST",
"name": null,
"ofType": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "INPUT_OBJECT",
"name": "PublishUpdateGroupInput",
"ofType": null
}
}
}
},
"defaultValue": null
}
@@ -19809,16 +20213,12 @@
"defaultValue": null
},
{
"name": "storageBucket",
"name": "fileExtension",
"description": "",
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"defaultValue": null
},
+5 -4
View File
@@ -1,8 +1,8 @@
{
"name": "eas-cli",
"description": "EAS command line tool",
"version": "0.22.3",
"author": "Expo <support@expo.io>",
"version": "0.24.0",
"author": "Expo <support@expo.dev>",
"bin": {
"eas": "./bin/run"
},
@@ -10,16 +10,17 @@
"dependencies": {
"@amplitude/identify": "1.7.0",
"@amplitude/node": "1.7.0",
"@expo/apple-utils": "0.0.0-alpha.24",
"@expo/apple-utils": "0.0.0-alpha.25",
"@expo/config": "3.3.42",
"@expo/config-plugins": "3.0.3",
"@expo/eas-build-job": "0.2.45",
"@expo/eas-json": "^0.22.3",
"@expo/eas-json": "^0.24.0",
"@expo/json-file": "8.2.25",
"@expo/pkcs12": "0.0.4",
"@expo/plist": "0.0.11",
"@expo/plugin-warn-if-update-available": "1.7.0",
"@expo/results": "1.0.0",
"@expo/rudder-sdk-node": "1.0.7",
"@expo/sdk-runtime-versions": "1.0.0",
"@expo/spawn-async": "1.5.0",
"@hapi/joi": "17.1.1",
+83 -20
View File
@@ -1,5 +1,6 @@
import { Identify } from '@amplitude/identify';
import * as Amplitude from '@amplitude/node';
import RudderAnalytics from '@expo/rudder-sdk-node';
import os from 'os';
import { v4 as uuidv4 } from 'uuid';
@@ -18,8 +19,9 @@ const PLATFORM_TO_ANALYTICS_PLATFORM: { [platform: string]: string } = {
linux: 'Linux',
};
let client: Amplitude.NodeClient | null = null;
let userIdentifyCalled = false;
let amplitudeClient: Amplitude.NodeClient | null = null;
let rudderstackClient: RudderAnalytics | null = null;
let userIdentified = false;
let identifyData: {
userId: string;
deviceId: string;
@@ -32,11 +34,33 @@ export async function initAsync(): Promise<void> {
}
const amplitudeEnabled = await UserSettings.getAsync('amplitudeEnabled', true);
if (amplitudeEnabled) {
const apiKey =
const config =
process.env.EXPO_STAGING || process.env.EXPO_LOCAL
? 'cdebbc678931403439486c4750781544'
: '4ac443afd5073c0df6169291db1d3495';
client = Amplitude.init(apiKey, { retryClass: new Amplitude.OfflineRetryHandler(apiKey) });
? {
// staging environment
amplitudeWriteKey: 'cdebbc678931403439486c4750781544',
rudderstackWriteKey: '1wpX20Da4ltFGSXbPFYUL00Chb7',
rudderstackDataPlaneURL: 'https://cdp.expo.dev',
}
: {
// prod environment
amplitudeWriteKey: '4ac443afd5073c0df6169291db1d3495',
rudderstackWriteKey: '1wpXLFxmujq86etH6G6cc90hPcC',
rudderstackDataPlaneURL: 'https://cdp.expo.dev',
};
amplitudeClient = Amplitude.init(config.amplitudeWriteKey, {
retryClass: new Amplitude.OfflineRetryHandler(config.amplitudeWriteKey),
});
rudderstackClient = new RudderAnalytics(
config.rudderstackWriteKey,
new URL('/v1/batch', config.rudderstackDataPlaneURL).toString(),
{
flushInterval: 300,
}
);
rudderstackClient.logger.silent = true;
}
}
@@ -53,6 +77,7 @@ export async function setUserDataAsync(
if (!savedDeviceId) {
await UserSettings.setAsync('amplitudeDeviceId', deviceId);
}
identifyData = {
userId,
deviceId,
@@ -63,41 +88,79 @@ export async function setUserDataAsync(
}
export async function flushAsync(): Promise<void> {
if (client) {
await client.flush();
if (rudderstackClient) {
rudderstackClient.flush();
}
if (amplitudeClient) {
await amplitudeClient.flush();
}
}
export function logEvent(name: string, properties: Record<string, any> = {}) {
if (client) {
ensureUserIdentified();
const { userId, deviceId } = identifyData ?? {};
client.logEvent({
if (!amplitudeClient && !rudderstackClient) {
return;
}
ensureUserIdentified();
const { userId, deviceId } = identifyData ?? {};
const commonEventProperties = { source_version: packageJSON?.version, source: 'eas cli' };
if (amplitudeClient) {
amplitudeClient.logEvent({
event_type: name,
event_properties: properties,
event_properties: { ...properties, ...commonEventProperties },
...(userId && { user_id: userId }),
...(deviceId && { device_id: deviceId }),
...getContext(),
...getAmplitudeContext(),
});
}
if (rudderstackClient) {
const identity = { userId: userId ?? undefined, anonymousId: deviceId ?? uuidv4() };
rudderstackClient.track({
event: name,
properties: { ...properties, ...commonEventProperties },
...identity,
context: getRudderStackContext(),
});
}
}
function ensureUserIdentified() {
if (client && !userIdentifyCalled && identifyData) {
client.identify(identifyData.userId, identifyData.deviceId, identifyData.identify);
userIdentifyCalled = true;
if (!(rudderstackClient || amplitudeClient) || userIdentified || !identifyData) {
return;
}
if (amplitudeClient) {
amplitudeClient.identify(identifyData.userId, identifyData.deviceId, identifyData.identify);
}
if (rudderstackClient) {
rudderstackClient.identify({
userId: identifyData.userId,
anonymousId: identifyData.deviceId,
});
}
userIdentified = true;
}
function getContext() {
function getAmplitudeContext() {
const platform = PLATFORM_TO_ANALYTICS_PLATFORM[os.platform()] || os.platform();
return {
os_name: platform,
os_version: os.release(),
device_brand: platform,
device_model: platform,
source_version: packageJSON?.version,
source: 'eas cli',
};
}
function getRudderStackContext() {
const platform = PLATFORM_TO_ANALYTICS_PLATFORM[os.platform()] || os.platform();
return {
os: { name: platform, version: os.release() },
device: { type: platform, model: platform },
app: { name: 'eas cli', version: packageJSON?.version ?? undefined },
};
}
+2 -2
View File
@@ -50,10 +50,10 @@ export function getExpoApiBaseUrl(): string {
export function getExpoWebsiteBaseUrl(): string {
if (process.env.EXPO_STAGING) {
return `https://staging.expo.io`;
return `https://staging.expo.dev`;
} else if (process.env.EXPO_LOCAL) {
return `http://expo.test`;
} else {
return `https://expo.io`;
return `https://expo.dev`;
}
}
@@ -23,6 +23,7 @@ import { BuildContext } from '../context';
import { transformMetadata } from '../graphql';
import { Platform } from '../types';
import { logCredentialsSource } from '../utils/credentials';
import { checkGoogleServicesFileAsync, checkNodeEnvVariable } from '../validate';
import { validateAndSyncProjectConfigurationAsync } from './configure';
import { transformJob } from './graphql';
import { prepareJobAsync } from './prepareJob';
@@ -48,6 +49,9 @@ This means that it will most likely produce an AAB and you will not be able to i
}
}
checkNodeEnvVariable(ctx);
await checkGoogleServicesFileAsync(ctx);
if (ctx.workflow === Workflow.MANAGED) {
await ensureApplicationIdIsDefinedForManagedProjectAsync(ctx.projectDir, ctx.exp);
}
+5 -2
View File
@@ -8,7 +8,7 @@ import ora from 'ora';
import { BuildFragment, BuildStatus, UploadSessionType } from '../graphql/generated';
import { BuildResult } from '../graphql/mutations/BuildMutation';
import { BuildQuery } from '../graphql/queries/BuildQuery';
import Log from '../log';
import Log, { learnMore } from '../log';
import { promptAsync } from '../prompts';
import { uploadAsync } from '../uploads';
import { formatBytes } from '../utils/files';
@@ -159,7 +159,10 @@ async function uploadProjectAsync<TPlatform extends Platform>(
`Uploading to EAS Build (${formatBytes(projectTarball.size * ratio)} / ${formatBytes(
projectTarball.size
)})`,
completedMessage: `Uploaded to EAS`,
completedMessage: (duration: string) =>
`Uploaded to EAS ${chalk.dim(duration)} ${learnMore(
'https://expo.fyi/eas-build-archive'
)}`,
})
);
return bucketKey;
+1 -1
View File
@@ -46,7 +46,7 @@ export async function ensureProjectConfiguredAsync(
} else {
error(
`Aborting, please run ${chalk.bold('eas build:configure')} or create eas.json (${learnMore(
'https://docs.expo.io/build/eas-json'
'https://docs.expo.dev/build/eas-json'
)})`,
{ exit: 1 }
);
+4
View File
@@ -11,6 +11,7 @@ import { BuildContext } from '../context';
import { transformMetadata } from '../graphql';
import { IosMetadataContext } from '../metadata';
import { Platform } from '../types';
import { checkGoogleServicesFileAsync, checkNodeEnvVariable } from '../validate';
import { validateAndSyncProjectConfigurationAsync } from './configure';
import { ensureIosCredentialsAsync } from './credentials';
import { transformJob } from './graphql';
@@ -25,6 +26,9 @@ export async function prepareIosBuildAsync(
await ensureBundleIdentifierIsDefinedForManagedProjectAsync(ctx.projectDir, ctx.exp);
}
checkNodeEnvVariable(ctx);
await checkGoogleServicesFileAsync(ctx);
const xcodeBuildContext = await resolveXcodeBuildContextAsync(
{
projectDir: ctx.projectDir,
+1 -1
View File
@@ -40,7 +40,7 @@ export async function prepareJobAsync(
platform: Platform.IOS,
projectArchive: jobData.projectArchive,
projectRootDirectory,
distribution: ctx.buildProfile.scheme ? 'simulator' : ctx.buildProfile.distribution,
distribution: ctx.buildProfile.simulator ? 'simulator' : ctx.buildProfile.distribution,
builderEnvironment: {
image: resolveImage(ctx),
node: ctx.buildProfile.node,
+6 -2
View File
@@ -41,9 +41,13 @@ export async function collectMetadata<T extends Platform>(
platformContext?: MetadataContext<T>
): Promise<Metadata> {
const channelOrReleaseChannel = await resolveChannelOrReleaseChannelAsync(ctx);
const distribution =
('simulator' in ctx.buildProfile && ctx.buildProfile.simulator
? 'simulator'
: ctx.buildProfile.distribution) ?? 'store';
const metadata = {
trackingContext: ctx.trackingCtx,
appVersion: await resolveAppVersionAsync(ctx),
appVersion: await resolveAppVersionAsync(ctx, platformContext),
appBuildVersion: await resolveAppBuildVersionAsync(ctx, platformContext),
cliVersion: packageJSON.version,
workflow: ctx.workflow,
@@ -51,7 +55,7 @@ export async function collectMetadata<T extends Platform>(
sdkVersion: ctx.exp.sdkVersion,
runtimeVersion: ctx.exp.runtimeVersion,
...channelOrReleaseChannel,
distribution: ctx.buildProfile.distribution ?? 'store',
distribution,
appName: ctx.exp.name,
appIdentifier: await resolveAppIdentifierAsync(ctx),
buildProfile: ctx.buildProfileName,
@@ -4,6 +4,7 @@ import indentString from 'indent-string';
import qrcodeTerminal from 'qrcode-terminal';
import {
AppPlatform,
BuildError,
BuildFragment,
BuildStatus,
@@ -12,6 +13,7 @@ import {
EasBuildDeprecationInfoType,
} from '../../graphql/generated';
import Log, { learnMore } from '../../log';
import { printJsonOnlyOutput } from '../../utils/json';
import { appPlatformDisplayNames, appPlatformEmojis } from '../constants';
import { getBuildLogsUrl, getInternalDistributionInstallUrl } from './url';
@@ -28,14 +30,18 @@ export function printLogsUrls(builds: BuildFragment[]): void {
}
}
export function printBuildResults(builds: (BuildFragment | null)[]): void {
Log.newLine();
if (builds.length === 1) {
const [build] = builds;
assert(build, 'Build should be defined');
printBuildResult(build);
export function printBuildResults(builds: (BuildFragment | null)[], json: boolean): void {
if (json) {
printJsonOnlyOutput(builds);
} else {
(builds.filter(i => i) as BuildFragment[]).forEach(build => printBuildResult(build));
Log.newLine();
if (builds.length === 1) {
const [build] = builds;
assert(build, 'Build should be defined');
printBuildResult(build);
} else {
(builds.filter(i => i) as BuildFragment[]).forEach(build => printBuildResult(build));
}
}
}
@@ -64,8 +70,13 @@ function printBuildResult(build: BuildFragment): void {
if (build.distribution === DistributionType.Internal) {
const logsUrl = getBuildLogsUrl(build);
const installUrl = getInternalDistributionInstallUrl(build);
qrcodeTerminal.generate(installUrl, code => Log.log(`${indentString(code, 2)}\n`));
// It's tricky to install the .apk file directly on Android so let's fallback
// to the build details page and let people press the button to download there
const qrcodeUrl =
build.platform === AppPlatform.Ios ? getInternalDistributionInstallUrl(build) : logsUrl;
qrcodeTerminal.generate(qrcodeUrl, { small: true }, code =>
Log.log(`${indentString(code, 2)}\n`)
);
Log.log(
`${appPlatformEmojis[build.platform]} Open this link on your ${
appPlatformDisplayNames[build.platform]
+5 -3
View File
@@ -3,12 +3,14 @@ import assert from 'assert';
import { getExpoApiBaseUrl, getExpoWebsiteBaseUrl } from '../../api';
import { AppPlatform, BuildFragment } from '../../graphql/generated';
export function getProjectDashboardUrl(accountName: string, projectName: string): string {
return `${getExpoWebsiteBaseUrl()}/accounts/${accountName}/projects/${projectName}`;
}
export function getBuildLogsUrl(build: BuildFragment): string {
const { project } = build;
if (project.__typename === 'App') {
return `${getExpoWebsiteBaseUrl()}/accounts/${project.ownerAccount.name}/projects/${
project.name
}/builds/${build.id}`;
return `${getExpoWebsiteBaseUrl()}/accounts/${project.ownerAccount.name}/builds/${build.id}`;
} else {
return `${getExpoWebsiteBaseUrl()}/builds/${build.id}`;
}
+53
View File
@@ -0,0 +1,53 @@
import { Workflow } from '@expo/eas-build-job';
import fs from 'fs-extra';
import path from 'path';
import Log, { learnMore } from '../log';
import vcs from '../vcs';
import { BuildContext } from './context';
import { Platform } from './types';
export function checkNodeEnvVariable(ctx: BuildContext<Platform>): void {
if (ctx.buildProfile.env?.NODE_ENV === 'production') {
Log.warn(
'You set NODE_ENV=production in the build profile. Remember that it will be available during the entire build process. In particular, it will make yarn/npm install only production packages.'
);
Log.newLine();
}
}
export async function checkGoogleServicesFileAsync<T extends Platform>(
ctx: BuildContext<T>
): Promise<void> {
if (ctx.workflow === Workflow.GENERIC || ctx.buildProfile?.env?.GOOGLE_SERVICES_FILE) {
return;
}
const googleServicesFilePath = ctx.exp[ctx.platform]?.googleServicesFile;
if (!googleServicesFilePath) {
return;
}
const rootDir = await vcs.getRootPathAsync();
const absGoogleServicesFilePath = path.resolve(ctx.projectDir, googleServicesFilePath);
if (
(await fs.pathExists(googleServicesFilePath)) &&
((await vcs.isFileIgnoredAsync(googleServicesFilePath)) ||
!isInsideDirectory(absGoogleServicesFilePath, rootDir))
) {
Log.warn(
`File specified via "${ctx.platform}.googleServicesFile" field in your app.json is not checked in to your repository and won't be uploaded to the builder.`
);
Log.warn(
`Use EAS Secret to pass all values that you don't want to include in your version control. ${learnMore(
'https://docs.expo.dev/build-reference/variables/#using-secrets-in-environment-variables'
)}`
);
Log.warn(
'If you are using that file for compatibility with the classic build service (expo build) you can silence this warning by setting GOOGLE_SERVICES_FILE in your build profile in eas.json to any non-falsy value.'
);
Log.newLine();
}
}
function isInsideDirectory(file: string, directory: string): boolean {
return file.startsWith(directory);
}
+198 -52
View File
@@ -1,4 +1,4 @@
import { getConfig, getDefaultTarget } from '@expo/config';
import { ExpoConfig, getConfig, getDefaultTarget } from '@expo/config';
import { getRuntimeVersionForSDKVersion } from '@expo/sdk-runtime-versions';
import { Command, flags } from '@oclif/command';
import assert from 'assert';
@@ -10,11 +10,13 @@ import ora from 'ora';
import { graphqlClient, withErrorHandlingAsync } from '../../graphql/client';
import {
Actor,
GetUpdateGroupAsyncQuery,
Robot,
RootQueryUpdatesByGroupArgs,
Update,
UpdateInfoGroup,
User,
ViewBranchQuery,
} from '../../graphql/generated';
import { PublishMutation } from '../../graphql/mutations/PublishMutation';
import Log from '../../log';
@@ -22,7 +24,7 @@ import { findProjectRootAsync, getProjectIdAsync } from '../../project/projectUt
import {
PublishPlatform,
buildBundlesAsync,
buildUpdateInfoGroupAsync,
buildUnsortedUpdateInfoGroupAsync,
collectAssets,
uploadAssetsAsync,
} from '../../project/publish';
@@ -30,6 +32,7 @@ import { promptAsync, selectAsync } from '../../prompts';
import { formatUpdate } from '../../update/utils';
import formatFields from '../../utils/formatFields';
import vcs from '../../vcs';
import { createUpdateBranchOnAppAsync } from './create';
import { listBranchesAsync } from './list';
import { viewUpdateBranchAsync } from './view';
@@ -63,6 +66,33 @@ async function getUpdateGroupAsync({
return updatesByGroup;
}
async function ensureBranchExists({
appId,
name: branchName,
}: {
appId: string;
name: string;
}): Promise<{
id: string;
updates: Exclude<
Exclude<ViewBranchQuery['app'], null | undefined>['byId']['updateBranchByName'],
null | undefined
>['updates'];
}> {
const { app } = await viewUpdateBranchAsync({
appId,
name: branchName,
});
const updateBranch = app?.byId.updateBranchByName;
if (updateBranch) {
const { id, updates } = updateBranch;
return { id, updates };
}
const newUpdateBranch = await createUpdateBranchOnAppAsync({ appId, name: branchName });
return { id: newUpdateBranch.id, updates: [] };
}
export default class BranchPublish extends Command {
static hidden = true;
static description = 'Publish an update group to a branch.';
@@ -76,7 +106,7 @@ export default class BranchPublish extends Command {
static flags = {
message: flags.string({
description: 'Short message describing the updates.',
description: 'short message describing the updates.',
required: false,
}),
republish: flags.boolean({
@@ -98,7 +128,7 @@ export default class BranchPublish extends Command {
}),
platform: flags.enum({
char: 'p',
description: `Only publish to a single platform`,
description: `only publish to a single platform`,
options: [...defaultPublishPlatforms, 'all'],
default: 'all',
required: false,
@@ -107,13 +137,19 @@ export default class BranchPublish extends Command {
description: `return a json with the new update group.`,
default: false,
}),
auto: flags.boolean({
description:
'use the current git branch and commit message for the EAS branch and update message',
default: false,
}),
};
async run() {
let {
args: { name },
args: { name: branchName },
flags: {
json: jsonFlag,
auto: autoFlag,
message,
republish,
group,
@@ -134,32 +170,24 @@ export default class BranchPublish extends Command {
skipSDKVersionRequirement: true,
isPublicConfig: true,
});
let { runtimeVersion, sdkVersion } = exp;
// When a SDK version is supplied instead of a runtime version and we're in the managed workflow
// construct the runtimeVersion with special meaning indicating that the runtime is an
// Expo SDK preset runtime that can be launched in Expo Go.
const isManagedProject = getDefaultTarget(projectDir) === 'managed';
if (!runtimeVersion && sdkVersion && isManagedProject) {
Log.withTick('Generating runtime version from sdk version');
runtimeVersion = getRuntimeVersionForSDKVersion(sdkVersion);
}
const runtimeVersions = getRuntimeVersionObject(exp, platformFlag, projectDir);
if (!runtimeVersion) {
throw new Error(
"Couldn't find 'runtimeVersion'. Please specify it under the 'expo' key in 'app.json'"
);
}
const projectId = await getProjectIdAsync(exp);
if (!name) {
if (!branchName && autoFlag) {
branchName =
(await vcs.getBranchNameAsync()) || `branch-${Math.random().toString(36).substr(2, 4)}`;
}
if (!branchName) {
const validationMessage = 'branch name may not be empty.';
if (jsonFlag) {
throw new Error(validationMessage);
}
const branches = await listBranchesAsync({ projectId });
name = await selectAsync<string>(
branchName = await selectAsync<string>(
'which branch would you like to publish on?',
branches.map(branch => {
return {
@@ -170,15 +198,15 @@ export default class BranchPublish extends Command {
};
})
);
assert(branchName, 'branch name must be specified.');
}
assert(name, 'branch name must be specified.');
const { id: branchId, updates } = await viewUpdateBranchAsync({
const { id: branchId, updates } = await ensureBranchExists({
appId: projectId,
name,
name: branchName,
});
let updateInfoGroup: UpdateInfoGroup = {};
let unsortedUpdateInfoGroups: UpdateInfoGroup = {};
let oldMessage: string, oldRuntimeVersion: string;
if (republish) {
// If we are republishing, we don't need to worry about building the bundle or uploading the assets.
@@ -206,7 +234,7 @@ export default class BranchPublish extends Command {
}));
if (updateGroups.length === 0) {
throw new Error(
`There are no updates on branch "${name}" published on the platform(s) ${platformFlag}. Did you mean to publish a new update instead?`
`There are no updates on branch "${branchName}" published on the platform(s) ${platformFlag}. Did you mean to publish a new update instead?`
);
}
@@ -222,7 +250,7 @@ export default class BranchPublish extends Command {
);
if (updatesToRepublishFilteredByPlatform.length === 0) {
throw new Error(
`There are no updates on branch "${name}" published on the platform(s) "${platformFlag}" with group ID "${
`There are no updates on branch "${branchName}" published on the platform(s) "${platformFlag}" with group ID "${
group ? group : updatesToRepublish[0].group
}". Did you mean to publish a new update instead?`
);
@@ -245,7 +273,7 @@ export default class BranchPublish extends Command {
const { manifestFragment } = update;
const platform = update.platform as PublishPlatform;
updateInfoGroup[platform] = JSON.parse(manifestFragment);
unsortedUpdateInfoGroups[platform] = JSON.parse(manifestFragment);
}
// These are the same for each member of an update group
@@ -263,7 +291,7 @@ export default class BranchPublish extends Command {
const platforms = platformFlag === 'all' ? defaultPublishPlatforms : [platformFlag];
const assets = collectAssets({ inputDir: inputDir!, platforms });
await uploadAssetsAsync(assets);
updateInfoGroup = await buildUpdateInfoGroupAsync(assets, exp);
unsortedUpdateInfoGroups = await buildUnsortedUpdateInfoGroupAsync(assets, exp);
assetSpinner.succeed('Uploaded assets!');
} catch (e) {
assetSpinner.fail('Failed to upload assets');
@@ -271,6 +299,10 @@ export default class BranchPublish extends Command {
}
}
if (!message && autoFlag) {
message = (await vcs.getLastCommitMessageAsync())?.trim();
}
if (!message) {
const validationMessage = 'publish message may not be empty.';
if (jsonFlag) {
@@ -287,15 +319,38 @@ export default class BranchPublish extends Command {
}));
}
let newUpdateGroup;
const runtimeToPlatformMapping: Record<string, string[]> = {};
for (const runtime of new Set(Object.values(runtimeVersions))) {
runtimeToPlatformMapping[runtime] = Object.entries(runtimeVersions)
.filter(pair => pair[1] === runtime)
.map(pair => pair[0]);
}
// Sort the updates into different groups based on their platform specific runtime versions
const updateGroups = Object.entries(runtimeToPlatformMapping).map(([runtime, platforms]) => {
const localUpdateInfoGroup = Object.fromEntries(
platforms.map(platform => [
platform,
unsortedUpdateInfoGroups[platform as keyof UpdateInfoGroup],
])
);
if (republish && !oldRuntimeVersion) {
throw new Error(
'Can not find the runtime version of the update group that is being republished.'
);
}
return {
branchId,
updateInfoGroup: localUpdateInfoGroup,
runtimeVersion: republish ? oldRuntimeVersion : runtime,
message,
};
});
let newUpdates;
const publishSpinner = ora('Publishing...').start();
try {
newUpdateGroup = await PublishMutation.publishUpdateGroupAsync({
branchId,
updateInfoGroup,
runtimeVersion: republish ? oldRuntimeVersion! : runtimeVersion,
message,
});
newUpdates = await PublishMutation.publishUpdateGroupAsync(updateGroups);
publishSpinner.succeed('Published!');
} catch (e) {
publishSpinner.fail('Failed to published updates');
@@ -303,27 +358,118 @@ export default class BranchPublish extends Command {
}
if (jsonFlag) {
Log.log(JSON.stringify(newUpdateGroup));
Log.log(JSON.stringify(newUpdates));
} else {
Log.log(
formatFields([
{ label: 'branch', value: name },
{ label: 'runtime version', value: runtimeVersion },
{ label: 'update group ID', value: newUpdateGroup.group },
{ label: 'message', value: message },
])
);
if (new Set(newUpdates.map(update => update.group)).size > 1) {
Log.addNewLineIfNone();
Log.log(
'👉 Since multiple runtime versions are defined, multiple update groups have been published.'
);
}
Log.addNewLineIfNone();
for (const runtime of new Set(Object.values(runtimeVersions))) {
const platforms = newUpdates
.filter(update => update.runtimeVersion === runtime)
.map(update => update.platform);
const newUpdate = newUpdates.find(update => update.runtimeVersion === runtime);
if (!newUpdate) {
throw new Error(`Publish response is missing updates with runtime ${runtime}.`);
}
Log.log(
formatFields([
{ label: 'branch', value: branchName },
{ label: 'runtime version', value: runtime },
{ label: 'platform', value: platforms.join(',') },
{ label: 'update group ID', value: newUpdate.group },
{ label: 'message', value: message },
])
);
Log.addNewLineIfNone();
}
}
}
}
function formatUpdateTitle(
update: Pick<Update, 'message' | 'createdAt' | 'runtimeVersion'> & {
actor?: Pick<Actor, 'firstName'> | null;
function getRuntimeVersionObject(
exp: ExpoConfig,
platformFlag: string,
projectDir: string
): Record<string, string> {
let { runtimeVersion: defaultRuntimeVersion, sdkVersion } = exp;
// When a SDK version is supplied instead of a runtime version and we're in the managed workflow
// construct the runtimeVersion with special meaning indicating that the runtime is an
// Expo SDK preset runtime that can be launched in Expo Go.
const isManagedProject = getDefaultTarget(projectDir) === 'managed';
if (!defaultRuntimeVersion && sdkVersion && isManagedProject) {
Log.withTick('Generating runtime version from sdk version');
defaultRuntimeVersion = getRuntimeVersionForSDKVersion(sdkVersion);
}
const iOSRuntimeVersion = (exp as any).ios?.runtimeVersion; // TODO-JJ remove cast to any
const androidRuntimeVersion = (exp as any).android?.runtimeVersion; // TODO-JJ remove cast to any
let runtimeVersions: Record<string, string>;
switch (platformFlag) {
case 'ios': {
runtimeVersions = {
ios: iOSRuntimeVersion ?? defaultRuntimeVersion,
};
break;
}
case 'android': {
runtimeVersions = {
android: androidRuntimeVersion ?? defaultRuntimeVersion,
};
break;
}
case 'all': {
runtimeVersions = {
ios: iOSRuntimeVersion ?? defaultRuntimeVersion,
android: androidRuntimeVersion ?? defaultRuntimeVersion,
};
break;
}
default:
throw new Error('Platform flag must be "ios", "android", or "all"');
}
if (Object.values(runtimeVersions).some(runtime => !runtime)) {
throw new Error(
"Couldn't find a 'runtimeVersion' for every platform. Please specify it under the 'expo' key in 'app.json'"
);
}
if (Object.values(runtimeVersions).some(runtime => typeof runtime !== 'string')) {
throw new Error(
`Please ensure that all of the runtime versions defined in the app.json are strings.`
);
}
return runtimeVersions;
}
function formatUpdateTitle(
update: Exclude<
Exclude<ViewBranchQuery['app'], null | undefined>['byId']['updateBranchByName'],
null | undefined
>['updates'][number]
): string {
const { message, createdAt, actor, runtimeVersion } = update;
return `[${dateFormat(createdAt, 'mmm dd HH:MM')} by ${
actor?.firstName ?? 'unknown'
}, runtimeVersion: ${runtimeVersion}] ${message}`;
let actorName: string;
switch (actor?.__typename) {
case 'User': {
actorName = (actor as Pick<User, 'username' | 'id'>).username;
break;
}
case 'Robot': {
const { firstName, id } = actor as Pick<Robot, 'firstName' | 'id'>;
actorName = firstName ?? `robot: ${id.slice(0, 4)}...`;
break;
}
default:
actorName = 'unknown';
}
return `[${dateFormat(
createdAt,
'mmm dd HH:MM'
)} by ${actorName}, runtimeVersion: ${runtimeVersion}] ${message}`;
}
+8 -25
View File
@@ -6,15 +6,7 @@ import gql from 'graphql-tag';
import { groupBy } from 'lodash';
import { graphqlClient, withErrorHandlingAsync } from '../../graphql/client';
import {
Maybe,
Robot,
Update,
UpdateBranch,
User,
ViewBranchQuery,
ViewBranchQueryVariables,
} from '../../graphql/generated';
import { ViewBranchQuery, ViewBranchQueryVariables } from '../../graphql/generated';
import Log from '../../log';
import { findProjectRootAsync, getProjectIdAsync } from '../../project/projectUtils';
import { promptAsync } from '../../prompts';
@@ -26,16 +18,7 @@ const PAGE_LIMIT = 10_000;
export async function viewUpdateBranchAsync({
appId,
name,
}: Pick<ViewBranchQueryVariables, 'appId' | 'name'>): Promise<
Pick<UpdateBranch, 'id' | 'name'> & {
updates: (Pick<
Update,
'id' | 'group' | 'message' | 'createdAt' | 'runtimeVersion' | 'platform' | 'manifestFragment'
> & {
actor?: Maybe<Pick<User, 'firstName' | 'id'> | Pick<Robot, 'firstName' | 'id'>>;
})[];
}
> {
}: Pick<ViewBranchQueryVariables, 'appId' | 'name'>): Promise<ViewBranchQuery> {
const data = await withErrorHandlingAsync(
graphqlClient
.query<ViewBranchQuery, ViewBranchQueryVariables>(
@@ -78,11 +61,7 @@ export async function viewUpdateBranchAsync({
)
.toPromise()
);
const updateBranch = data.app?.byId.updateBranchByName;
if (!updateBranch) {
throw new Error(`Could not find branch "${name}"`);
}
return updateBranch;
return data;
}
export default class BranchView extends Command {
@@ -131,10 +110,14 @@ export default class BranchView extends Command {
}));
}
const UpdateBranch = await viewUpdateBranchAsync({
const { app } = await viewUpdateBranchAsync({
appId: projectId,
name,
});
const UpdateBranch = app?.byId.updateBranchByName;
if (!UpdateBranch) {
throw new Error(`Could not find branch "${name}"`);
}
const updates = Object.values(groupBy(UpdateBranch.updates, u => u.group)).map(
group => group[0]
@@ -56,7 +56,7 @@ function logSuccess(platform: RequestedPlatform) {
- Run ${chalk.bold('eas build')} when you are ready to create your first build.
- Once the build is completed, run ${chalk.bold('eas submit')} to upload the app to ${storesText}
- ${learnMore('https://docs.expo.io/build/introduction', {
- ${learnMore('https://docs.expo.dev/build/introduction', {
learnMoreMessage: 'Learn more about other capabilities of EAS Build',
})}`);
}
+17 -3
View File
@@ -26,6 +26,7 @@ import {
import { validateMetroConfigForManagedWorkflowAsync } from '../../project/metroConfig';
import { findProjectRootAsync } from '../../project/projectUtils';
import { confirmAsync, promptAsync } from '../../prompts';
import { enableJsonOutput } from '../../utils/json';
import vcs from '../../vcs';
interface RawBuildFlags {
@@ -37,6 +38,7 @@ interface RawBuildFlags {
local: boolean;
wait: boolean;
'clear-cache': boolean;
json: boolean;
}
interface BuildFlags {
@@ -47,6 +49,7 @@ interface BuildFlags {
local: boolean;
wait: boolean;
clearCache: boolean;
json: boolean;
}
export default class Build extends EasCommand {
@@ -58,6 +61,10 @@ export default class Build extends EasCommand {
default: false,
hidden: true,
}),
json: flags.boolean({
description: 'Enable JSON output, non-JSON messages will be printed to stderr',
default: false,
}),
'skip-project-configuration': flags.boolean({
default: false,
description: 'Skip project configuration',
@@ -87,6 +94,9 @@ export default class Build extends EasCommand {
async run(): Promise<void> {
const { flags: rawFlags } = this.parse(Build);
if (rawFlags.json) {
enableJsonOutput();
}
const flags = await this.sanitizeFlagsAsync(rawFlags);
const { requestedPlatform } = flags;
@@ -139,7 +149,7 @@ export default class Build extends EasCommand {
if (flags.wait) {
const builds = await waitForBuildEndAsync(startedBuilds.map(build => build.id));
printBuildResults(builds);
printBuildResults(builds, flags.json);
this.exitWithNonZeroCodeIfSomeBuildsFailed(builds);
}
}
@@ -149,6 +159,9 @@ export default class Build extends EasCommand {
if (!flags.platform && nonInteractive) {
throw new Error('--platform is required when building in non-interactive mode');
}
if (flags.json && !nonInteractive) {
throw new Error('--json is allowed only when building in non-interactive mode');
}
const requestedPlatform =
(flags.platform as RequestedPlatform | undefined) ?? (await this.promptForPlatformAsync());
@@ -176,6 +189,7 @@ export default class Build extends EasCommand {
local: flags['local'],
wait: flags['wait'],
clearCache: flags['clear-cache'],
json: flags['json'],
};
}
@@ -232,7 +246,7 @@ export async function handleDeprecatedEasJsonAsync(
if (nonInteractive) {
Log.error('We detected that your eas.json is using a deprecated format.');
Log.error(
'We will convert it automatically if run this command without --non-interactive flag. Alternatively, you can update eas.json manually according to https://docs.expo.io/build/eas-json'
'We will convert it automatically if run this command without --non-interactive flag. Alternatively, you can update eas.json manually according to https://docs.expo.dev/build/eas-json'
);
error('Unsupported eas.json format', { exit: 1 });
}
@@ -254,7 +268,7 @@ export async function handleDeprecatedEasJsonAsync(
}
} else {
Log.error(
"Aborting, update your eas.json according to https://docs.expo.io/build/eas-json and run 'eas build' again"
"Aborting, update your eas.json according to https://docs.expo.dev/build/eas-json and run 'eas build' again"
);
error('Unsupported eas.json format', { exit: 1 });
}
+16 -4
View File
@@ -17,6 +17,7 @@ import {
getProjectFullNameAsync,
getProjectIdAsync,
} from '../../project/projectUtils';
import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
export default class BuildList extends Command {
static description = 'list all builds for your project';
@@ -25,6 +26,9 @@ export default class BuildList extends Command {
platform: flags.enum({
options: [RequestedPlatform.All, RequestedPlatform.Android, RequestedPlatform.Ios],
}),
json: flags.boolean({
description: 'Enable JSON output, non-JSON messages will be printed to stderr',
}),
status: flags.enum({
options: [
BuildStatus.NEW,
@@ -56,11 +60,15 @@ export default class BuildList extends Command {
async run() {
const { flags } = this.parse(BuildList);
const {
json,
platform: requestedPlatform,
status: buildStatus,
distribution: buildDistribution,
limit = 10,
} = flags;
if (json) {
enableJsonOutput();
}
const platform = toAppPlatform(requestedPlatform);
const graphqlBuildStatus = toGraphQLBuildStatus(buildStatus);
@@ -100,11 +108,15 @@ export default class BuildList extends Command {
spinner.succeed(`Showing last ${builds.length} builds for the project ${projectName}`);
}
const list = builds
.map(build => formatGraphQLBuild(build))
.join(`\n\n${chalk.dim('———')}\n\n`);
if (json) {
printJsonOnlyOutput(builds);
} else {
const list = builds
.map(build => formatGraphQLBuild(build))
.join(`\n\n${chalk.dim('———')}\n\n`);
Log.log(`\n${list}`);
Log.log(`\n${list}`);
}
} else {
spinner.fail(`Couldn't find any builds for the project ${projectName}`);
}
+20 -3
View File
@@ -1,5 +1,5 @@
import { getConfig } from '@expo/config';
import { Command } from '@oclif/command';
import { Command, flags } from '@oclif/command';
import ora from 'ora';
import { formatGraphQLBuild } from '../../build/utils/formatBuild';
@@ -11,14 +11,27 @@ import {
getProjectFullNameAsync,
getProjectIdAsync,
} from '../../project/projectUtils';
import { enableJsonOutput, printJsonOnlyOutput } from '../../utils/json';
export default class BuildView extends Command {
static description = 'view a build for your project';
static args = [{ name: 'BUILD_ID' }];
static flags = {
json: flags.boolean({
description: 'Enable JSON output, non-JSON messages will be printed to stderr',
}),
};
async run() {
const { BUILD_ID: buildId } = this.parse(BuildView).args;
const {
args: { BUILD_ID: buildId },
flags,
} = this.parse(BuildView);
if (flags.json) {
enableJsonOutput();
}
const projectDir = (await findProjectRootAsync()) ?? process.cwd();
const { exp } = getConfig(projectDir, { skipSDKVersionRequirement: true });
@@ -47,7 +60,11 @@ export default class BuildView extends Command {
spinner.succeed(`Showing the last build for the project ${projectName}`);
}
Log.log(`\n${formatGraphQLBuild(build)}`);
if (flags.json) {
printJsonOnlyOutput(build);
} else {
Log.log(`\n${formatGraphQLBuild(build)}`);
}
} catch (err) {
if (buildId) {
spinner.fail(`Something went wrong and we couldn't fetch the build with id ${buildId}`);
+89 -37
View File
@@ -1,6 +1,8 @@
import { getConfig } from '@expo/config';
import { Platform } from '@expo/eas-build-job';
import { flags } from '@oclif/command';
import { EasJsonReader } from '../../../eas-json/build';
import EasCommand from '../commandUtils/EasCommand';
import { AppPlatform } from '../graphql/generated';
import { learnMore } from '../log';
@@ -15,6 +17,13 @@ const COMMON_FLAGS = '';
const ANDROID_FLAGS = 'Android specific options';
const IOS_FLAGS = 'iOS specific options';
interface Flags {
platform?: Platform;
profile?: string;
iosOptions: Partial<IosSubmitCommandFlags>;
androidOptions: Partial<AndroidSubmitCommandFlags>;
}
export default class BuildSubmit extends EasCommand {
static description = 'Submits build artifact to app store';
static usage = 'submit --platform=(android|ios)';
@@ -41,6 +50,9 @@ export default class BuildSubmit extends EasCommand {
}),
/* Common flags for both platforms */
profile: flags.string({
description: 'Name of the submit profile from eas.json',
}),
latest: flags.boolean({
description: 'Submit the latest build for specified platform',
exclusive: ['id', 'path', 'url'],
@@ -65,7 +77,6 @@ export default class BuildSubmit extends EasCommand {
verbose: flags.boolean({
description: 'Always print logs from Submission Service',
default: false,
helpLabel: COMMON_FLAGS,
}),
@@ -77,7 +88,8 @@ export default class BuildSubmit extends EasCommand {
}),
key: flags.string({
description: 'Path to the JSON key used to authenticate with Google Play',
description:
'Path to the JSON file with service account key used to authenticate with Google Play',
helpLabel: ANDROID_FLAGS,
}),
'android-package': flags.string({
@@ -86,14 +98,17 @@ export default class BuildSubmit extends EasCommand {
}),
track: flags.enum({
description: 'The track of the application to use',
default: 'internal',
description: '[default: internal] The track of the application to use',
options: ['production', 'beta', 'alpha', 'internal', 'rollout'],
helpLabel: ANDROID_FLAGS,
}),
'changes-not-sent-for-review': flags.boolean({
description:
'[default: false] Indicates that the changes sent with this submission will not be reviewed until they are explicitly sent for review from the Google Play Console UI',
helpLabel: ANDROID_FLAGS,
}),
'release-status': flags.enum({
description: 'Release status (used when uploading new APKs/AABs)',
default: 'completed',
description: '[default: completed] Release status (used when uploading new APKs/AABs)',
options: ['completed', 'draft', 'halted', 'inProgress'],
helpLabel: ANDROID_FLAGS,
}),
@@ -129,8 +144,7 @@ export default class BuildSubmit extends EasCommand {
helpLabel: IOS_FLAGS,
}),
language: flags.string({
description: 'Primary language (e.g. English, German, ...)',
default: 'en-US',
description: '[default: en-US] Primary language (e.g. English, German, ...)',
helpLabel: IOS_FLAGS,
}),
'company-name': flags.string({
@@ -141,25 +155,7 @@ export default class BuildSubmit extends EasCommand {
};
async run(): Promise<void> {
const {
flags: {
// android
'android-package': androidPackage,
'release-status': releaseStatus,
// ios
'apple-id': appleId,
'asc-app-id': ascAppId,
'apple-team-id': appleTeamId,
'app-name': appName,
'bundle-identifier': bundleIdentifier,
'company-name': companyName,
// common
...flags
},
} = this.parse(BuildSubmit);
const flags = this.parseFlags();
const platform =
(flags.platform?.toUpperCase() as AppPlatform | undefined) ??
(await promptForPlatformAsync());
@@ -178,26 +174,33 @@ export default class BuildSubmit extends EasCommand {
if (!projectDir) {
throw new Error("Please run this command inside your project's directory");
}
const easJsonReader = new EasJsonReader(projectDir);
if (platform === AppPlatform.Android) {
const submitProfile = flags.profile
? await easJsonReader.readSubmitProfileAsync(flags.profile, Platform.ANDROID)
: {};
const options: AndroidSubmitCommandFlags = {
androidPackage,
releaseStatus,
...flags,
releaseStatus: 'completed',
track: 'internal',
verbose: false,
changesNotSentForReview: false,
...submitProfile,
...flags.androidOptions,
};
const ctx = AndroidSubmitCommand.createContext(projectDir, projectId, options);
const command = new AndroidSubmitCommand(ctx);
await command.runAsync();
} else if (platform === AppPlatform.Ios) {
const submitProfile = flags.profile
? await easJsonReader.readSubmitProfileAsync(flags.profile, Platform.IOS)
: {};
const options: IosSubmitCommandFlags = {
appleId,
ascAppId,
appleTeamId,
appName,
bundleIdentifier,
companyName,
...flags,
language: 'en-US',
verbose: false,
...submitProfile,
...flags.iosOptions,
};
const ctx = IosSubmitCommand.createContext(projectDir, projectId, options);
@@ -207,6 +210,55 @@ export default class BuildSubmit extends EasCommand {
throw new Error(`Unsupported platform: ${platform}!`);
}
}
private parseFlags(): Flags {
const {
flags: {
platform,
profile,
// android
'android-package': androidPackage,
'release-status': releaseStatus,
'changes-not-sent-for-review': changesNotSentForReview,
track,
type,
key: serviceAccountKeyPath,
// ios
'apple-id': appleId,
'asc-app-id': ascAppId,
'apple-team-id': appleTeamId,
'app-name': appName,
'bundle-identifier': bundleIdentifier,
'company-name': companyName,
// common
...flags
},
} = this.parse(BuildSubmit);
return {
platform: platform as Platform,
profile,
androidOptions: {
...(androidPackage && { androidPackage }),
...(releaseStatus && { releaseStatus }),
...(track && { track }),
...(changesNotSentForReview && { changesNotSentForReview }),
...(serviceAccountKeyPath && { serviceAccountKeyPath }),
...flags,
},
iosOptions: {
...(appleId && { appleId }),
...(ascAppId && { ascAppId }),
...(appleTeamId && { appleTeamId }),
...(appName && { appName }),
...(bundleIdentifier && { bundleIdentifier }),
...(companyName && { companyName }),
...flags,
},
};
}
}
async function promptForPlatformAsync(): Promise<AppPlatform> {
@@ -54,7 +54,7 @@ export class RemoveKeystore {
)
);
Log.warn(
'Please read https://docs.expo.io/distribution/building-standalone-apps/#if-you-choose-to-build-for-android for more info before proceeding.'
'Please read https://docs.expo.dev/distribution/building-standalone-apps/#if-you-choose-to-build-for-android for more info before proceeding.'
);
Log.newLine();
Log.warn(
@@ -221,7 +221,7 @@ async function generateDistributionCertificateAsync(
`✅ Distribution Certificates can be revoked with no side effects for App Store builds.`
)
);
Log.log(learnMore('https://docs.expo.io/distribution/app-signing/#summary'));
Log.log(learnMore('https://docs.expo.dev/distribution/app-signing/#summary'));
Log.newLine();
const { distCertsToRevoke } = await promptAsync({
@@ -80,7 +80,7 @@ async function generatePushKeyAsync(ctx: Context, accountName: string): Promise<
}
Log.log(chalk.grey(`⚠️ Revoking a Push Key will affect other apps that rely on it`));
Log.log(learnMore('https://docs.expo.io/distribution/app-signing/#push-notification-keys'));
Log.log(learnMore('https://docs.expo.dev/distribution/app-signing/#push-notification-keys'));
Log.log();
const { pushKeysToRevoke } = await promptAsync({
@@ -32,7 +32,7 @@ const IosAppCredentialsQuery = {
},
appSpecificPassword: {
id: '64bdd007-da7b-4190-a571-edb87e9324a1',
appleIdUsername: 'quin@expo.io',
appleIdUsername: 'quin@expo.dev',
passwordLabel: 'description for super secret password',
updatedAt: '2020-10-13T18:39:04.463Z',
__typename: 'AppleAppSpecificPassword',
@@ -152,7 +152,14 @@ export async function ensureAppExistsAsync(
language,
companyName,
bundleIdentifier,
}: { name: string; language?: string; companyName?: string; bundleIdentifier: string }
sku,
}: {
name: string;
language?: string;
companyName?: string;
bundleIdentifier: string;
sku?: string;
}
) {
const context = getRequestContext(authCtx);
const spinner = ora(`Linking to App Store ${chalk.dim(bundleIdentifier)}`).start();
@@ -170,6 +177,7 @@ export async function ensureAppExistsAsync(
name,
primaryLocale: language,
companyName,
sku,
});
} catch (error) {
if (error.message.match(/An App ID with Identifier '(.*)' is not available/)) {
@@ -81,11 +81,11 @@ export async function promptPasswordAsync({
if (cachedPassword) {
Log.log(`\u203A Using password for ${username} from your local Keychain`);
Log.log(` ${learnMore('https://docs.expo.io/distribution/security#keychain')}`);
Log.log(` ${learnMore('https://docs.expo.dev/distribution/security#keychain')}`);
return cachedPassword;
}
// https://docs.expo.io/distribution/security/#apple-developer-account-credentials
// https://docs.expo.dev/distribution/security/#apple-developer-account-credentials
Log.log(
wrapAnsi(
chalk.bold(
@@ -160,7 +160,7 @@ async function cachePasswordAsync({ username, password }: Auth.UserCredentials):
}
Log.log(`\u203A Saving Apple ID password to the local Keychain`);
Log.log(` ${learnMore('https://docs.expo.io/distribution/security#keychain')}`);
Log.log(` ${learnMore('https://docs.expo.dev/distribution/security#keychain')}`);
const serviceName = getKeychainServiceName(username);
return Keychain.setPasswordAsync({ username, password, serviceName });
}
@@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`print credentials prints the IosAppCredentials map 1`] = `"iOS Credentials Project: @quinlanj/test52 Bundle Identifier: com.quinlanj.test52 Apple Team: test-apple-identifier Push Key: Developer Portal ID: 9839M6AY8W Apple Team: 77KQ969CHE Updated 6 months ago App Specific Password: Apple ID Username: quin@expo.io Password Label: description for super secret password Updated 6 months ago Configuration: App Store Distribution Certificate: Serial Number: test-serial Expiration Date: Wed, 13 Oct 2021 18:28:44 GMT+0000 Apple Team: test-apple-identifier Updated 6 months ago Provisioning Profile: Developer Portal ID: test-profile-id Status: active Expiration Date: Wed, 13 Oct 2021 18:28:44 GMT+0000 Apple Team: test-apple-identifier Updated 5 months ago Configuration: Ad Hoc Distribution Certificate: Serial Number: test-serial Expiration Date: Wed, 13 Oct 2021 18:28:44 GMT+0000 Apple Team: test-apple-identifier Updated 6 months ago Provisioning Profile: Developer Portal ID: test-profile-id Status: active Expiration Date: Wed, 13 Oct 2021 18:28:44 GMT+0000 Apple Team: test-apple-identifier Updated 5 months ago"`;
exports[`print credentials prints the IosAppCredentials map 1`] = `"iOS Credentials Project: @quinlanj/test52 Bundle Identifier: com.quinlanj.test52 Apple Team: test-apple-identifier Push Key: Developer Portal ID: 9839M6AY8W Apple Team: 77KQ969CHE Updated 6 months ago App Specific Password: Apple ID Username: quin@expo.dev Password Label: description for super secret password Updated 6 months ago Configuration: App Store Distribution Certificate: Serial Number: test-serial Expiration Date: Wed, 13 Oct 2021 18:28:44 GMT+0000 Apple Team: test-apple-identifier Updated 6 months ago Provisioning Profile: Developer Portal ID: test-profile-id Status: active Expiration Date: Wed, 13 Oct 2021 18:28:44 GMT+0000 Apple Team: test-apple-identifier Updated 5 months ago Configuration: Ad Hoc Distribution Certificate: Serial Number: test-serial Expiration Date: Wed, 13 Oct 2021 18:28:44 GMT+0000 Apple Team: test-apple-identifier Updated 6 months ago Provisioning Profile: Developer Portal ID: test-profile-id Status: active Expiration Date: Wed, 13 Oct 2021 18:28:44 GMT+0000 Apple Team: test-apple-identifier Updated 5 months ago"`;
@@ -23,7 +23,7 @@ export class SelectBuildProfileFromEasJson<T extends Platform> {
const buildProfileNames = await this.easJsonReader.getBuildProfileNamesAsync();
if (buildProfileNames.length === 0) {
throw new Error(
'You need at least one iOS build profile declared in eas.json. Go to https://docs.expo.io/build/eas-json/ for more details'
'You need at least one iOS build profile declared in eas.json. Go to https://docs.expo.dev/build/eas-json/ for more details'
);
} else if (buildProfileNames.length === 1) {
return buildProfileNames[0];
@@ -14,7 +14,9 @@ export async function runRegistrationUrlMethodAsync(
): Promise<void> {
const registrationURL = await generateDeviceRegistrationURLAsync(accountId, appleTeam);
Log.newLine();
qrcodeTerminal.generate(registrationURL, code => Log.log(`${indentString(code, 2)}\n`));
qrcodeTerminal.generate(registrationURL, { small: true }, code =>
Log.log(`${indentString(code, 2)}\n`)
);
Log.log(
'Open the following link on your iOS devices (or scan the QR code) and follow the instructions to install the development profile:'
);
+65 -16
View File
@@ -438,6 +438,7 @@ export type App = Project & {
submissions: Array<Submission>;
/** Deployments associated with this app */
deployments: Array<Deployment>;
deployment?: Maybe<Deployment>;
/** iOS app credentials for the project */
iosAppCredentials: Array<IosAppCredentials>;
/** Android app credentials for the project */
@@ -523,8 +524,16 @@ export type AppSubmissionsArgs = {
/** Represents an Exponent App (or Experience in legacy terms) */
export type AppDeploymentsArgs = {
limit: Scalars['Int'];
buildListMaxSize: Scalars['Int'];
mostRecentlyUpdatedAt?: Maybe<Scalars['DateTime']>;
options?: Maybe<DeploymentOptions>;
};
/** Represents an Exponent App (or Experience in legacy terms) */
export type AppDeploymentArgs = {
channel: Scalars['String'];
runtimeVersion: Scalars['String'];
options?: Maybe<DeploymentOptions>;
};
@@ -1010,14 +1019,19 @@ export type SubmissionFilter = {
status?: Maybe<SubmissionStatus>;
};
export type DeploymentOptions = {
/** Max number of associated builds to return */
buildListMaxSize?: Maybe<Scalars['Int']>;
};
/** Represents a Deployment - a set of Builds with the same Runtime Version and Channel */
export type Deployment = {
__typename?: 'Deployment';
id?: Maybe<Scalars['String']>;
runtimeVersion?: Maybe<Scalars['String']>;
channel?: Maybe<Scalars['String']>;
recentBuilds?: Maybe<Array<Maybe<Build>>>;
branchToReceive?: Maybe<UpdateBranch>;
id: Scalars['ID'];
runtimeVersion: Scalars['String'];
channel: Scalars['String'];
recentBuilds: Array<Build>;
branchMapping?: Maybe<UpdateBranch>;
};
export type UpdateBranch = {
@@ -1028,7 +1042,6 @@ export type UpdateBranch = {
createdAt: Scalars['DateTime'];
updatedAt: Scalars['DateTime'];
updates: Array<Update>;
mostRecentUpdateForEachPlatform: Array<Update>;
};
@@ -1208,6 +1221,7 @@ export type AndroidAppCredentials = {
app: App;
applicationIdentifier?: Maybe<Scalars['String']>;
androidFcm?: Maybe<AndroidFcm>;
googleServiceAccountKeyForSubmissions?: Maybe<GoogleServiceAccountKey>;
androidAppBuildCredentialsList: Array<AndroidAppBuildCredentials>;
isLegacy: Scalars['Boolean'];
/** @deprecated use androidAppBuildCredentialsList instead */
@@ -1250,6 +1264,18 @@ export enum AndroidFcmVersion {
V1 = 'V1'
}
export type GoogleServiceAccountKey = {
__typename?: 'GoogleServiceAccountKey';
id: Scalars['ID'];
account: Account;
projectIdentifier: Scalars['String'];
privateKeyIdentifier: Scalars['String'];
clientEmail: Scalars['String'];
clientIdentifier: Scalars['String'];
createdAt: Scalars['DateTime'];
updatedAt: Scalars['DateTime'];
};
export type AndroidAppBuildCredentials = {
__typename?: 'AndroidAppBuildCredentials';
id: Scalars['ID'];
@@ -2883,6 +2909,8 @@ export type SubmissionMutation = {
createSubmission: CreateSubmissionResult;
/** Create an iOS EAS Submit submission */
createIosSubmission: CreateSubmissionResult;
/** Create an Android EAS Submit submission */
createAndroidSubmission: CreateSubmissionResult;
};
@@ -2895,6 +2923,11 @@ export type SubmissionMutationCreateIosSubmissionArgs = {
input: CreateIosSubmissionInput;
};
export type SubmissionMutationCreateAndroidSubmissionArgs = {
input: CreateAndroidSubmissionInput;
};
export type CreateSubmissionInput = {
appId: Scalars['ID'];
platform: AppPlatform;
@@ -2910,11 +2943,11 @@ export type CreateSubmissionResult = {
export type CreateIosSubmissionInput = {
appId: Scalars['ID'];
config: NewIosSubmissionConfig;
config: IosSubmissionConfigInput;
submittedBuildId?: Maybe<Scalars['ID']>;
};
export type NewIosSubmissionConfig = {
export type IosSubmissionConfigInput = {
appleAppSpecificPasswordId?: Maybe<Scalars['String']>;
appleAppSpecificPassword?: Maybe<Scalars['String']>;
archiveUrl: Scalars['String'];
@@ -2922,6 +2955,22 @@ export type NewIosSubmissionConfig = {
ascAppIdentifier: Scalars['String'];
};
export type CreateAndroidSubmissionInput = {
appId: Scalars['ID'];
config: AndroidSubmissionConfigInput;
submittedBuildId?: Maybe<Scalars['ID']>;
};
export type AndroidSubmissionConfigInput = {
googleServiceAccountKeyId?: Maybe<Scalars['String']>;
googleServiceAccountKeyJson?: Maybe<Scalars['String']>;
archiveUrl: Scalars['String'];
archiveType: SubmissionAndroidArchiveType;
applicationIdentifier: Scalars['String'];
track: SubmissionAndroidTrack;
releaseStatus?: Maybe<SubmissionAndroidReleaseStatus>;
};
export type UpdateChannelMutation = {
__typename?: 'UpdateChannelMutation';
/**
@@ -2993,7 +3042,7 @@ export type UpdateBranchMutation = {
/** Delete an EAS branch and all of its updates as long as the branch is not being used by any channels */
deleteUpdateBranch: DeleteUpdateBranchResult;
/** Publish an update group to a branch */
publishUpdateGroup: Array<Update>;
publishUpdateGroups: Array<Update>;
};
@@ -3013,8 +3062,8 @@ export type UpdateBranchMutationDeleteUpdateBranchArgs = {
};
export type UpdateBranchMutationPublishUpdateGroupArgs = {
publishUpdateGroupInput?: Maybe<PublishUpdateGroupInput>;
export type UpdateBranchMutationPublishUpdateGroupsArgs = {
publishUpdateGroupsInput: Array<PublishUpdateGroupInput>;
};
export type EditUpdateBranchInput = {
@@ -3052,7 +3101,7 @@ export type PartialManifestAsset = {
fileSHA256: Scalars['String'];
bundleKey: Scalars['String'];
contentType: Scalars['String'];
storageBucket: Scalars['String'];
fileExtension?: Maybe<Scalars['String']>;
storageKey: Scalars['String'];
};
@@ -4770,7 +4819,7 @@ export type GetSignedUploadMutation = (
);
export type UpdatePublishMutationVariables = Exact<{
publishUpdateGroupInput?: Maybe<PublishUpdateGroupInput>;
publishUpdateGroupsInput: Array<PublishUpdateGroupInput>;
}>;
@@ -4778,9 +4827,9 @@ export type UpdatePublishMutation = (
{ __typename?: 'RootMutation' }
& { updateBranch: (
{ __typename?: 'UpdateBranchMutation' }
& { publishUpdateGroup: Array<(
& { publishUpdateGroups: Array<(
{ __typename?: 'Update' }
& Pick<Update, 'id' | 'group'>
& Pick<Update, 'id' | 'group' | 'runtimeVersion' | 'platform'>
)> }
) }
);
@@ -1,7 +1,7 @@
import gql from 'graphql-tag';
import { graphqlClient, withErrorHandlingAsync } from '../client';
import { PublishUpdateGroupInput, Update, UpdatePublishMutation } from '../generated';
import { PublishUpdateGroupInput, UpdatePublishMutation } from '../generated';
const PublishMutation = {
async getUploadURLsAsync(contentTypes: string[]): Promise<{ specifications: string[] }> {
@@ -30,27 +30,28 @@ const PublishMutation = {
},
async publishUpdateGroupAsync(
publishUpdateGroupInput: PublishUpdateGroupInput
): Promise<Pick<Update, 'group'>> {
publishUpdateGroupsInput: PublishUpdateGroupInput[]
): Promise<UpdatePublishMutation['updateBranch']['publishUpdateGroups']> {
const data = await withErrorHandlingAsync(
graphqlClient
.mutation<UpdatePublishMutation>(
gql`
mutation UpdatePublishMutation($publishUpdateGroupInput: PublishUpdateGroupInput) {
mutation UpdatePublishMutation($publishUpdateGroupsInput: [PublishUpdateGroupInput!]!) {
updateBranch {
publishUpdateGroup(publishUpdateGroupInput: $publishUpdateGroupInput) {
publishUpdateGroups(publishUpdateGroupsInput: $publishUpdateGroupsInput) {
id
group
runtimeVersion
platform
}
}
}
`,
{ publishUpdateGroupInput }
{ publishUpdateGroupsInput }
)
.toPromise()
);
const { group } = data.updateBranch.publishUpdateGroup[0]!;
return { group };
return data.updateBranch.publishUpdateGroups;
},
};
+1 -1
View File
@@ -85,7 +85,7 @@ export default class Log {
/**
* Format links as dim (unless disabled) with an underline.
*
* @example Learn more: https://expo.io
* @example Learn more: https://expo.dev
* @param url
*/
export function learnMore(
@@ -10,7 +10,7 @@ import { PublishQuery } from '../../graphql/queries/PublishQuery';
import {
MetadataJoi,
TIMEOUT_LIMIT,
buildUpdateInfoGroupAsync,
buildUnsortedUpdateInfoGroupAsync,
collectAssets,
convertAssetToUpdateInfoGroupFormatAsync,
filterOutAssetsThatAlreadyExistAsync,
@@ -131,23 +131,23 @@ describe(convertAssetToUpdateInfoGroupFormatAsync, () => {
it('resolves to the correct value', async () => {
const path = uuidv4();
fs.writeFileSync(path, 'I am pretending to be a jpeg');
const type = 'jpg';
const fileExtension = '.jpg';
const asset = {
type,
fileExtension,
contentType: 'image/jpeg',
path,
};
await expect(convertAssetToUpdateInfoGroupFormatAsync(asset)).resolves.toEqual({
bundleKey: 'c939e759656f577c058f445bfb19182e',
fileExtension: '.jpg',
contentType: 'image/jpeg',
fileSHA256: 'tzD6J-OQZaHCKnL3GHWV9RbnrpyojnagiOE7r3mSkU4',
storageBucket: 'update-assets-production',
storageKey: 'fo8Y08LktVk6qLtGbn8GRWpOUyD13ABMUnbtRCN1L7Y',
});
});
});
describe(buildUpdateInfoGroupAsync, () => {
describe(buildUnsortedUpdateInfoGroupAsync, () => {
const androidBundlePath = uuidv4();
const assetPath = uuidv4();
fs.writeFileSync(androidBundlePath, 'I am a js bundle');
@@ -155,17 +155,17 @@ describe(buildUpdateInfoGroupAsync, () => {
it('returns the correct value', async () => {
await expect(
buildUpdateInfoGroupAsync(
buildUnsortedUpdateInfoGroupAsync(
{
android: {
launchAsset: {
type: 'bundle',
fileExtension: '.bundle',
contentType: 'bundle/javascript',
path: androidBundlePath,
},
assets: [
{
type: 'jpg',
fileExtension: '.jpg',
contentType: 'image/jpeg',
path: assetPath,
},
@@ -182,17 +182,17 @@ describe(buildUpdateInfoGroupAsync, () => {
assets: [
{
bundleKey: 'c939e759656f577c058f445bfb19182e',
fileExtension: '.jpg',
contentType: 'image/jpeg',
fileSHA256: 'tzD6J-OQZaHCKnL3GHWV9RbnrpyojnagiOE7r3mSkU4',
storageBucket: 'update-assets-production',
storageKey: 'fo8Y08LktVk6qLtGbn8GRWpOUyD13ABMUnbtRCN1L7Y',
},
],
launchAsset: {
bundleKey: 'ec0dd14670aae108f99a810df9c1482c',
fileExtension: '.bundle',
contentType: 'bundle/javascript',
fileSHA256: 'KEw79FnKTLOyVbRT1SlohSTjPe5e8FpULy2ST-I5BUg',
storageBucket: 'update-assets-production',
storageKey: 'aC9N6RZlcHoIYjIsoJd2KUcigBKy98RHvZacDyPNjCQ',
},
extra: {
@@ -232,7 +232,7 @@ describe(collectAssets, () => {
const userDefinedAssets = [
{
type: 'jpg',
fileExtension: '.jpg',
contentType: 'image/jpeg',
path: path.resolve(`${inputDir}/assets/${fakeHash}`),
},
@@ -267,7 +267,7 @@ describe(collectAssets, () => {
expect(collectAssets({ inputDir, platforms: defaultPublishPlatforms })).toEqual({
android: {
launchAsset: {
type: 'bundle',
fileExtension: '.bundle',
contentType: 'application/javascript',
path: path.resolve(`${inputDir}/bundles/android.js`),
},
@@ -275,7 +275,7 @@ describe(collectAssets, () => {
},
ios: {
launchAsset: {
type: 'bundle',
fileExtension: '.bundle',
contentType: 'application/javascript',
path: path.resolve(`${inputDir}/bundles/ios.js`),
},
@@ -286,7 +286,7 @@ describe(collectAssets, () => {
expect(collectAssets({ inputDir, platforms: ['ios'] })).toEqual({
ios: {
launchAsset: {
type: 'bundle',
fileExtension: '.bundle',
contentType: 'application/javascript',
path: path.resolve(`${inputDir}/bundles/ios.js`),
},
@@ -1,7 +1,9 @@
import assert from 'assert';
import chalk from 'chalk';
import ora from 'ora';
import terminalLink from 'terminal-link';
import { getProjectDashboardUrl } from '../build/utils/url';
import { AppPrivacy } from '../graphql/generated';
import { AppMutation } from '../graphql/mutations/AppMutation';
import { ProjectQuery } from '../graphql/queries/ProjectQuery';
@@ -26,12 +28,14 @@ export async function ensureProjectExistsAsync(projectInfo: ProjectInfo): Promis
assert(account, `You must have access to the ${accountName} account to run this command`);
const projectFullName = `@${accountName}/${projectName}`;
const projectDashboardUrl = getProjectDashboardUrl(accountName, projectName);
const projectLink = terminalLink(projectFullName, projectDashboardUrl);
const spinner = ora(`Linking to project ${chalk.bold(projectFullName)}`).start();
const maybeId = await findProjectIdByAccountNameAndSlugNullableAsync(accountName, projectName);
if (maybeId) {
spinner.succeed(`Linked to project ${chalk.bold(projectFullName)}`);
spinner.succeed(`Linked to project ${chalk.bold(projectLink)}`);
return maybeId;
}
@@ -42,7 +46,7 @@ export async function ensureProjectExistsAsync(projectInfo: ProjectInfo): Promis
projectName,
privacy: projectInfo.privacy,
});
spinner.succeed(`Created ${chalk.bold(projectFullName)} on Expo`);
spinner.succeed(`Created ${chalk.bold(projectLink)} on Expo`);
return id;
} catch (err) {
spinner.fail();
@@ -24,7 +24,7 @@ export async function isEasEnabledForProjectAsync(projectId: string): Promise<bo
}
export const EAS_UNAVAILABLE_MESSAGE = `Your account doesn't have access to Expo Application Services (EAS) features. Enroll in EAS to give it a try: ${chalk.underline(
'https://expo.io/eas'
'https://expo.dev/eas'
)}`;
export function warnEasUnavailable() {
+1 -1
View File
@@ -28,7 +28,7 @@ export async function validateMetroConfigForManagedWorkflowAsync(ctx: BuildConte
);
Log.warn(`We recommend you to abort, fix the ${chalk.bold('metro.config.js')}, and try again.`);
Log.warn(
learnMore('https://docs.expo.io/guides/customizing-metro/', {
learnMore('https://docs.expo.dev/guides/customizing-metro/', {
learnMoreMessage: 'Learn more on customizing Metro',
})
);
+3 -3
View File
@@ -24,7 +24,7 @@ export function getProjectAccountName(exp: ExpoConfig, user: Actor): string {
case 'Robot':
if (!exp.owner) {
throw new Error(
'The "owner" manifest property is required when using robot users. See: https://docs.expo.io/versions/latest/config/app/#owner'
'The "owner" manifest property is required when using robot users. See: https://docs.expo.dev/versions/latest/config/app/#owner'
);
}
return exp.owner;
@@ -39,7 +39,7 @@ export function getUsername(exp: ExpoConfig, user: Actor): string | undefined {
// owner field is necessary to run `expo prebuild`
if (!exp.owner) {
throw new Error(
'The "owner" manifest property is required when using robot users. See: https://docs.expo.io/versions/latest/config/app/#owner'
'The "owner" manifest property is required when using robot users. See: https://docs.expo.dev/versions/latest/config/app/#owner'
);
}
// robot users don't have usernames
@@ -82,7 +82,7 @@ export async function setProjectIdAsync(
Log.warn('It looks like you are using a dynamic configuration!');
Log.log(
chalk.dim(
'https://docs.expo.io/workflow/configuration/#dynamic-configuration-with-appconfigjs)\n'
'https://docs.expo.dev/workflow/configuration/#dynamic-configuration-with-appconfigjs)\n'
)
);
Log.warn(
+15 -15
View File
@@ -16,15 +16,6 @@ import Log from '../log';
import { uploadWithPresignedPostAsync } from '../uploads';
export const TIMEOUT_LIMIT = 60_000; // 1 minute
const STORAGE_BUCKET = getStorageBucket();
function getStorageBucket(): string {
if (process.env.EXPO_STAGING || process.env.EXPO_LOCAL) {
return 'update-assets-staging';
} else {
return 'update-assets-production';
}
}
export type PublishPlatform = Extract<'android' | 'ios', Platform>;
type Metadata = {
@@ -35,7 +26,7 @@ type Metadata = {
};
};
export type RawAsset = {
type: string;
fileExtension?: string;
contentType: string;
path: string;
};
@@ -117,20 +108,24 @@ export async function convertAssetToUpdateInfoGroupFormatAsync(
asset: RawAsset
): Promise<PartialManifestAsset> {
const fileSHA256 = getBase64URLEncoding(await calculateFileHashAsync(asset.path, 'sha256'));
const contentType = asset.contentType;
const { contentType, fileExtension } = asset;
const storageKey = getStorageKey(contentType, fileSHA256);
const bundleKey = (await calculateFileHashAsync(asset.path, 'md5')).toString('hex');
return {
fileSHA256,
contentType,
storageBucket: STORAGE_BUCKET,
storageKey,
bundleKey,
fileExtension,
};
}
export async function buildUpdateInfoGroupAsync(
/**
* This will be sorted later based on the platform's runtime versions.
*/
export async function buildUnsortedUpdateInfoGroupAsync(
assets: CollectedAssets,
exp: ExpoConfig
): Promise<UpdateInfoGroup> {
@@ -230,13 +225,18 @@ export function collectAssets({
for (const platform of platforms) {
assetsFinal[platform] = {
launchAsset: {
type: 'bundle',
fileExtension: '.bundle',
contentType: 'application/javascript',
path: path.resolve(distRoot, metadata.fileMetadata[platform].bundle),
},
assets: metadata.fileMetadata[platform].assets.map(asset => {
let fileExtension;
if (asset.ext) {
// ensure the file extension has a '.' prefix
fileExtension = asset.ext.startsWith('.') ? asset.ext : `.${asset.ext}`;
}
return {
type: asset.ext,
fileExtension,
contentType: guessContentTypeFromExtension(asset.ext),
path: path.join(distRoot, asset.path),
};
@@ -1,15 +1,20 @@
import { getConfig } from '@expo/config';
import chalk from 'chalk';
import ora from 'ora';
import { getExpoWebsiteBaseUrl } from '../api';
import { AppPlatform, SubmissionFragment, SubmissionStatus } from '../graphql/generated';
import Log from '../log';
import { getProjectAccountNameAsync } from '../project/projectUtils';
import { sleep } from '../utils/promise';
import SubmissionService, {
DEFAULT_CHECK_INTERVAL_MS,
SubmissionConfig,
} from './SubmissionService';
import { BaseSubmissionContext } from './types';
import { displayLogs } from './utils/logs';
abstract class BaseSubmitter<SubmissionContext, SubmissionOptions> {
abstract class BaseSubmitter<SubmissionContext extends BaseSubmissionContext, SubmissionOptions> {
protected abstract readonly appStoreName: string;
protected constructor(
@@ -41,10 +46,19 @@ abstract class BaseSubmitter<SubmissionContext, SubmissionOptions> {
throw err;
}
const projectUrl = await this.getProjectUrlAsync();
const submissionUrl = `${projectUrl}/submissions/${submissionId}`;
Log.newLine();
Log.log(`Submission details: ${chalk.underline(submissionUrl)}`);
Log.log(`Waiting for submission to finish. You can press Ctrl + C to exit`);
Log.newLine();
let submissionCompleted = false;
let submissionStatus: SubmissionStatus | null = null;
let submission: SubmissionFragment | null = null;
const submissionSpinner = ora(`Submitting your app to ${this.appStoreName}`).start();
try {
while (!submissionCompleted) {
await sleep(DEFAULT_CHECK_INTERVAL_MS);
@@ -52,6 +66,7 @@ abstract class BaseSubmitter<SubmissionContext, SubmissionOptions> {
submissionStatus = submission.status;
submissionSpinner.text = this.getStatusText(submissionStatus);
if (submissionStatus === SubmissionStatus.Errored) {
submissionCompleted = true;
process.exitCode = 1;
@@ -83,6 +98,16 @@ abstract class BaseSubmitter<SubmissionContext, SubmissionOptions> {
throw new Error('This should never happen');
}
}
private async getProjectUrlAsync(): Promise<string> {
const projectDir = this.ctx.projectDir;
const { exp } = getConfig(projectDir, { skipSDKVersionRequirement: true });
const accountName = await getProjectAccountNameAsync(exp);
const projectName = exp.slug;
const submissionUrl = `${getExpoWebsiteBaseUrl()}/accounts/${accountName}/projects/${projectName}`;
return submissionUrl;
}
}
export default BaseSubmitter;
@@ -8,6 +8,7 @@ export interface AndroidSubmissionConfig {
track: ReleaseTrack;
serviceAccount: string;
releaseStatus?: ReleaseStatus;
changesNotSentForReview: boolean;
}
export enum ReleaseStatus {
@@ -3,6 +3,7 @@ import { Result, result } from '@expo/results';
import { AppPlatform } from '../../graphql/generated';
import Log from '../../log';
import { getApplicationIdAsync } from '../../project/android/applicationId';
import { ArchiveSource, ArchiveTypeSource, ArchiveTypeSourceType } from '../archiveSource';
import { resolveArchiveFileSource } from '../commons';
import { AndroidArchiveType, AndroidSubmissionContext, AndroidSubmitCommandFlags } from '../types';
@@ -28,13 +29,13 @@ class AndroidSubmitCommand {
async runAsync(): Promise<void> {
Log.addNewLineIfNone();
const submissionOptions = this.getAndroidSubmissionOptions();
const submissionOptions = await this.getAndroidSubmissionOptionsAsync();
const submitter = new AndroidSubmitter(this.ctx, submissionOptions);
await submitter.submitAsync();
}
private getAndroidSubmissionOptions(): AndroidSubmissionOptions {
const androidPackageSource = this.resolveAndroidPackageSource();
private async getAndroidSubmissionOptionsAsync(): Promise<AndroidSubmissionOptions> {
const androidPackageSource = await this.resolveAndroidPackageSourceAsync();
const track = this.resolveTrack();
const releaseStatus = this.resolveReleaseStatus();
const archiveSource = this.resolveArchiveSource(this.ctx.projectId);
@@ -60,16 +61,25 @@ class AndroidSubmitCommand {
releaseStatus: releaseStatus.enforceValue(),
archiveSource: archiveSource.enforceValue(),
serviceAccountSource: serviceAccountSource.enforceValue(),
changesNotSentForReview: this.ctx.commandFlags.changesNotSentForReview,
};
}
private resolveAndroidPackageSource(): Result<AndroidPackageSource> {
let androidPackage: string | undefined;
private async maybeGetAndroidPackageFromCurrentProjectAsync(): Promise<string | undefined> {
const { exp } = getConfig(this.ctx.projectDir, { skipSDKVersionRequirement: true });
try {
return await getApplicationIdAsync(this.ctx.projectDir, exp);
} catch {
return undefined;
}
}
private async resolveAndroidPackageSourceAsync(): Promise<Result<AndroidPackageSource>> {
let androidPackage: string | undefined;
if (this.ctx.commandFlags.androidPackage) {
androidPackage = this.ctx.commandFlags.androidPackage;
} else if (exp.android?.package) {
androidPackage = exp.android.package;
} else {
androidPackage = await this.maybeGetAndroidPackageFromCurrentProjectAsync();
}
if (androidPackage) {
return result({
@@ -147,11 +157,11 @@ class AndroidSubmitCommand {
}
private resolveServiceAccountSource(): Result<ServiceAccountSource> {
const { key } = this.ctx.commandFlags;
if (key) {
const { serviceAccountKeyPath } = this.ctx.commandFlags;
if (serviceAccountKeyPath) {
return result({
sourceType: ServiceAccountSourceType.path,
path: key,
path: serviceAccountKeyPath,
});
} else {
return result({
@@ -14,7 +14,10 @@ import { AndroidSubmissionConfig, ReleaseStatus, ReleaseTrack } from './AndroidS
import { ServiceAccountSource, getServiceAccountAsync } from './ServiceAccountSource';
export interface AndroidSubmissionOptions
extends Pick<AndroidSubmissionConfig, 'track' | 'releaseStatus' | 'projectId'> {
extends Pick<
AndroidSubmissionConfig,
'track' | 'releaseStatus' | 'projectId' | 'changesNotSentForReview'
> {
androidPackageSource: AndroidPackageSource;
archiveSource: ArchiveSource;
serviceAccountSource: ServiceAccountSource;
@@ -66,14 +69,14 @@ class AndroidSubmitter extends BaseSubmitter<AndroidSubmissionContext, AndroidSu
{ archive, androidPackage, serviceAccountPath }: ResolvedSourceOptions
): Promise<AndroidSubmissionConfig> {
const serviceAccount = await fs.readFile(serviceAccountPath, 'utf-8');
const { track, releaseStatus, projectId } = options;
const { track, releaseStatus, projectId, changesNotSentForReview } = options;
// structuring order affects table rows order
return {
androidPackage,
archiveUrl: archive.location,
archiveType: archive.type as AndroidArchiveType,
track,
changesNotSentForReview,
releaseStatus,
projectId,
serviceAccount,
@@ -84,12 +87,14 @@ class AndroidSubmitter extends BaseSubmitter<AndroidSubmissionContext, AndroidSu
options: AndroidSubmissionOptions,
{ archive, androidPackage, serviceAccountPath }: ResolvedSourceOptions
): Summary {
const { projectId, track, releaseStatus } = options;
const { projectId, track, releaseStatus, changesNotSentForReview } = options;
// structuring order affects table rows order
return {
projectId,
androidPackage,
track,
changesNotSentForReview,
releaseStatus,
archiveType: archive.type as AndroidArchiveType,
serviceAccountPath,
@@ -105,6 +110,7 @@ type Summary = {
track: ReleaseTrack;
releaseStatus?: ReleaseStatus;
projectId?: string;
changesNotSentForReview?: boolean;
} & ArchiveSourceSummaryFields;
const SummaryHumanReadableKeys: Record<keyof Summary, string> = {
@@ -113,6 +119,7 @@ const SummaryHumanReadableKeys: Record<keyof Summary, string> = {
archiveUrl: 'Download URL',
archiveType: 'Archive type',
serviceAccountPath: 'Google Service Key',
changesNotSentForReview: 'Changes not sent for a review',
track: 'Release track',
releaseStatus: 'Release status',
projectId: 'Project ID',
@@ -44,7 +44,7 @@ describe(AndroidSubmitCommand, () => {
const fakeBuildFragment: Partial<BuildFragment> = {
id: uuidv4(),
artifacts: { buildUrl: 'http://expo.io/fake.apk' },
artifacts: { buildUrl: 'http://expo.dev/fake.apk' },
appVersion: '1.2.3',
platform: AppPlatform.Android,
};
@@ -101,24 +101,26 @@ describe(AndroidSubmitCommand, () => {
const options: AndroidSubmitCommandFlags = {
latest: false,
url: 'http://expo.io/fake.apk',
url: 'http://expo.dev/fake.apk',
type: 'apk',
key: '/google-service-account.json',
serviceAccountKeyPath: '/google-service-account.json',
track: 'internal',
releaseStatus: 'draft',
verbose: false,
changesNotSentForReview: false,
};
const ctx = AndroidSubmitCommand.createContext(testProject.projectRoot, projectId, options);
const command = new AndroidSubmitCommand(ctx);
await command.runAsync();
const androidSubmissionConfig: AndroidSubmissionConfig = {
archiveUrl: 'http://expo.io/fake.apk',
archiveUrl: 'http://expo.dev/fake.apk',
archiveType: AndroidArchiveType.apk,
androidPackage: testProject.appJSON.expo.android?.package,
serviceAccount: fakeFiles['/google-service-account.json'],
releaseStatus: ReleaseStatus.draft,
track: ReleaseTrack.internal,
changesNotSentForReview: false,
projectId,
};
@@ -147,23 +149,25 @@ describe(AndroidSubmitCommand, () => {
const options: AndroidSubmitCommandFlags = {
latest: true,
type: 'apk',
key: '/google-service-account.json',
serviceAccountKeyPath: '/google-service-account.json',
track: 'internal',
releaseStatus: 'draft',
verbose: false,
changesNotSentForReview: false,
};
const ctx = AndroidSubmitCommand.createContext(testProject.projectRoot, projectId, options);
const command = new AndroidSubmitCommand(ctx);
await command.runAsync();
const androidSubmissionConfig: AndroidSubmissionConfig = {
archiveUrl: 'http://expo.io/fake.apk',
archiveUrl: 'http://expo.dev/fake.apk',
archiveType: AndroidArchiveType.apk,
androidPackage: testProject.appJSON.expo.android?.package,
serviceAccount: fakeFiles['/google-service-account.json'],
releaseStatus: ReleaseStatus.draft,
track: ReleaseTrack.internal,
projectId,
changesNotSentForReview: false,
};
expect(SubmissionService.startSubmissionAsync).toHaveBeenCalledWith(
@@ -18,7 +18,6 @@ interface CreateAppOptions {
appName: string;
bundleIdentifier: string;
appleTeamId?: string;
itcTeamId?: string;
language?: string;
companyName?: string;
sku?: string;
@@ -70,6 +69,7 @@ async function createAppStoreConnectAppAsync(options: CreateAppOptions): Promise
appName,
language,
companyName,
sku,
} = options;
const authCtx = await authenticateAsync({
@@ -99,6 +99,7 @@ async function createAppStoreConnectAppAsync(options: CreateAppOptions): Promise
language,
companyName,
bundleIdentifier: bundleId,
sku,
});
} catch (error) {
if (
@@ -84,7 +84,7 @@ describe(IosSubmitCommand, () => {
const options: IosSubmitCommandFlags = {
latest: false,
url: 'http://expo.io/fake.ipa',
url: 'http://expo.dev/fake.ipa',
appleId: '[email protected]',
ascAppId: '12345678',
verbose: false,
@@ -94,7 +94,7 @@ describe(IosSubmitCommand, () => {
await command.runAsync();
const iosSubmissionConfig: IosSubmissionConfig = {
archiveUrl: 'http://expo.io/fake.ipa',
archiveUrl: 'http://expo.dev/fake.ipa',
appleId: '[email protected]',
appSpecificPassword: 'supersecret',
appAppleId: '12345678',
+9 -6
View File
@@ -1,11 +1,14 @@
export interface SubmissionContext<T extends SubmitCommandFlags> {
projectDir: string;
projectId: string;
export interface SubmissionContext<T extends SubmitCommandFlags> extends BaseSubmissionContext {
commandFlags: T;
}
export interface BaseSubmissionContext {
projectDir: string;
projectId: string;
}
export interface SubmitCommandFlags {
latest: boolean;
latest?: boolean;
id?: string;
path?: string;
url?: string;
@@ -26,10 +29,11 @@ export type ArchiveType = AndroidArchiveType | IosArchiveType;
// Android specific types
export interface AndroidSubmitCommandFlags extends SubmitCommandFlags {
type?: 'apk' | 'aab';
key?: string;
serviceAccountKeyPath?: string;
androidPackage?: string;
track: string;
releaseStatus: string;
changesNotSentForReview: boolean;
}
export type AndroidSubmissionContext = SubmissionContext<AndroidSubmitCommandFlags>;
@@ -42,7 +46,6 @@ export interface IosSubmitCommandFlags extends SubmitCommandFlags {
// used only when running produce
appleTeamId?: string;
itcTeamId?: string;
appName?: string;
bundleIdentifier?: string;
sku?: string;
@@ -51,11 +51,11 @@ const SubmissionErrorMessages: Record<SubmissionErrorCode, string> = {
[SubmissionErrorCode.IOS_MISSING_APP_ICON]:
'Your iOS app icon is missing or is an invalid format. The icon must be a 1024x1024 PNG image with no transparency.\n' +
'Please check your icon image and icon configuration in app.json.\n' +
`${learnMore('https://docs.expo.io/guides/app-icons/')}`,
`${learnMore('https://docs.expo.dev/guides/app-icons/')}`,
[SubmissionErrorCode.IOS_INVALID_SIGNATURE]:
'Your app signature seems to be invalid.\n' +
"Please check your iOS Distribution Certificate and your app's Provisioning Profile.\n" +
`${learnMore('https://docs.expo.io/distribution/app-signing')}`,
`${learnMore('https://docs.expo.dev/distribution/app-signing')}`,
[SubmissionErrorCode.IOS_INCORRECT_CREDENTIALS]:
'Your Apple ID or app-specific password is incorrect. Please verify that you entered them correctly and try again.',
[SubmissionErrorCode.IOS_IPAD_INVALID_ORIENTATION]:
+43
View File
@@ -0,0 +1,43 @@
import assert from 'assert';
import Log from '../log';
let stdoutWrite: NodeJS.WriteStream['write'] | undefined;
export function enableJsonOutput() {
if (stdoutWrite) {
return;
}
stdoutWrite = process.stdout.write;
process.stdout.write = (...args: any) => {
return process.stderr.write.call(null, args);
};
}
export function printJsonOnlyOutput(value: object): void {
assert(stdoutWrite, 'this should only be called with --json flag');
try {
process.stdout.write = stdoutWrite;
Log.log(JSON.stringify(sanitizeValue(value), null, 2));
} finally {
process.stdout.write = (...args: any) => {
return process.stderr.write.call(null, args);
};
}
}
function sanitizeValue(value: any): unknown {
if (Array.isArray(value)) {
return value.map(val => sanitizeValue(val));
} else if (value && typeof value === 'object') {
const result: Record<string, any> = {};
Object.keys(value).forEach(key => {
if (key !== '__typename' && value[key] !== null) {
result[key] = sanitizeValue(value[key]);
}
});
return result;
} else {
return value;
}
}
+6 -2
View File
@@ -17,7 +17,7 @@ function createProgressTracker({
}: {
total?: number;
message: string | ((ratio: number) => string);
completedMessage: string;
completedMessage: string | ((duration: string) => string);
}): ProgressHandler {
let bar: ora.Ora | null = null;
let calcTotal: number = total ?? 0;
@@ -66,7 +66,11 @@ function createProgressTracker({
if (error) {
bar.fail();
} else if (isComplete) {
bar.succeed(`${completedMessage} ${chalk.dim(prettyTime)}`);
if (typeof completedMessage === 'string') {
bar.succeed(`${completedMessage} ${chalk.dim(prettyTime)}`);
} else {
bar.succeed(completedMessage(prettyTime));
}
}
}
};
+2 -2
View File
@@ -1,8 +1,8 @@
{
"name": "@expo/eas-json",
"description": "A library for interacting with the eas.json",
"version": "0.22.3",
"author": "Expo <support@expo.io>",
"version": "0.24.0",
"author": "Expo <support@expo.dev>",
"bugs": "https://github.com/expo/eas-cli/issues",
"dependencies": {
"@expo/eas-build-job": "0.2.45",
+59
View File
@@ -0,0 +1,59 @@
import { Android, Cache, Ios, Platform } from '@expo/eas-build-job';
export enum CredentialsSource {
LOCAL = 'local',
REMOTE = 'remote',
}
export type DistributionType = 'store' | 'internal';
export type IosEnterpriseProvisioning = 'adhoc' | 'universal';
export type VersionAutoIncrement = boolean | 'version' | 'buildNumber';
export interface CommonBuildProfile {
credentialsSource: CredentialsSource;
distribution: DistributionType;
cache?: Omit<Cache, 'clear'>;
releaseChannel?: string;
channel?: string;
developmentClient?: boolean;
node?: string;
yarn?: string;
expoCli?: string;
env?: Record<string, string>;
}
export interface AndroidBuildProfile extends CommonBuildProfile {
withoutCredentials?: boolean;
image?: Android.BuilderEnvironment['image'];
ndk?: string;
buildType?: Android.BuildType.APK | Android.BuildType.APP_BUNDLE;
gradleCommand?: string;
artifactPath?: string;
}
export interface IosBuildProfile extends CommonBuildProfile {
enterpriseProvisioning?: IosEnterpriseProvisioning;
autoIncrement?: VersionAutoIncrement;
simulator?: boolean;
image?: Ios.BuilderEnvironment['image'];
bundler?: string;
fastlane?: string;
cocoapods?: string;
artifactPath?: string;
scheme?: string;
buildConfiguration?: string;
}
export type BuildProfile<TPlatform extends Platform = Platform> = TPlatform extends Platform.ANDROID
? AndroidBuildProfile
: TPlatform extends Platform.IOS
? IosBuildProfile
: TPlatform extends Platform
? AndroidBuildProfile | IosBuildProfile
: never;
+9 -57
View File
@@ -1,71 +1,23 @@
import { Android, Cache, Ios, Platform } from '@expo/eas-build-job';
import { AndroidBuildProfile, CommonBuildProfile, IosBuildProfile } from './EasBuild.types';
import { AndroidSubmitProfile, IosSubmitProfile } from './EasSubmit.types';
export enum CredentialsSource {
LOCAL = 'local',
REMOTE = 'remote',
}
export type DistributionType = 'store' | 'internal';
export type IosEnterpriseProvisioning = 'adhoc' | 'universal';
export type VersionAutoIncrement = boolean | 'version' | 'buildNumber';
export interface CommonBuildProfile {
credentialsSource: CredentialsSource;
distribution: DistributionType;
cache?: Omit<Cache, 'clear'>;
releaseChannel?: string;
channel?: string;
developmentClient?: boolean;
node?: string;
yarn?: string;
expoCli?: string;
env?: Record<string, string>;
}
export interface AndroidBuildProfile extends CommonBuildProfile {
withoutCredentials?: boolean;
image?: Android.BuilderEnvironment['image'];
ndk?: string;
buildType?: Android.BuildType.APK | Android.BuildType.APP_BUNDLE;
gradleCommand?: string;
artifactPath?: string;
}
export interface IosBuildProfile extends CommonBuildProfile {
enterpriseProvisioning?: IosEnterpriseProvisioning;
autoIncrement?: VersionAutoIncrement;
simulator?: boolean;
image?: Ios.BuilderEnvironment['image'];
bundler?: string;
fastlane?: string;
cocoapods?: string;
artifactPath?: string;
scheme?: string;
buildConfiguration?: string;
}
export type BuildProfile<TPlatform extends Platform = Platform> = TPlatform extends Platform.ANDROID
? AndroidBuildProfile
: TPlatform extends Platform.IOS
? IosBuildProfile
: TPlatform extends Platform
? AndroidBuildProfile | IosBuildProfile
: never;
export interface RawBuildProfile extends Partial<CommonBuildProfile> {
extends?: string;
android?: Partial<AndroidBuildProfile>;
ios?: Partial<IosBuildProfile>;
}
export interface EasSubmitConfiguration {
android?: AndroidSubmitProfile;
ios?: IosSubmitProfile;
}
export interface EasJson {
build: {
[profile: string]: RawBuildProfile;
};
build: { [profile: string]: RawBuildProfile };
submit?: { [profile: string]: EasSubmitConfiguration };
}
+17 -3
View File
@@ -2,8 +2,10 @@ import { Platform } from '@expo/eas-build-job';
import fs from 'fs-extra';
import path from 'path';
import { BuildProfile, CredentialsSource, EasJson, RawBuildProfile } from './EasJson.types';
import { BuildProfile } from './EasBuild.types';
import { CredentialsSource, EasJson, RawBuildProfile } from './EasJson.types';
import { EasJsonSchema, MinimalEasJsonSchema } from './EasJsonSchema';
import { SubmitProfile } from './EasSubmit.types';
interface EasJsonPreValidation {
build: { [profile: string]: object };
@@ -26,12 +28,24 @@ export class EasJsonReader {
return Object.keys(easJson?.build ?? {});
}
public async readSubmitProfileAsync<T extends Platform>(
profileName: string,
platform: T
): Promise<SubmitProfile<T>> {
const easJson = await this.readAndValidateAsync();
const profile = easJson?.submit?.[profileName]?.[platform];
if (!profile) {
throw new Error(`There is no profile named ${profileName} in eas.json for ${platform}.`);
}
return profile as SubmitProfile<T>;
}
public async readBuildProfileAsync<T extends Platform>(
buildProfileName: string,
platform: T
): Promise<BuildProfile<T>> {
const easJson = await this.readAndValidateAsync();
this.ensureProfileExists(easJson, buildProfileName);
this.ensureBuildProfileExists(easJson, buildProfileName);
const {
android: resolvedAndroidSpecificValues,
ios: resolvedIosSpecificValues,
@@ -104,7 +118,7 @@ export class EasJsonReader {
}
}
private ensureProfileExists(easJson: EasJson, profileName: string) {
private ensureBuildProfileExists(easJson: EasJson, profileName: string) {
if (!easJson.build || !easJson.build[profileName]) {
throw new Error(`There is no profile named ${profileName} in eas.json.`);
}
+28
View File
@@ -1,6 +1,8 @@
import { Android, Ios } from '@expo/eas-build-job';
import Joi from '@hapi/joi';
import { ReleaseStatus, ReleaseTrack } from './EasSubmit.types';
const semverSchemaCheck = (value: any) => {
if (/^[0-9]+\.[0-9]+\.[0-9]+$/.test(value)) {
return value;
@@ -72,10 +74,36 @@ const EasJsonBuildProfileSchema = CommonBuildProfileSchema.concat(
})
);
const AndroidSubmitProfileSchema = Joi.object({
serviceAccountKeyPath: Joi.string(),
track: Joi.string().valid(...Object.values(ReleaseTrack)),
releaseStatus: Joi.string().valid(...Object.values(ReleaseStatus)),
changesNotSentForReview: Joi.boolean(),
verbose: Joi.boolean(),
});
const IosSubmitProfileSchema = Joi.object({
appleId: Joi.string(),
ascAppId: Joi.string(),
appleTeamId: Joi.string(),
sku: Joi.string(),
language: Joi.string(),
companyName: Joi.string(),
verbose: Joi.boolean(),
});
const EasJsonSubmitConfigurationSchema = Joi.object({
android: AndroidSubmitProfileSchema,
ios: IosSubmitProfileSchema,
});
export const MinimalEasJsonSchema = Joi.object({
build: Joi.object().pattern(Joi.string(), Joi.object()),
submit: Joi.object().pattern(Joi.string(), Joi.object()),
});
export const EasJsonSchema = Joi.object({
build: Joi.object().pattern(Joi.string(), EasJsonBuildProfileSchema),
submit: Joi.object().pattern(Joi.string(), EasJsonSubmitConfigurationSchema),
});
+43
View File
@@ -0,0 +1,43 @@
import { Platform } from '@expo/eas-build-job';
export enum ReleaseStatus {
completed = 'completed',
draft = 'draft',
halted = 'halted',
inProgress = 'inProgress',
}
export enum ReleaseTrack {
production = 'production',
beta = 'beta',
alpha = 'alpha',
internal = 'internal',
}
export interface AndroidSubmitProfile {
serviceAccountKeyPath?: string;
track?: ReleaseTrack;
releaseStatus?: ReleaseStatus;
changesNotSentForReview?: boolean;
verbose?: boolean;
}
export interface IosSubmitProfile {
appleId?: string;
ascAppId?: string;
appleTeamId?: string;
sku?: string;
language?: string;
companyName?: string;
verbose?: boolean;
}
export type SubmitProfile<TPlatform extends Platform = Platform> =
TPlatform extends Platform.ANDROID
? AndroidSubmitProfile
: TPlatform extends Platform.IOS
? IosSubmitProfile
: TPlatform extends Platform
? AndroidSubmitProfile | IosSubmitProfile
: never;
@@ -0,0 +1,95 @@
import { Platform } from '@expo/eas-build-job';
import fs from 'fs-extra';
import { vol } from 'memfs';
import { EasJsonReader } from '../EasJsonReader';
jest.mock('fs');
beforeEach(async () => {
vol.reset();
await fs.mkdirp('/project');
});
test('minimal allowed eas.json for both platforms', async () => {
await fs.writeJson('/project/eas.json', {
submit: {
release: {
android: {},
ios: {},
},
},
});
const reader = new EasJsonReader('/project');
const iosProfile = await reader.readSubmitProfileAsync('release', Platform.IOS);
const androidProfile = await reader.readSubmitProfileAsync('release', Platform.ANDROID);
expect(androidProfile).toEqual({});
expect(iosProfile).toEqual({});
});
test('android config with all required values', async () => {
await fs.writeJson('/project/eas.json', {
submit: {
release: {
android: {
serviceAccountKeyPath: './path.json',
track: 'beta',
releaseStatus: 'completed',
},
},
},
});
const reader = new EasJsonReader('/project');
const androidProfile = await reader.readSubmitProfileAsync('release', Platform.ANDROID);
expect(androidProfile).toEqual({
serviceAccountKeyPath: './path.json',
track: 'beta',
releaseStatus: 'completed',
});
});
test('ios config with all required values', async () => {
await fs.writeJson('/project/eas.json', {
submit: {
release: {
ios: {
appleId: '[email protected]',
ascAppId: '1223423523',
appleTeamId: 'QWERTY',
},
},
},
});
const reader = new EasJsonReader('/project');
const iosProfile = await reader.readSubmitProfileAsync('release', Platform.IOS);
expect(iosProfile).toEqual({
appleId: '[email protected]',
appleTeamId: 'QWERTY',
ascAppId: '1223423523',
});
});
test('missing ios profile', async () => {
await fs.writeJson('/project/eas.json', {
submit: {
release: {
android: {
serviceAccountKeyPath: './path.json',
track: 'beta',
releaseStatus: 'completed',
},
},
},
});
const reader = new EasJsonReader('/project');
const promise = reader.readSubmitProfileAsync('release', Platform.IOS);
expect(promise).rejects.toThrow('There is no profile named release in eas.json for ios.');
});
+3 -2
View File
@@ -1,12 +1,13 @@
export { AndroidSubmitProfile, IosSubmitProfile } from './EasSubmit.types';
export { EasJson } from './EasJson.types';
export {
AndroidBuildProfile,
BuildProfile,
CredentialsSource,
DistributionType,
EasJson,
IosBuildProfile,
IosEnterpriseProvisioning,
VersionAutoIncrement,
} from './EasJson.types';
} from './EasBuild.types';
export { EasJsonReader } from './EasJsonReader';
export { hasMismatchedExtendsAsync, isUsingDeprecatedFormatAsync, migrateAsync } from './migrate';
+1 -1
View File
@@ -1,3 +1,3 @@
declare module 'qrcode-terminal' {
function generate(text: string, cb: (code: string) => void): void;
function generate(text: string, opts: { small: boolean }, cb: (code: string) => void): void;
}
Generated
+444 -14
View File
@@ -1757,6 +1757,15 @@
exec-sh "^0.3.2"
minimist "^1.2.0"
"@dabh/diagnostics@^2.0.2":
version "2.0.2"
resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.2.tgz#290d08f7b381b8f94607dc8f471a12c675f9db31"
integrity sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==
dependencies:
colorspace "1.1.x"
enabled "2.0.x"
kuler "^2.0.0"
"@endemolshinegroup/[email protected]":
version "3.0.2"
resolved "https://registry.yarnpkg.com/@endemolshinegroup/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-3.0.2.tgz#eea4635828dde372838b0909693ebd9aafeec22d"
@@ -1856,10 +1865,10 @@
unique-filename "^1.1.1"
which "^1.3.1"
"@expo/[email protected]4":
version "0.0.0-alpha.24"
resolved "https://registry.yarnpkg.com/@expo/apple-utils/-/apple-utils-0.0.0-alpha.24.tgz#4208204d3763a4770ce9e63f36c14476adc635bd"
integrity sha512-96MGsGcRIjzJ3Stqw9fiXAgOfMn4UlmlBp2EZkmpad7945ke9Gguceafb6rpbKJHEkQd2qcBcfcumU73QisP2w==
"@expo/[email protected]5":
version "0.0.0-alpha.25"
resolved "https://registry.yarnpkg.com/@expo/apple-utils/-/apple-utils-0.0.0-alpha.25.tgz#fea4f5a409cc1bf79a0d2acec3eca52dbd8443c1"
integrity sha512-meyCJ/5jHJsgZNBMwlAugqD5Z0bcazCLgAyYQCw8O1/sXh4gWf0IiWJGnkevdxnA3g1R9nmJFmjkFuLoGOt+Bw==
"@expo/babel-preset-cli@^0.2.17":
version "0.2.18"
@@ -2066,6 +2075,24 @@
resolved "https://registry.yarnpkg.com/@expo/results/-/results-1.0.0.tgz#fd4b22f936ceafce23b04799f54b87fe2a9e18d1"
integrity sha512-qECzzXX5oJot3m2Gu9pfRDz50USdBieQVwYAzeAtQRUTD3PVeTK1tlRUoDcrK8PSruDLuVYdKkLebX4w/o55VA==
"@expo/[email protected]":
version "1.0.7"
resolved "https://registry.yarnpkg.com/@expo/rudder-sdk-node/-/rudder-sdk-node-1.0.7.tgz#162c4bb843bbb0fdfdfe62620a001a225a1ff95e"
integrity sha512-TQuHUwugxzJGCYOFN/ZIQ+rNSdLPv2pgxaH2Ky7y80RDvWN8DNKeTbrgX0tPnVd/aLjKhxADx8C2se//lZR24w==
dependencies:
"@segment/loosely-validate-event" "^2.0.0"
auto-changelog "^1.16.2"
axios "^0.21.1"
axios-retry "^3.0.2"
bull "^3.20.0"
lodash.isstring "^4.0.1"
md5 "^2.2.1"
ms "^2.0.0"
remove-trailing-slash "^0.1.0"
serialize-javascript "^5.0.1"
uuid "^3.2.1"
winston "^3.3.3"
"@expo/[email protected]":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@expo/sdk-runtime-versions/-/sdk-runtime-versions-1.0.0.tgz#d7ebd21b19f1c6b0395e50d78da4416941c57f7c"
@@ -3907,6 +3934,14 @@
dependencies:
any-observable "^0.3.0"
"@segment/loosely-validate-event@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@segment/loosely-validate-event/-/loosely-validate-event-2.0.0.tgz#87dfc979e5b4e7b82c5f1d8b722dfd5d77644681"
integrity sha512-ZMCSfztDBqwotkl848ODgVcAmN4OItEWDCkshcKz0/W6gGSQayuuCtWV/MlodFivAZD793d6UgANd6wCXUfrIw==
dependencies:
component-type "^1.2.1"
join-component "^1.1.0"
"@sindresorhus/is@^0.14.0":
version "0.14.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea"
@@ -4717,6 +4752,11 @@ async-limiter@~1.0.0:
resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
async@^3.1.0:
version "3.2.1"
resolved "https://registry.yarnpkg.com/async/-/async-3.2.1.tgz#d3274ec66d107a47476a4c49136aacdb00665fc8"
integrity sha512-XdD5lRO/87udXCMC9meWdYiR+Nq6ZjUfXidViUZGu2F1MO4T3XwZ1et0hb2++BgLfhyJwy44BGB/yx80ABx8hg==
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
@@ -4742,6 +4782,20 @@ auto-bind@~4.0.0:
resolved "https://registry.yarnpkg.com/auto-bind/-/auto-bind-4.0.0.tgz#e3589fc6c2da8f7ca43ba9f84fa52a744fc997fb"
integrity sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ==
auto-changelog@^1.16.2:
version "1.16.4"
resolved "https://registry.yarnpkg.com/auto-changelog/-/auto-changelog-1.16.4.tgz#5abcce4e92a4f81824000ab2550bc5d2315fc8fb"
integrity sha512-h7diyELoq692AA4oqO50ULoYKIomUdzuQ+NW+eFPwIX0xzVbXEu9cIcgzZ3TYNVbpkGtcNKh51aRfAQNef7HVA==
dependencies:
commander "^5.0.0"
core-js "^3.6.4"
handlebars "^4.7.3"
lodash.uniqby "^4.7.0"
node-fetch "^2.6.0"
parse-github-url "^1.0.2"
regenerator-runtime "^0.13.5"
semver "^6.3.0"
aws-sign2@~0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
@@ -4752,7 +4806,14 @@ aws4@^1.8.0:
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.0.tgz#a17b3a8ea811060e74d47d306122400ad4497ae2"
integrity sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==
axios@0.21.1:
axios-retry@^3.0.2:
version "3.1.9"
resolved "https://registry.yarnpkg.com/axios-retry/-/axios-retry-3.1.9.tgz#6c30fc9aeb4519aebaec758b90ef56fa03fe72e8"
integrity sha512-NFCoNIHq8lYkJa6ku4m+V1837TP6lCa7n79Iuf8/AqATAHYB0ISaAS1eyIenDOfHOLtym34W65Sjke2xjg2fsA==
dependencies:
is-retry-allowed "^1.1.0"
[email protected], axios@^0.21.1:
version "0.21.1"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
@@ -5051,6 +5112,22 @@ builtins@^1.0.3:
resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88"
integrity sha1-y5T662HIaWRR2zZTThQi+U8K7og=
bull@^3.20.0:
version "3.28.1"
resolved "https://registry.yarnpkg.com/bull/-/bull-3.28.1.tgz#33bc7bbe640e71258a2a800935a692a24a2d7236"
integrity sha512-TasVWD1410Q8druRG6SIAN5hwAT3F4QICcGszReD859qAerq+VwbW3vPg6lV60reJkWyWBK11FHa2FsQ8iDBmQ==
dependencies:
cron-parser "^2.13.0"
debuglog "^1.0.0"
get-port "^5.1.1"
ioredis "^4.27.0"
lodash "^4.17.21"
p-timeout "^3.2.0"
promise.prototype.finally "^3.1.2"
semver "^7.3.2"
util.promisify "^1.0.1"
uuid "^8.3.0"
byline@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1"
@@ -5303,6 +5380,11 @@ chardet@^0.7.0:
resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
[email protected]:
version "0.0.2"
resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=
chokidar@^3.4.3:
version "3.4.3"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.3.tgz#c1df38231448e45ca4ac588e6c79573ba6a57d5b"
@@ -5490,6 +5572,11 @@ clone@^1.0.2:
resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
cluster-key-slot@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d"
integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==
co@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
@@ -5513,7 +5600,7 @@ collection-visit@^1.0.0:
map-visit "^1.0.0"
object-visit "^1.0.0"
color-convert@^1.9.0:
color-convert@^1.9.0, color-convert@^1.9.1:
version "1.9.3"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
@@ -5537,6 +5624,14 @@ color-name@^1.0.0, color-name@~1.1.4:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
color-string@^1.5.2:
version "1.6.0"
resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.6.0.tgz#c3915f61fe267672cb7e1e064c9d692219f6c312"
integrity sha512-c/hGS+kRWJutUBEngKKmk4iH3sD59MBkoxVapS/0wgpCz2u7XsNloxknyvBhzwEs1IbV36D9PwqLPJ2DTu3vMA==
dependencies:
color-name "^1.0.0"
simple-swizzle "^0.2.2"
color-string@^1.5.3:
version "1.5.4"
resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.4.tgz#dd51cd25cfee953d138fe4002372cc3d0e504cb6"
@@ -5545,16 +5640,32 @@ color-string@^1.5.3:
color-name "^1.0.0"
simple-swizzle "^0.2.2"
[email protected]:
version "3.0.0"
resolved "https://registry.yarnpkg.com/color/-/color-3.0.0.tgz#d920b4328d534a3ac8295d68f7bd4ba6c427be9a"
integrity sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==
dependencies:
color-convert "^1.9.1"
color-string "^1.5.2"
colorette@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94"
integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==
colors@^1.1.2:
colors@^1.1.2, colors@^1.2.1:
version "1.4.0"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==
[email protected]:
version "1.1.2"
resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.2.tgz#e0128950d082b86a2168580796a0aa5d6c68d8c5"
integrity sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==
dependencies:
color "3.0.x"
text-hex "1.0.x"
columnify@^1.5.4:
version "1.5.4"
resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb"
@@ -5570,7 +5681,7 @@ combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
dependencies:
delayed-stream "~1.0.0"
commander@^5.1.0:
commander@^5.0.0, commander@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae"
integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==
@@ -5593,6 +5704,11 @@ component-emitter@^1.2.1:
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
component-type@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/component-type/-/component-type-1.2.1.tgz#8a47901700238e4fc32269771230226f24b415a9"
integrity sha1-ikeQFwAjjk/DIml3EjAibyS0Fak=
[email protected]:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
@@ -5773,6 +5889,11 @@ core-js@^2.4.1:
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c"
integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==
core-js@^3.6.4:
version "3.16.1"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.16.1.tgz#f4485ce5c9f3c6a7cb18fa80488e08d362097249"
integrity sha512-AAkP8i35EbefU+JddyWi12AWE9f2N/qr/pwnDtWz4nyUIBGMJPX99ANFFRSw6FefM374lDujdtLDyhN2A/btHw==
[email protected], core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
@@ -5817,6 +5938,14 @@ cosmiconfig@^7.0.0:
path-type "^4.0.0"
yaml "^1.10.0"
cron-parser@^2.13.0:
version "2.18.0"
resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-2.18.0.tgz#de1bb0ad528c815548371993f81a54e5a089edcf"
integrity sha512-s4odpheTyydAbTBQepsqd2rNWGa2iV3cyo8g7zbI2QQYGLVsfbhmwukayS1XHppe02Oy1fg7mg6xoaraVJeEcg==
dependencies:
is-nan "^1.3.0"
moment-timezone "^0.5.31"
[email protected], cross-fetch@^3.0.6:
version "3.0.6"
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.0.6.tgz#3a4040bc8941e653e0e9cf17f29ebcd177d3365c"
@@ -5844,6 +5973,11 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2:
shebang-command "^2.0.0"
which "^2.0.1"
[email protected]:
version "0.0.2"
resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=
crypto-random-string@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
@@ -5981,7 +6115,7 @@ debug@^4.3.1:
dependencies:
ms "2.1.2"
debuglog@^1.0.1:
debuglog@^1.0.0, debuglog@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=
@@ -6113,6 +6247,11 @@ delegates@^1.0.0:
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
denque@^1.1.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.0.tgz#773de0686ff2d8ec2ff92914316a47b73b1c73de"
integrity sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ==
dependency-graph@^0.9.0:
version "0.9.0"
resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.9.0.tgz#11aed7e203bc8b00f48356d92db27b265c445318"
@@ -6303,6 +6442,11 @@ emoji-regex@^8.0.0:
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
[email protected]:
version "2.0.0"
resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2"
integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==
encoding@^0.1.11:
version "0.1.13"
resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9"
@@ -6346,6 +6490,29 @@ error-ex@^1.2.0, error-ex@^1.3.1:
dependencies:
is-arrayish "^0.2.1"
es-abstract@^1.17.0-next.0:
version "1.18.5"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.5.tgz#9b10de7d4c206a3581fd5b2124233e04db49ae19"
integrity sha512-DDggyJLoS91CkJjgauM5c0yZMjiD1uK3KcaCeAmffGwZ+ODWzOkPN4QwRbsK5DOFf06fywmyLci3ZD8jLGhVYA==
dependencies:
call-bind "^1.0.2"
es-to-primitive "^1.2.1"
function-bind "^1.1.1"
get-intrinsic "^1.1.1"
has "^1.0.3"
has-symbols "^1.0.2"
internal-slot "^1.0.3"
is-callable "^1.2.3"
is-negative-zero "^2.0.1"
is-regex "^1.1.3"
is-string "^1.0.6"
object-inspect "^1.11.0"
object-keys "^1.1.1"
object.assign "^4.1.2"
string.prototype.trimend "^1.0.4"
string.prototype.trimstart "^1.0.4"
unbox-primitive "^1.0.1"
es-abstract@^1.17.0-next.1, es-abstract@^1.17.5:
version "1.17.7"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.7.tgz#a4de61b2f66989fc7421676c1cb9787573ace54c"
@@ -6900,6 +7067,11 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6:
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
fast-safe-stringify@^2.0.4:
version "2.0.8"
resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.8.tgz#dc2af48c46cf712b683e849b2bbd446b32de936f"
integrity sha512-lXatBjf3WPjmWD6DpIZxkeSsCOwqI0maYMpgDlx8g4U2qi4lbjA9oH/HD2a87G+KfsUmo5WbJFmqBZlPxtptag==
fastq@^1.6.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.8.0.tgz#550e1f9f59bbc65fe185cb6a9b4d95357107f481"
@@ -6933,6 +7105,11 @@ fbjs@^1.0.0:
setimmediate "^1.0.5"
ua-parser-js "^0.7.18"
fecha@^4.2.0:
version "4.2.1"
resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.1.tgz#0a83ad8f86ef62a091e22bb5a039cd03d23eecce"
integrity sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==
figgy-pudding@^3.4.1, figgy-pudding@^3.5.1:
version "3.5.2"
resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e"
@@ -7055,11 +7232,23 @@ flush-write-stream@^1.0.0:
inherits "^2.0.3"
readable-stream "^2.3.6"
[email protected]:
version "1.1.0"
resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc"
integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==
follow-redirects@^1.10.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.1.tgz#d9114ded0a1cfdd334e164e6662ad02bfd91ff43"
integrity sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==
for-each@^0.3.3:
version "0.3.3"
resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e"
integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==
dependencies:
is-callable "^1.1.3"
for-in@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
@@ -7263,6 +7452,11 @@ get-port@^4.2.0:
resolved "https://registry.yarnpkg.com/get-port/-/get-port-4.2.0.tgz#e37368b1e863b7629c43c5a323625f95cf24b119"
integrity sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw==
get-port@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193"
integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==
get-stdin@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
@@ -7557,6 +7751,18 @@ growly@^1.3.0:
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=
handlebars@^4.7.3:
version "4.7.7"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1"
integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==
dependencies:
minimist "^1.2.5"
neo-async "^2.6.0"
source-map "^0.6.1"
wordwrap "^1.0.0"
optionalDependencies:
uglify-js "^3.1.4"
handlebars@^4.7.6:
version "4.7.6"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.6.tgz#d4c05c1baf90e9945f77aa68a7a219aa4a7df74e"
@@ -7976,6 +8182,23 @@ invariant@^2.2.2, invariant@^2.2.4:
dependencies:
loose-envify "^1.0.0"
ioredis@^4.27.0:
version "4.27.7"
resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.27.7.tgz#11bf2947e23a0e8055931afa7c2da89fc48c8ff3"
integrity sha512-lqvFFmUyGIHlrNyDvBoakzy1+ioJzNyoP6CP97GWtdTjWq9IOAnv6l0HUTsqhvd/z9etGgtrDHZ4kWCMAwNkug==
dependencies:
cluster-key-slot "^1.1.0"
debug "^4.3.1"
denque "^1.1.0"
lodash.defaults "^4.2.0"
lodash.flatten "^4.4.0"
lodash.isarguments "^3.1.0"
p-map "^2.1.0"
redis-commands "1.7.0"
redis-errors "^1.2.0"
redis-parser "^3.0.0"
standard-as-callback "^2.1.0"
ip-regex@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9"
@@ -8037,11 +8260,16 @@ is-boolean-object@^1.1.0:
dependencies:
call-bind "^1.0.2"
is-buffer@^1.1.5:
is-buffer@^1.1.5, is-buffer@~1.1.6:
version "1.1.6"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
is-callable@^1.1.3:
version "1.2.4"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945"
integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==
is-callable@^1.1.4, is-callable@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.2.tgz#c7c6715cd22d4ddb48d3e19970223aceabb080d9"
@@ -8181,6 +8409,14 @@ is-interactive@^1.0.0:
resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e"
integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==
is-nan@^1.3.0:
version "1.3.2"
resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d"
integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==
dependencies:
call-bind "^1.0.0"
define-properties "^1.1.3"
is-negative-zero@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24"
@@ -8878,6 +9114,11 @@ [email protected]:
node-int64 "^0.4.0"
node-rsa "^1.0.7"
join-component@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/join-component/-/join-component-1.1.0.tgz#b8417b750661a392bee2c2537c68b2a9d4977cd5"
integrity sha1-uEF7dQZho5K+4sJTfGiyqdSXfNU=
jpeg-js@^0.4.0:
version "0.4.2"
resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.2.tgz#8b345b1ae4abde64c2da2fe67ea216a114ac279d"
@@ -9137,6 +9378,11 @@ kleur@^3.0.3:
resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
kuler@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3"
integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==
[email protected]:
version "5.1.0"
resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face"
@@ -9341,6 +9587,11 @@ lodash.clonedeep@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
lodash.defaults@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=
lodash.flatten@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f"
@@ -9356,6 +9607,11 @@ lodash.includes@^4.3.0:
resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f"
integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=
lodash.isarguments@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a"
integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=
lodash.isboolean@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6"
@@ -9431,6 +9687,11 @@ lodash.uniq@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
lodash.uniqby@^4.7.0:
version "4.7.0"
resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302"
integrity sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI=
lodash.without@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac"
@@ -9441,6 +9702,11 @@ [email protected], lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
lodash@^4.17.21:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
log-symbols@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18"
@@ -9464,6 +9730,17 @@ log-update@^2.3.0:
cli-cursor "^2.0.0"
wrap-ansi "^3.0.1"
logform@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/logform/-/logform-2.2.0.tgz#40f036d19161fc76b68ab50fdc7fe495544492f2"
integrity sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg==
dependencies:
colors "^1.2.1"
fast-safe-stringify "^2.0.4"
fecha "^4.2.0"
ms "^2.1.1"
triple-beam "^1.3.0"
loose-envify@^1.0.0, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
@@ -9593,6 +9870,15 @@ map-visit@^1.0.0:
dependencies:
object-visit "^1.0.0"
md5@^2.2.1:
version "2.3.0"
resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f"
integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==
dependencies:
charenc "0.0.2"
crypt "0.0.2"
is-buffer "~1.1.6"
memfs@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.2.0.tgz#f9438e622b5acd1daa8a4ae160c496fdd1325b26"
@@ -9866,6 +10152,18 @@ modify-values@^1.0.0:
resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022"
integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==
moment-timezone@^0.5.31:
version "0.5.33"
resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.33.tgz#b252fd6bb57f341c9b59a5ab61a8e51a73bbd22c"
integrity sha512-PTc2vcT8K9J5/9rDEPe5czSIKgLoGsH8UNpA4qZTVw0Vd/Uz19geE9abbIOQKaAQFcnQ3v5YEXrbSc5BpshH+w==
dependencies:
moment ">= 2.9.0"
"moment@>= 2.9.0":
version "2.29.1"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3"
integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==
move-concurrently@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
@@ -10222,7 +10520,7 @@ object-copy@^0.1.0:
define-property "^0.2.5"
kind-of "^3.0.3"
object-inspect@^1.10.3, object-inspect@^1.9.0:
object-inspect@^1.10.3, object-inspect@^1.11.0, object-inspect@^1.9.0:
version "1.11.0"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1"
integrity sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==
@@ -10286,6 +10584,15 @@ object.getownpropertydescriptors@^2.0.3:
define-properties "^1.1.3"
es-abstract "^1.17.0-next.1"
object.getownpropertydescriptors@^2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz#1bd63aeacf0d5d2d2f31b5e393b03a7c601a23f7"
integrity sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ==
dependencies:
call-bind "^1.0.2"
define-properties "^1.1.3"
es-abstract "^1.18.0-next.2"
object.pick@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
@@ -10319,6 +10626,13 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0:
dependencies:
wrappy "1"
one-time@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/one-time/-/one-time-1.0.0.tgz#e06bc174aed214ed58edede573b433bbf827cb45"
integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==
dependencies:
fn.name "1.x.x"
onetime@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4"
@@ -10509,6 +10823,13 @@ p-reduce@^1.0.0:
resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa"
integrity sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=
p-timeout@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe"
integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==
dependencies:
p-finally "^1.0.0"
p-try@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
@@ -10597,6 +10918,11 @@ parse-github-repo-url@^1.3.0:
resolved "https://registry.yarnpkg.com/parse-github-repo-url/-/parse-github-repo-url-1.4.1.tgz#9e7d8bb252a6cb6ba42595060b7bf6df3dbc1f50"
integrity sha1-nn2LslKmy2ukJZUGC3v23z28H1A=
parse-github-url@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/parse-github-url/-/parse-github-url-1.0.2.tgz#242d3b65cbcdda14bb50439e3242acf6971db395"
integrity sha512-kgBf6avCbO3Cn6+RnzRGLkUsv4ZVqv/VfAYkRsyBcgkshNvVBkRn1FEZcW0Jb+npXQWm2vHPnnOqFteZxRRGNw==
parse-headers@^2.0.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.3.tgz#5e8e7512383d140ba02f0c7aa9f49b4399c92515"
@@ -10941,6 +11267,15 @@ promise-retry@^1.1.1:
err-code "^1.0.0"
retry "^0.10.0"
promise.prototype.finally@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/promise.prototype.finally/-/promise.prototype.finally-3.1.2.tgz#b8af89160c9c673cefe3b4c4435b53cfd0287067"
integrity sha512-A2HuJWl2opDH0EafgdjwEw7HysI8ff/n4lW4QEVBCUXFk9QeGecBWv0Deph0UmLe3tTNYegz8MOjsVuE6SMoJA==
dependencies:
define-properties "^1.1.3"
es-abstract "^1.17.0-next.0"
function-bind "^1.1.1"
promise@^7.1.1:
version "7.3.1"
resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
@@ -11078,6 +11413,13 @@ quick-lru@^5.1.1:
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
randombytes@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
dependencies:
safe-buffer "^5.1.0"
rc@^1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
@@ -11191,7 +11533,7 @@ read@1, read@~1.0.1:
dependencies:
mute-stream "~0.0.4"
"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.6, readable-stream@~2.3.6:
"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.6, readable-stream@^2.3.7, readable-stream@~2.3.6:
version "2.3.7"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
@@ -11261,6 +11603,23 @@ redeyed@~2.1.0:
dependencies:
esprima "~4.0.0"
[email protected]:
version "1.7.0"
resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.7.0.tgz#15a6fea2d58281e27b1cd1acfb4b293e278c3a89"
integrity sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ==
redis-errors@^1.0.0, redis-errors@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad"
integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60=
redis-parser@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4"
integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=
dependencies:
redis-errors "^1.0.0"
regenerate-unicode-properties@^8.2.0:
version "8.2.0"
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec"
@@ -11278,6 +11637,11 @@ regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.4:
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
regenerator-runtime@^0.13.5:
version "0.13.9"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==
regenerator-transform@^0.14.2:
version "0.14.5"
resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4"
@@ -11396,6 +11760,11 @@ remove-trailing-separator@^1.0.1:
resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8=
remove-trailing-slash@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/remove-trailing-slash/-/remove-trailing-slash-0.1.1.tgz#be2285a59f39c74d1bce4f825950061915e3780d"
integrity sha512-o4S4Qh6L2jpnCy83ysZDau+VORNvnFw07CKSAymkd6ICNVEPisMyzlc00KlvvicsxKck94SEwhDnMNdICzO+tA==
remove-trailing-spaces@^1.0.6:
version "1.0.8"
resolved "https://registry.yarnpkg.com/remove-trailing-spaces/-/remove-trailing-spaces-1.0.8.tgz#4354d22f3236374702f58ee373168f6d6887ada7"
@@ -11630,7 +11999,7 @@ rxjs@^6.3.3, rxjs@^6.4.0, rxjs@^6.6.0:
dependencies:
tslib "^1.9.0"
safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0:
safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
@@ -11718,6 +12087,13 @@ semver@^7.2.1, semver@^7.3.5:
dependencies:
lru-cache "^6.0.0"
serialize-javascript@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4"
integrity sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==
dependencies:
randombytes "^2.1.0"
set-blocking@^2.0.0, set-blocking@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
@@ -12026,6 +12402,11 @@ ssri@^6.0.0, ssri@^6.0.1:
dependencies:
figgy-pudding "^3.5.1"
[email protected]:
version "0.0.10"
resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=
stack-utils@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.2.tgz#5cf48b4557becb4638d0bc4f21d23f5d19586593"
@@ -12033,6 +12414,11 @@ stack-utils@^2.0.2:
dependencies:
escape-string-regexp "^2.0.0"
standard-as-callback@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45"
integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==
static-extend@^0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
@@ -12451,6 +12837,11 @@ text-extensions@^1.0.0:
resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26"
integrity sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==
[email protected]:
version "1.0.0"
resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5"
integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==
text-table@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
@@ -12623,6 +13014,11 @@ trim-off-newlines@^1.0.0:
resolved "https://registry.yarnpkg.com/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz#9f9ba9d9efa8764c387698bcbfeb2c848f11adb3"
integrity sha1-n5up2e+odkw4dpi8v+sshI8RrbM=
triple-beam@^1.2.0, triple-beam@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9"
integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==
ts-log@^2.2.3:
version "2.2.3"
resolved "https://registry.yarnpkg.com/ts-log/-/ts-log-2.2.3.tgz#4da5640fe25a9fb52642cd32391c886721318efb"
@@ -12971,12 +13367,23 @@ util-promisify@^2.1.0:
dependencies:
object.getownpropertydescriptors "^2.0.3"
util.promisify@^1.0.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.1.1.tgz#77832f57ced2c9478174149cae9b96e9918cd54b"
integrity sha512-/s3UsZUrIfa6xDhr7zZhnE9SLQ5RIXyYfiVnMMyMDzOc8WhWN4Nbh36H842OyurKbCDAesZOJaVyvmSl6fhGQw==
dependencies:
call-bind "^1.0.0"
define-properties "^1.1.3"
for-each "^0.3.3"
has-symbols "^1.0.1"
object.getownpropertydescriptors "^2.1.1"
[email protected], uuid@^8.3.0:
version "8.3.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.0.tgz#ab738085ca22dc9a8c92725e459b1d507df5d6ea"
integrity sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ==
uuid@^3.0.1, uuid@^3.3.2:
uuid@^3.0.1, uuid@^3.2.1, uuid@^3.3.2:
version "3.4.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
@@ -13185,6 +13592,29 @@ windows-release@^3.1.0:
dependencies:
execa "^1.0.0"
winston-transport@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.4.0.tgz#17af518daa690d5b2ecccaa7acf7b20ca7925e59"
integrity sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==
dependencies:
readable-stream "^2.3.7"
triple-beam "^1.2.0"
winston@^3.3.3:
version "3.3.3"
resolved "https://registry.yarnpkg.com/winston/-/winston-3.3.3.tgz#ae6172042cafb29786afa3d09c8ff833ab7c9170"
integrity sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==
dependencies:
"@dabh/diagnostics" "^2.0.2"
async "^3.1.0"
is-stream "^2.0.0"
logform "^2.2.0"
one-time "^1.0.0"
readable-stream "^3.4.0"
stack-trace "0.0.x"
triple-beam "^1.3.0"
winston-transport "^4.4.0"
wonka@^4.0.14:
version "4.0.14"
resolved "https://registry.yarnpkg.com/wonka/-/wonka-4.0.14.tgz#77d680a84e575ed15a9f975eb87d6c530488f3a4"