Compare commits

...
13 Commits
Author SHA1 Message Date
Brent Vatne a9da78946b v0.18.2 2021-06-25 14:57:32 -07:00
Brent Vatne b6d9accea4 [eas-cli] Fix inverted conditional so we actually only prompt about commit when index is dirty (#481) 2021-06-25 14:54:26 -07:00
Quinlan Jung 4611a65bce [eas-cli] show projects that depend on a push key (#472) 2021-06-25 13:55:16 -07:00
Quinlan Jung db29b3fc18 [eas-cli] make apple team optional in appropriate cases (#468)
* [eas-cli] make apple team optional in appropriate cases

* pr feedback
2021-06-25 13:53:37 -07:00
Dominik Sokal 2534a46bd3 [ENG-1396] change default ios image for sdk <= 41 (#479)
* change default ios image for sdk <= 41

* update CHANGELOG
2021-06-25 15:23:24 +02:00
Dominik Sokal 7def4b502e remove redundant type 2021-06-25 13:58:38 +02:00
Brent Vatne 4ea26d7ca3 Remove leftover CHANGELOG entry 2021-06-24 17:56:14 -07:00
Brent Vatne c4c8075b1f Update CHANGELOG 2021-06-24 17:55:06 -07:00
Brent Vatne 266545d2a0 v0.18.1 2021-06-24 17:43:58 -07:00
Brent Vatne ddd7046513 Add entry to CHANGELOG 2021-06-24 17:43:14 -07:00
Quinlan Jung 7a44eeb22b [eas-cli] add basic printing support for Apple App Specific Password (#474) 2021-06-24 17:42:00 -07:00
Brent Vatne 5bcf8263cf [eas-cli] Automatically migrate build credentials to EAS (#477) 2021-06-24 17:41:17 -07:00
Dominik Sokal f380ba0106 update CHANGELOG 2021-06-24 13:35:32 +02:00
29 changed files with 254 additions and 137 deletions

No files matched your search

+24 -2
View File
@@ -6,6 +6,30 @@ This is the log of notable changes to EAS CLI and related packages.
### 🛠 Breaking changes
### 🎉 New features
- Change default iOS image for projects with Expo SDK <= 41 (SDK 41 won't build with Xcode 12.5). ([#479](https://github.com/expo/eas-cli/pull/479) by [@dsokal](https://github.com/dsokal))
### 🐛 Bug fixes
- Fix inverted conditional so we actually only prompt about commit when index is dirty. ([#481](https://github.com/expo/eas-cli/pull/481) by [@brentvatne](https://github.com/brentvatne))
### 🧹 Chores
## [0.18.1](https://github.com/expo/eas-cli/releases/tag/v0.18.1) - 2021-06-24
### 🎉 New features
- Add basic printing support for Apple App Specific Password. ([#474](https://github.com/expo/eas-cli/pull/474) by [@quinlanj](https://github.com/quinlanj))
### 🐛 Bug fixes
- Fix CLI UI getting blocked on credentials migration, leading to partially migrated state. ([#477](https://github.com/expo/eas-cli/pull/477) by [@brentvatne](https://github.com/brentvatne))
## [0.18.0](https://github.com/expo/eas-cli/releases/tag/v0.18.0) - 2021-06-24
### 🛠 Breaking changes
- Drop support for `experimental.npmToken` in credentials.json, EAS Secrets can be used instead. ([#444](https://github.com/expo/eas-cli/pull/444) by [@dsokal](https://github.com/dsokal))
- Remove `--allow-experimental` flag from `eas build:configure` as it has no effect now. ([#444](https://github.com/expo/eas-cli/pull/444) by [@dsokal](https://github.com/dsokal))
@@ -20,8 +44,6 @@ This is the log of notable changes to EAS CLI and related packages.
- iOS push key setup and management now available in `eas-cli credentials`. ([#469](https://github.com/expo/eas-cli/pull/469) [#470](https://github.com/expo/eas-cli/pull/470) by [@quinlanj](https://github.com/quinlanj))
- Support new build status: `new`. ([#475](https://github.com/expo/eas-cli/pull/475) by [@dsokal](https://github.com/dsokal))
### 🐛 Bug fixes
### 🧹 Chores
- Deprecate `--skip-credentials-check` flag because it doesn't do anything and is no longer needed. ([#442](https://github.com/expo/eas-cli/pull/442) by [@brentvatne](https://github.com/brentvatne))
+1 -1
View File
@@ -1,5 +1,5 @@
{
"npmClient": "yarn",
"useWorkspaces": true,
"version": "0.18.0"
"version": "0.18.2"
}
+23 -24
View File
@@ -69,7 +69,7 @@ ALIASES
$ eas login
```
_See code: [src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v0.18.0/packages/eas-cli/src/commands/account/login.ts)_
_See code: [src/commands/account/login.ts](https://github.com/expo/eas-cli/blob/v0.18.2/packages/eas-cli/src/commands/account/login.ts)_
## `eas account:logout`
@@ -83,7 +83,7 @@ ALIASES
$ eas logout
```
_See code: [src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v0.18.0/packages/eas-cli/src/commands/account/logout.ts)_
_See code: [src/commands/account/logout.ts](https://github.com/expo/eas-cli/blob/v0.18.2/packages/eas-cli/src/commands/account/logout.ts)_
## `eas account:view`
@@ -97,7 +97,7 @@ ALIASES
$ eas whoami
```
_See code: [src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v0.18.0/packages/eas-cli/src/commands/account/view.ts)_
_See code: [src/commands/account/view.ts](https://github.com/expo/eas-cli/blob/v0.18.2/packages/eas-cli/src/commands/account/view.ts)_
## `eas analytics [STATUS]`
@@ -108,7 +108,7 @@ USAGE
$ eas analytics [STATUS]
```
_See code: [src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v0.18.0/packages/eas-cli/src/commands/analytics.ts)_
_See code: [src/commands/analytics.ts](https://github.com/expo/eas-cli/blob/v0.18.2/packages/eas-cli/src/commands/analytics.ts)_
## `eas build`
@@ -128,7 +128,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.18.0/packages/eas-cli/src/commands/build/index.ts)_
_See code: [src/commands/build/index.ts](https://github.com/expo/eas-cli/blob/v0.18.2/packages/eas-cli/src/commands/build/index.ts)_
## `eas build:cancel [BUILD_ID]`
@@ -139,7 +139,7 @@ USAGE
$ eas build:cancel [BUILD_ID]
```
_See code: [src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v0.18.0/packages/eas-cli/src/commands/build/cancel.ts)_
_See code: [src/commands/build/cancel.ts](https://github.com/expo/eas-cli/blob/v0.18.2/packages/eas-cli/src/commands/build/cancel.ts)_
## `eas build:configure`
@@ -153,7 +153,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.18.0/packages/eas-cli/src/commands/build/configure.ts)_
_See code: [src/commands/build/configure.ts](https://github.com/expo/eas-cli/blob/v0.18.2/packages/eas-cli/src/commands/build/configure.ts)_
## `eas build:list`
@@ -169,7 +169,7 @@ OPTIONS
--status=(new|in-queue|in-progress|errored|finished|canceled)
```
_See code: [src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v0.18.0/packages/eas-cli/src/commands/build/list.ts)_
_See code: [src/commands/build/list.ts](https://github.com/expo/eas-cli/blob/v0.18.2/packages/eas-cli/src/commands/build/list.ts)_
## `eas build:view [BUILD_ID]`
@@ -180,7 +180,7 @@ USAGE
$ eas build:view [BUILD_ID]
```
_See code: [src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v0.18.0/packages/eas-cli/src/commands/build/view.ts)_
_See code: [src/commands/build/view.ts](https://github.com/expo/eas-cli/blob/v0.18.2/packages/eas-cli/src/commands/build/view.ts)_
## `eas credentials`
@@ -191,7 +191,7 @@ USAGE
$ eas credentials
```
_See code: [src/commands/credentials.ts](https://github.com/expo/eas-cli/blob/v0.18.0/packages/eas-cli/src/commands/credentials.ts)_
_See code: [src/commands/credentials.ts](https://github.com/expo/eas-cli/blob/v0.18.2/packages/eas-cli/src/commands/credentials.ts)_
## `eas device:create`
@@ -202,7 +202,7 @@ USAGE
$ eas device:create
```
_See code: [src/commands/device/create.ts](https://github.com/expo/eas-cli/blob/v0.18.0/packages/eas-cli/src/commands/device/create.ts)_
_See code: [src/commands/device/create.ts](https://github.com/expo/eas-cli/blob/v0.18.2/packages/eas-cli/src/commands/device/create.ts)_
## `eas device:list`
@@ -216,7 +216,7 @@ OPTIONS
--apple-team-id=apple-team-id
```
_See code: [src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v0.18.0/packages/eas-cli/src/commands/device/list.ts)_
_See code: [src/commands/device/list.ts](https://github.com/expo/eas-cli/blob/v0.18.2/packages/eas-cli/src/commands/device/list.ts)_
## `eas device:view [UDID]`
@@ -227,7 +227,7 @@ USAGE
$ eas device:view [UDID]
```
_See code: [src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v0.18.0/packages/eas-cli/src/commands/device/view.ts)_
_See code: [src/commands/device/view.ts](https://github.com/expo/eas-cli/blob/v0.18.2/packages/eas-cli/src/commands/device/view.ts)_
## `eas help [COMMAND]`
@@ -260,7 +260,7 @@ OPTIONS
--value=value Value of the secret
```
_See code: [src/commands/secret/create.ts](https://github.com/expo/eas-cli/blob/v0.18.0/packages/eas-cli/src/commands/secret/create.ts)_
_See code: [src/commands/secret/create.ts](https://github.com/expo/eas-cli/blob/v0.18.2/packages/eas-cli/src/commands/secret/create.ts)_
## `eas secret:delete`
@@ -277,7 +277,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.18.0/packages/eas-cli/src/commands/secret/delete.ts)_
_See code: [src/commands/secret/delete.ts](https://github.com/expo/eas-cli/blob/v0.18.2/packages/eas-cli/src/commands/secret/delete.ts)_
## `eas secret:list`
@@ -288,7 +288,7 @@ USAGE
$ eas secret:list
```
_See code: [src/commands/secret/list.ts](https://github.com/expo/eas-cli/blob/v0.18.0/packages/eas-cli/src/commands/secret/list.ts)_
_See code: [src/commands/secret/list.ts](https://github.com/expo/eas-cli/blob/v0.18.2/packages/eas-cli/src/commands/secret/list.ts)_
## `eas submit --platform=(android|ios)`
@@ -314,8 +314,7 @@ OPTIONS
iOS specific options=asc-app-id App Store Connect unique application Apple ID
number. Providing this param results in skipping
app creation step. Learn more:
https://expo.fyi/asc-app-id
app creation step. Learn more.
iOS specific options=bundle-identifier Your iOS Bundle Identifier (default:
expo.ios.bundleIdentifier from app config)
@@ -368,7 +367,7 @@ EXAMPLES
and provide its App ID
```
_See code: [src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v0.18.0/packages/eas-cli/src/commands/submit.ts)_
_See code: [src/commands/submit.ts](https://github.com/expo/eas-cli/blob/v0.18.2/packages/eas-cli/src/commands/submit.ts)_
## `eas webhook:create`
@@ -387,7 +386,7 @@ OPTIONS
--url=url Webhook URL
```
_See code: [src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v0.18.0/packages/eas-cli/src/commands/webhook/create.ts)_
_See code: [src/commands/webhook/create.ts](https://github.com/expo/eas-cli/blob/v0.18.2/packages/eas-cli/src/commands/webhook/create.ts)_
## `eas webhook:delete [ID]`
@@ -401,7 +400,7 @@ ARGUMENTS
ID ID of the webhook to delete
```
_See code: [src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v0.18.0/packages/eas-cli/src/commands/webhook/delete.ts)_
_See code: [src/commands/webhook/delete.ts](https://github.com/expo/eas-cli/blob/v0.18.2/packages/eas-cli/src/commands/webhook/delete.ts)_
## `eas webhook:list`
@@ -415,7 +414,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.18.0/packages/eas-cli/src/commands/webhook/list.ts)_
_See code: [src/commands/webhook/list.ts](https://github.com/expo/eas-cli/blob/v0.18.2/packages/eas-cli/src/commands/webhook/list.ts)_
## `eas webhook:update`
@@ -435,7 +434,7 @@ OPTIONS
--url=url Webhook URL
```
_See code: [src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v0.18.0/packages/eas-cli/src/commands/webhook/update.ts)_
_See code: [src/commands/webhook/update.ts](https://github.com/expo/eas-cli/blob/v0.18.2/packages/eas-cli/src/commands/webhook/update.ts)_
## `eas webhook:view ID`
@@ -449,5 +448,5 @@ ARGUMENTS
ID ID of the webhook to view
```
_See code: [src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v0.18.0/packages/eas-cli/src/commands/webhook/view.ts)_
_See code: [src/commands/webhook/view.ts](https://github.com/expo/eas-cli/blob/v0.18.2/packages/eas-cli/src/commands/webhook/view.ts)_
<!-- commandsstop -->
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "eas-cli",
"description": "EAS command line tool",
"version": "0.18.0",
"version": "0.18.2",
"author": "Expo <[email protected]>",
"bin": {
"eas": "./bin/run"
@@ -14,7 +14,7 @@
"@expo/config": "3.3.42",
"@expo/config-plugins": "2.0.2",
"@expo/eas-build-job": "0.2.37",
"@expo/eas-json": "^0.18.0",
"@expo/eas-json": "^0.18.2",
"@expo/json-file": "8.2.25",
"@expo/pkcs12": "0.0.4",
"@expo/plist": "0.0.11",
+13 -1
View File
@@ -1,6 +1,7 @@
import { ArchiveSource, Cache, Ios, Job, Workflow, sanitizeJob } from '@expo/eas-build-job';
import { IosGenericBuildProfile, IosManagedBuildProfile } from '@expo/eas-json';
import path from 'path';
import semver from 'semver';
import { IosCredentials, TargetCredentials } from '../../credentials/ios/types';
import { getUsername } from '../../project/projectUtils';
@@ -59,7 +60,7 @@ async function prepareJobCommonAsync(
projectArchive,
distribution: ctx.buildProfile.distribution,
builderEnvironment: {
image: ctx.buildProfile.image,
image: resolveImage(ctx),
node: ctx.buildProfile.node,
yarn: ctx.buildProfile.yarn,
bundler: ctx.buildProfile.bundler,
@@ -78,6 +79,17 @@ async function prepareJobCommonAsync(
};
}
function resolveImage(ctx: BuildContext<Platform.IOS>): Ios.BuilderEnvironment['image'] {
// see https://linear.app/expo/issue/ENG-1396/make-default-image-dependent-on-sdk-version
if (!ctx.buildProfile.image && ctx.commandCtx.exp.sdkVersion) {
const majorSdkVersion = semver.major(ctx.commandCtx.exp.sdkVersion);
if (majorSdkVersion <= 41) {
return 'macos-catalina-10.15-xcode-12.4';
}
}
return ctx.buildProfile.image ?? 'default';
}
function prepareTargetCredentials(targetCredentials: TargetCredentials): Ios.TargetCredentials {
return {
provisioningProfileBase64: targetCredentials.provisioningProfile,
@@ -13,7 +13,7 @@ import { endTimer, formatMilliseconds, startTimer } from '../../utils/timer';
import vcs from '../../vcs';
export async function maybeBailOnRepoStatusAsync(): Promise<void> {
if (await vcs.hasUncommittedChangesAsync()) {
if (!(await vcs.hasUncommittedChangesAsync())) {
return;
}
Log.addNewLineIfNone();
@@ -40,6 +40,7 @@ export const testPushKey: ApplePushKeyFragment = {
keyIdentifier: 'test-key-identifier',
appleTeam: { ...testAppleTeamFragment },
updatedAt: new Date(),
iosAppCredentialsList: [],
};
export const testTargets: Target[] = [{ targetName: 'testapp', bundleIdentifier: 'foo.bar.com' }];
@@ -3,10 +3,9 @@ import { nanoid } from 'nanoid';
import ora from 'ora';
import { AndroidAppBuildCredentialsFragment } from '../../../graphql/generated';
import Log from '../../../log';
import { getApplicationId } from '../../../project/android/applicationId';
import { getProjectAccountName, getProjectConfigDescription } from '../../../project/projectUtils';
import { confirmAsync, promptAsync } from '../../../prompts';
import { promptAsync } from '../../../prompts';
import { findAccountByName } from '../../../user/Account';
import { Context } from '../../context';
import { AppLookupParams } from '../api/GraphqlClient';
@@ -34,62 +33,57 @@ export async function promptUserAndCopyLegacyCredentialsAsync(
ctx: Context,
app: AppLookupParams
): Promise<void> {
assert(
!ctx.nonInteractive,
'Copying over Expo Classic credentials cannot be run in non-interactive mode'
);
assert(
await canCopyLegacyCredentialsAsync(ctx, app),
'User not eligible to copy Expo Classic credentials to EAS'
'User not eligible to copy classic build credentials to EAS'
);
const shouldCopy = await confirmAsync({
message: `We've detected credentials from Expo Classic (expo-cli). Would you like to copy them over to Expo Application Services (EAS)?`,
});
if (!shouldCopy) {
return;
}
Log.log('Copying credentials...');
const spinner = ora().start();
const spinner = ora('Classic credentials detected, copying to EAS...').start();
const legacyAppCredentials = await ctx.android.getLegacyAndroidAppCredentialsWithCommonFieldsAsync(
app
);
if (!legacyAppCredentials) {
return;
}
const appCredentials = await ctx.android.createOrGetExistingAndroidAppCredentialsWithBuildCredentialsAsync(
app
);
const legacyFcm = legacyAppCredentials.androidFcm;
if (legacyFcm) {
const clonedFcm = await ctx.android.createFcmAsync(
app.account,
legacyFcm.credential,
legacyFcm.version
try {
const legacyAppCredentials = await ctx.android.getLegacyAndroidAppCredentialsWithCommonFieldsAsync(
app
);
await ctx.android.updateAndroidAppCredentialsAsync(appCredentials, {
androidFcmId: clonedFcm.id,
});
if (!legacyAppCredentials) {
return;
}
const appCredentials = await ctx.android.createOrGetExistingAndroidAppCredentialsWithBuildCredentialsAsync(
app
);
const legacyFcm = legacyAppCredentials.androidFcm;
if (legacyFcm) {
const clonedFcm = await ctx.android.createFcmAsync(
app.account,
legacyFcm.credential,
legacyFcm.version
);
await ctx.android.updateAndroidAppCredentialsAsync(appCredentials, {
androidFcmId: clonedFcm.id,
});
}
const legacyBuildCredentials = await ctx.android.getLegacyAndroidAppBuildCredentialsAsync(app);
const legacyKeystore = legacyBuildCredentials?.androidKeystore ?? null;
if (legacyKeystore) {
const clonedKeystore = await ctx.android.createKeystoreAsync(app.account, {
keystore: legacyKeystore.keystore,
keystorePassword: legacyKeystore.keystorePassword,
keyAlias: legacyKeystore.keyAlias,
keyPassword: legacyKeystore.keyPassword ?? undefined,
type: legacyKeystore.type,
});
await createOrUpdateDefaultAndroidAppBuildCredentialsAsync(ctx, app, {
androidKeystoreId: clonedKeystore.id,
});
}
} catch (e) {
spinner.fail(`Unable to migrate credentials to EAS.`);
throw e;
}
const legacyBuildCredentials = await ctx.android.getLegacyAndroidAppBuildCredentialsAsync(app);
const legacyKeystore = legacyBuildCredentials?.androidKeystore ?? null;
if (legacyKeystore) {
const clonedKeystore = await ctx.android.createKeystoreAsync(app.account, {
keystore: legacyKeystore.keystore,
keystorePassword: legacyKeystore.keystorePassword,
keyAlias: legacyKeystore.keyAlias,
keyPassword: legacyKeystore.keyPassword ?? undefined,
type: legacyKeystore.type,
});
await createOrUpdateDefaultAndroidAppBuildCredentialsAsync(ctx, app, {
androidKeystoreId: clonedKeystore.id,
});
}
spinner.succeed('Credentials successfully copied');
spinner.succeed('Credentials copied to EAS.');
}
export function getAppLookupParamsFromContext(ctx: Context): AppLookupParams {
@@ -135,9 +129,8 @@ export async function createOrUpdateDefaultAndroidAppBuildCredentialsAsync(
{ androidKeystoreId }
);
}
const providedName = await promptForNameAsync();
return await ctx.android.createAndroidAppBuildCredentialsAsync(appLookupParams, {
name: providedName,
name: generateRandomName(),
isDefault: true,
androidKeystoreId,
});
@@ -1,4 +1,5 @@
import nullthrows from 'nullthrows';
import ora from 'ora';
import {
AndroidAppBuildCredentialsFragment,
@@ -94,9 +95,9 @@ export class SetupBuildCredentials {
);
const defaultKeystore = defaultBuildCredentials?.androidKeystore ?? null;
if (defaultKeystore) {
Log.log(
ora(
`Using Keystore from configuration: ${nullthrows(defaultBuildCredentials).name} (default)`
);
).succeed();
return defaultBuildCredentials;
}
return null;
@@ -118,11 +119,11 @@ export class SetupBuildCredentials {
const keystore = maybeBuildCredentials?.androidKeystore ?? null;
if (keystore) {
const buildCredentials = nullthrows(maybeBuildCredentials);
Log.log(
ora(
`Using Keystore from configuration: ${buildCredentials.name}${
buildCredentials.isDefault ? ' (default)' : ''
}`
);
).succeed();
return buildCredentials;
}
Log.log(
@@ -2,7 +2,6 @@ import { ApplePushKeyFragment, CommonIosAppCredentialsFragment } from '../../../
import Log from '../../../log';
import { Context } from '../../context';
import { AppLookupParams } from '../api/GraphqlClient';
import { AppleTeamMissingError } from '../errors';
import { resolveAppleTeamIfAuthenticatedAsync } from './AppleTeamUtils';
export class AssignPushKey {
@@ -14,15 +13,9 @@ export class AssignPushKey {
): Promise<CommonIosAppCredentialsFragment> {
const appleTeam =
(await resolveAppleTeamIfAuthenticatedAsync(ctx, this.app)) ?? pushKey.appleTeam ?? null;
if (!appleTeam) {
// TODO(quin): make this optional
throw new AppleTeamMissingError(
'An Apple Team is required to proceed. You must be authenticated to your Apple account'
);
}
const appCredentials = await ctx.ios.createOrGetIosAppCredentialsWithCommonFieldsAsync(
this.app,
{ appleTeam }
{ appleTeam: appleTeam ?? undefined }
);
const updatedAppCredentials = await ctx.ios.updateIosAppCredentialsAsync(appCredentials, {
applePushKeyId: pushKey.id,
@@ -187,6 +187,12 @@ export function formatPushKey(
line += ` ${appleTeam ? `, ${formatAppleTeam(appleTeam)}` : ''}`;
line += chalk.gray(`\n Updated: ${fromNow(new Date(updatedAt))} ago,`);
const apps = pushKey.iosAppCredentialsList.map(appCredentials => appCredentials.app);
if (apps.length) {
const appFullNames = apps.map(app => app.fullName).join(',');
line += chalk.gray(`\n 📲 Used by: ${appFullNames}`);
}
if (validPushKeyIdentifiers?.includes(keyIdentifier)) {
line += chalk.gray("\n ✅ Currently valid on Apple's servers.");
} else {
@@ -26,13 +26,16 @@ export class RemovePushKey {
throw new Error(`Cannot remove push keys in non-interactive mode`);
}
// TODO(quin): show the projects that rely on this
const confirm = await confirmAsync({
message: `Removing this push key will disable push notifications for projects that rely on it. Do you want to continue?`,
});
if (!confirm) {
return;
const apps = this.pushKey.iosAppCredentialsList.map(appCredentials => appCredentials.app);
if (apps.length !== 0) {
const appFullNames = apps.map(app => app.fullName).join(',');
const confirm = await confirmAsync({
message: `Removing this push key will disable push notifications for ${appFullNames}. Do you want to continue?`,
});
if (!confirm) {
Log.log('Aborting');
return;
}
}
Log.log('Removing Push Key');
@@ -11,6 +11,7 @@ import {
IosAppBuildCredentialsFragment,
IosDistributionType,
} from '../../../graphql/generated';
import { isWildcardBundleIdentifier } from '../../../project/ios/bundleIdentifier';
import { Account } from '../../../user/Account';
import { DistributionCertificate, PushKey } from '../appstore/Credentials.types';
import { AppleTeamMissingError } from '../errors';
@@ -138,7 +139,7 @@ export async function createOrGetIosAppCredentialsWithCommonFieldsAsync(
{
appleTeam,
}: {
appleTeam: AppleTeamFragment;
appleTeam?: AppleTeamFragment;
}
): Promise<CommonIosAppCredentialsFragment> {
const maybeIosAppCredentials = await getIosAppCredentialsWithCommonFieldsAsync(appLookupParams);
@@ -147,10 +148,10 @@ export async function createOrGetIosAppCredentialsWithCommonFieldsAsync(
}
const [app, appleAppIdentifier] = await Promise.all([
getAppAsync(appLookupParams),
createOrGetExistingAppleAppIdentifierAsync(appLookupParams, appleTeam),
createOrGetExistingAppleAppIdentifierAsync(appLookupParams, appleTeam ?? null),
]);
return await IosAppCredentialsMutation.createIosAppCredentialsAsync(
{ appleTeamId: appleTeam.id },
{ appleTeamId: appleTeam?.id },
app.id,
appleAppIdentifier.id
);
@@ -181,7 +182,7 @@ async function createOrGetExistingIosAppCredentialsWithBuildCredentialsAsync(
appleAppIdentifierId,
iosDistributionType,
}: {
appleTeam: AppleTeamFragment;
appleTeam?: AppleTeamFragment;
appleAppIdentifierId: string;
iosDistributionType: IosDistributionType;
}
@@ -197,10 +198,10 @@ async function createOrGetExistingIosAppCredentialsWithBuildCredentialsAsync(
} else {
const [app, appleAppIdentifier] = await Promise.all([
getAppAsync(appLookupParams),
createOrGetExistingAppleAppIdentifierAsync(appLookupParams, appleTeam),
createOrGetExistingAppleAppIdentifierAsync(appLookupParams, appleTeam ?? null),
]);
await IosAppCredentialsMutation.createIosAppCredentialsAsync(
{ appleTeamId: appleTeam.id },
{ appleTeamId: appleTeam?.id },
app.id,
appleAppIdentifier.id
);
@@ -243,8 +244,10 @@ export async function createOrGetExistingAppleAppIdentifierAsync(
if (appleAppIdentifier) {
return appleAppIdentifier;
} else {
if (!appleTeam) {
throw new AppleTeamMissingError();
if (isWildcardBundleIdentifier(bundleIdentifier) && !appleTeam) {
throw new AppleTeamMissingError(
`An Apple Team is required for wildcard bundle identifier: ${bundleIdentifier}`
);
}
const parentAppleAppIdentifier = parentBundleIdentifier
? await createOrGetExistingAppleAppIdentifierAsync(
@@ -255,7 +258,7 @@ export async function createOrGetExistingAppleAppIdentifierAsync(
return await AppleAppIdentifierMutation.createAppleAppIdentifierAsync(
{
bundleIdentifier,
appleTeamId: appleTeam.id,
appleTeamId: appleTeam?.id,
parentAppleAppId: parentAppleAppIdentifier?.id,
},
account.id
@@ -30,6 +30,13 @@ const IosAppCredentialsQuery = {
},
__typename: 'ApplePushKey',
},
appSpecificPassword: {
id: '64bdd007-da7b-4190-a571-edb87e9324a1',
appleIdUsername: '[email protected]',
passwordLabel: 'description for super secret password',
updatedAt: '2020-10-13T18:39:04.463Z',
__typename: 'AppleAppSpecificPassword',
},
iosAppBuildCredentialsList: [
{
id: '6f8d0175-0caf-4922-b09b-eae757b83144',
@@ -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 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: [email protected] 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"`;
@@ -2,6 +2,7 @@ import chalk from 'chalk';
import dateformat from 'dateformat';
import {
AppleAppSpecificPasswordFragment,
AppleDeviceFragment,
ApplePushKeyFragment,
IosAppBuildCredentialsFragment,
@@ -84,7 +85,7 @@ export function displayIosCredentials(
continue;
}
const { appleTeam, pushKey } = targetAppCredentials;
const { appleTeam, pushKey, appSpecificPassword } = targetAppCredentials;
if (appleTeam) {
const { appleTeamIdentifier, appleTeamName } = appleTeam;
Log.log(` Apple Team: ${appleTeamIdentifier} ${appleTeamName ? `(${appleTeamName})` : ''}`);
@@ -95,6 +96,10 @@ export function displayIosCredentials(
displayApplePushKey(pushKey);
}
if (appSpecificPassword) {
displayAppSpecificPassword(appSpecificPassword);
}
const sortedIosAppBuildCredentialsList = sortBuildCredentialsByDistributionType(
targetAppCredentials.iosAppBuildCredentialsList
);
@@ -189,6 +194,23 @@ function displayIosAppBuildCredentials(buildCredentials: IosAppBuildCredentialsF
Log.newLine();
}
function displayAppSpecificPassword(
maybeAppSpecificPassword: AppleAppSpecificPasswordFragment | null
): void {
Log.log(` App Specific Password:`);
if (maybeAppSpecificPassword) {
const { appleIdUsername, passwordLabel, updatedAt } = maybeAppSpecificPassword;
Log.log(` Apple ID Username: ${appleIdUsername}`);
if (passwordLabel) {
Log.log(` Password Label: ${passwordLabel}`);
}
Log.log(` Updated ${fromNow(new Date(updatedAt))} ago`);
} else {
Log.log(` None assigned yet`);
}
Log.newLine();
}
function displayApplePushKey(maybePushKey: ApplePushKeyFragment | null): void {
Log.log(` Push Key:`);
if (maybePushKey) {
+21
View File
@@ -5088,6 +5088,11 @@ export type AppleAppIdentifierFragment = (
& Pick<AppleAppIdentifier, 'id' | 'bundleIdentifier'>
);
export type AppleAppSpecificPasswordFragment = (
{ __typename?: 'AppleAppSpecificPassword' }
& Pick<AppleAppSpecificPassword, 'id' | 'appleIdUsername' | 'passwordLabel' | 'updatedAt'>
);
export type AppleDeviceFragment = (
{ __typename?: 'AppleDevice' }
& Pick<AppleDevice, 'id' | 'identifier' | 'name' | 'model' | 'deviceClass'>
@@ -5154,6 +5159,18 @@ export type ApplePushKeyFragment = (
{ __typename?: 'AppleTeam' }
& Pick<AppleTeam, 'id'>
& AppleTeamFragment
)>, iosAppCredentialsList: Array<(
{ __typename?: 'IosAppCredentials' }
& Pick<IosAppCredentials, 'id'>
& { app: (
{ __typename?: 'App' }
& Pick<App, 'id'>
& AppFragment
), appleAppIdentifier: (
{ __typename?: 'AppleAppIdentifier' }
& Pick<AppleAppIdentifier, 'id'>
& AppleAppIdentifierFragment
) }
)> }
);
@@ -5195,6 +5212,10 @@ export type CommonIosAppCredentialsWithoutBuildCredentialsFragment = (
{ __typename?: 'ApplePushKey' }
& Pick<ApplePushKey, 'id'>
& ApplePushKeyFragment
)>, appSpecificPassword?: Maybe<(
{ __typename?: 'AppleAppSpecificPassword' }
& Pick<AppleAppSpecificPassword, 'id'>
& AppleAppSpecificPasswordFragment
)> }
);
@@ -4,7 +4,6 @@ import gql from 'graphql-tag';
import { graphqlClient, withErrorHandlingAsync } from '../client';
import {
AppPlatform,
Build,
BuildFragment,
BuildStatus,
BuildsByIdQuery,
@@ -21,8 +20,6 @@ type Filters = {
limit?: number;
};
type PendingBuildQueryResult = Pick<Build, 'id' | 'platform'>;
export const BuildQuery = {
async byIdAsync(
buildId: string,
@@ -0,0 +1,10 @@
import gql from 'graphql-tag';
export const AppleAppSpecificPasswordFragmentNode = gql`
fragment AppleAppSpecificPasswordFragment on AppleAppSpecificPassword {
id
appleIdUsername
passwordLabel
updatedAt
}
`;
@@ -1,6 +1,8 @@
import { print } from 'graphql';
import gql from 'graphql-tag';
import { AppFragmentNode } from '../App';
import { AppleAppIdentifierFragmentNode } from './AppleAppIdentifier';
import { AppleTeamFragmentNode } from './AppleTeam';
export const ApplePushKeyFragmentNode = gql`
@@ -12,6 +14,19 @@ export const ApplePushKeyFragmentNode = gql`
id
...AppleTeamFragment
}
iosAppCredentialsList {
id
app {
id
...AppFragment
}
appleAppIdentifier {
id
...AppleAppIdentifierFragment
}
}
}
${print(AppleTeamFragmentNode)}
${print(AppFragmentNode)}
${print(AppleAppIdentifierFragmentNode)}
`;
@@ -2,6 +2,7 @@ import gql from 'graphql-tag';
import { AppFragmentNode } from '../App';
import { AppleAppIdentifierFragmentNode } from './AppleAppIdentifier';
import { AppleAppSpecificPasswordFragmentNode } from './AppleAppSpecificPassword';
import { ApplePushKeyFragmentNode } from './ApplePushKey';
import { AppleTeamFragmentNode } from './AppleTeam';
import { IosAppBuildCredentialsFragmentNode } from './IosAppBuildCredentials';
@@ -25,11 +26,16 @@ export const CommonIosAppCredentialsWithoutBuildCredentialsFragmentNode = gql`
id
...ApplePushKeyFragment
}
appSpecificPassword {
id
...AppleAppSpecificPasswordFragment
}
}
${AppFragmentNode}
${AppleTeamFragmentNode}
${AppleAppIdentifierFragmentNode}
${ApplePushKeyFragmentNode}
${AppleAppSpecificPasswordFragmentNode}
`;
export const CommonIosAppCredentialsFragmentNode = gql`
@@ -8,6 +8,7 @@ import { promptAsync } from '../../../prompts';
import {
ensureBundleIdentifierIsDefinedForManagedProjectAsync,
getBundleIdentifier,
isWildcardBundleIdentifier,
} from '../bundleIdentifier';
jest.mock('fs');
@@ -141,3 +142,15 @@ describe(ensureBundleIdentifierIsDefinedForManagedProjectAsync, () => {
});
});
});
describe(isWildcardBundleIdentifier, () => {
it('classifies wildcard bundle identifiers correctly', async () => {
expect(isWildcardBundleIdentifier('doge.doge.*')).toBe(true);
expect(isWildcardBundleIdentifier('doge*')).toBe(true);
expect(isWildcardBundleIdentifier('*')).toBe(false);
expect(isWildcardBundleIdentifier('*.doge')).toBe(false);
expect(isWildcardBundleIdentifier('doge')).toBe(false);
expect(isWildcardBundleIdentifier('doge.doge.doge')).toBe(false);
});
});
@@ -130,3 +130,8 @@ function _warnIfBundleIdentifierDefinedInAppConfigForGenericProject(
export const warnIfBundleIdentifierDefinedInAppConfigForGenericProject = once(
_warnIfBundleIdentifierDefinedInAppConfigForGenericProject
);
export function isWildcardBundleIdentifier(bundleIdentifier: string): boolean {
const wildcardRegex = /^[A-Za-z0-9.-]+\*$/;
return wildcardRegex.test(bundleIdentifier);
}
+1 -1
View File
@@ -56,7 +56,7 @@ export default class GitClient extends Client {
public async hasUncommittedChangesAsync(): Promise<boolean> {
const changes = await gitStatusAsync({ showUntracked: true });
return changes.length !== 0;
return changes.length > 0;
}
public async getRootPathAsync(): Promise<string> {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@expo/eas-json",
"description": "A library for interacting with the eas.json",
"version": "0.18.0",
"version": "0.18.2",
"author": "Expo <[email protected]>",
"bugs": "https://github.com/expo/eas-cli/issues",
"dependencies": {
+4 -2
View File
@@ -35,7 +35,7 @@ export interface AndroidGenericBuildProfile extends Android.BuilderEnvironment {
cache: Cache;
}
export interface IosManagedBuildProfile extends Ios.BuilderEnvironment {
export interface IosManagedBuildProfile extends Omit<Ios.BuilderEnvironment, 'image'> {
workflow: Workflow.MANAGED;
credentialsSource: CredentialsSource;
buildType?: Ios.ManagedBuildType;
@@ -45,9 +45,10 @@ export interface IosManagedBuildProfile extends Ios.BuilderEnvironment {
enterpriseProvisioning?: IosEnterpriseProvisioning;
autoIncrement: VersionAutoIncrement;
cache: Cache;
image?: Ios.BuilderEnvironment['image'];
}
export interface IosGenericBuildProfile extends Ios.BuilderEnvironment {
export interface IosGenericBuildProfile extends Omit<Ios.BuilderEnvironment, 'image'> {
workflow: Workflow.GENERIC;
credentialsSource: CredentialsSource;
scheme?: string;
@@ -59,6 +60,7 @@ export interface IosGenericBuildProfile extends Ios.BuilderEnvironment {
enterpriseProvisioning?: IosEnterpriseProvisioning;
autoIncrement: VersionAutoIncrement;
cache: Cache;
image?: Ios.BuilderEnvironment['image'];
}
export type AndroidBuildProfile = AndroidManagedBuildProfile | AndroidGenericBuildProfile;
+3 -7
View File
@@ -21,9 +21,7 @@ const AndroidBuilderEnvironmentSchema = Joi.object({
});
const IosBuilderEnvironmentSchema = Joi.object({
image: Joi.string()
.valid(...Ios.builderBaseImages)
.default('default'),
image: Joi.string().valid(...Ios.builderBaseImages),
node: Joi.string().empty(null).custom(semverSchemaCheck),
yarn: Joi.string().empty(null).custom(semverSchemaCheck),
bundler: Joi.string().empty(null).custom(semverSchemaCheck),
@@ -100,7 +98,7 @@ const IosManagedSchema = Joi.object({
cache: CacheSchema.default(),
}).concat(IosBuilderEnvironmentSchema);
const schemaBuildProfileMap: Record<string, Record<string, Joi.Schema>> = {
export const schemaBuildProfileMap: Record<string, Record<string, Joi.Schema>> = {
android: {
generic: AndroidGenericSchema,
managed: AndroidManagedSchema,
@@ -111,7 +109,7 @@ const schemaBuildProfileMap: Record<string, Record<string, Joi.Schema>> = {
},
};
const EasJsonSchema = Joi.object({
export const EasJsonSchema = Joi.object({
builds: Joi.object({
android: Joi.object().pattern(
Joi.string(),
@@ -127,5 +125,3 @@ const EasJsonSchema = Joi.object({
),
}),
});
export { EasJsonSchema, schemaBuildProfileMap };
@@ -56,7 +56,6 @@ test('minimal valid ios eas.json', async () => {
autoIncrement: false,
env: {},
cache: { disabled: false, cacheDefaultPaths: true, customPaths: [] },
image: 'default',
},
},
}).toEqual(easJson);
@@ -94,7 +93,6 @@ test('minimal valid eas.json for both platforms', async () => {
autoIncrement: false,
env: {},
cache: { disabled: false, cacheDefaultPaths: true, customPaths: [] },
image: 'default',
},
},
}).toEqual(easJson);
@@ -165,7 +163,6 @@ test('valid eas.json for development client builds', async () => {
distribution: 'store',
autoIncrement: false,
env: {},
image: 'default',
cache: { disabled: false, cacheDefaultPaths: true, customPaths: [] },
buildType: 'development-client',
},
-7
View File
@@ -1924,13 +1924,6 @@
dependencies:
"@hapi/joi" "^17.1.1"
"@expo/[email protected]":
version "0.2.37"
resolved "https://registry.yarnpkg.com/@expo/eas-build-job/-/eas-build-job-0.2.37.tgz#fd6cb911e33774239d1ab7662c0ccc8efa22f7a2"
integrity sha512-B9gahwTTYs0pWQP2HnfYWcbsqmUIAdnr+iwounVqpcxHhERxGJby2JEw+Vxtl2+VMARM4w9RLgNduP5Vk/zeQw==
dependencies:
"@hapi/joi" "^17.1.1"
"@expo/[email protected]":
version "0.3.14"
resolved "https://registry.yarnpkg.com/@expo/image-utils/-/image-utils-0.3.14.tgz#eea0d59c5845e8b19504011c20afd837c5d044c5"