eas-cli 0.35.0 → 0.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -26
- package/build/analytics/common.d.ts +8 -0
- package/build/analytics/common.js +19 -0
- package/build/analytics/events.d.ts +43 -0
- package/build/analytics/events.js +51 -0
- package/build/{analytics.d.ts → analytics/rudderstackClient.d.ts} +0 -0
- package/build/{analytics.js → analytics/rudderstackClient.js} +2 -2
- package/build/build/build.js +18 -27
- package/build/build/context.d.ts +1 -1
- package/build/build/context.js +2 -2
- package/build/build/ios/credentials.js +3 -3
- package/build/build/local.js +18 -27
- package/build/build/types.d.ts +0 -1
- package/build/commandUtils/EasCommand.js +4 -4
- package/build/commands/build/index.js +1 -1
- package/build/credentials/android/actions/RemoveFcm.js +4 -4
- package/build/credentials/android/utils/keystore.js +67 -32
- package/build/credentials/ios/actions/AscApiKeyUtils.js +8 -7
- package/build/credentials/ios/actions/AssignAscApiKey.js +1 -1
- package/build/credentials/ios/actions/CreateAscApiKey.js +2 -2
- package/build/credentials/ios/actions/RemoveAscApiKey.js +6 -6
- package/build/credentials/ios/actions/SetUpAscApiKey.js +8 -8
- package/build/credentials/ios/actions/SetUpSubmissionCredentials.js +3 -3
- package/build/credentials/ios/appstore/ascApiKey.js +12 -12
- package/build/credentials/ios/appstore/entitlements.d.ts +2 -2
- package/build/credentials/ios/appstore/entitlements.js +20 -10
- package/build/credentials/ios/credentials.js +2 -2
- package/build/credentials/ios/utils/printCredentials.js +1 -1
- package/build/credentials/manager/AndroidActions.js +3 -3
- package/build/credentials/manager/IosActions.js +5 -5
- package/build/credentials/manager/ManageIos.js +4 -4
- package/build/graphql/generated.d.ts +144 -53
- package/build/graphql/mutations/KeystoreGenerationUrlMutation.d.ts +3 -0
- package/build/graphql/mutations/KeystoreGenerationUrlMutation.js +23 -0
- package/build/submit/BaseSubmitter.d.ts +20 -4
- package/build/submit/BaseSubmitter.js +34 -1
- package/build/submit/android/AndroidSubmitter.d.ts +12 -6
- package/build/submit/android/AndroidSubmitter.js +31 -20
- package/build/submit/context.d.ts +2 -0
- package/build/submit/context.js +14 -0
- package/build/submit/ios/AppSpecificPasswordSource.d.ts +8 -1
- package/build/submit/ios/AppSpecificPasswordSource.js +44 -4
- package/build/submit/ios/CredentialsServiceSource.d.ts +3 -2
- package/build/submit/ios/CredentialsServiceSource.js +9 -3
- package/build/submit/ios/IosSubmitCommand.d.ts +1 -2
- package/build/submit/ios/IosSubmitCommand.js +2 -39
- package/build/submit/ios/IosSubmitter.d.ts +17 -7
- package/build/submit/ios/IosSubmitter.js +55 -29
- package/build/submit/submit.js +13 -4
- package/build/user/User.js +1 -1
- package/oclif.manifest.json +1 -1
- package/package.json +3 -3
- package/build/build/utils/analytics.d.ts +0 -22
- package/build/build/utils/analytics.js +0 -28
|
@@ -1,14 +1,39 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
|
+
const common_1 = require("../analytics/common");
|
|
5
|
+
const events_1 = require("../analytics/events");
|
|
4
6
|
const AppPlatform_1 = require("../graphql/types/AppPlatform");
|
|
5
7
|
const log_1 = (0, tslib_1.__importDefault)(require("../log"));
|
|
6
8
|
const ora_1 = require("../ora");
|
|
7
9
|
const platform_1 = require("../platform");
|
|
8
10
|
class BaseSubmitter {
|
|
9
|
-
constructor(ctx, options) {
|
|
11
|
+
constructor(ctx, options, sourceOptionResolver, sourceOptionAnalytics) {
|
|
10
12
|
this.ctx = ctx;
|
|
11
13
|
this.options = options;
|
|
14
|
+
this.sourceOptionResolver = sourceOptionResolver;
|
|
15
|
+
this.sourceOptionAnalytics = sourceOptionAnalytics;
|
|
16
|
+
}
|
|
17
|
+
async getSourceOptionsAsync() {
|
|
18
|
+
const resolvedSourceOptions = {};
|
|
19
|
+
// Do not perform this in parallel as some of these require user interaction
|
|
20
|
+
for (const key in this.sourceOptionResolver) {
|
|
21
|
+
const sourceOptionKey = key;
|
|
22
|
+
const sourceOptionAnalytics = this.sourceOptionAnalytics[sourceOptionKey];
|
|
23
|
+
const sourceOption = await (0, common_1.withAnalyticsAsync)(async () => await this.sourceOptionResolver[sourceOptionKey](), {
|
|
24
|
+
attemptEvent: sourceOptionAnalytics.attemptEvent,
|
|
25
|
+
successEvent: sourceOptionAnalytics.successEvent,
|
|
26
|
+
failureEvent: sourceOptionAnalytics.failureEvent,
|
|
27
|
+
trackingCtx: this.ctx.trackingCtx,
|
|
28
|
+
});
|
|
29
|
+
resolvedSourceOptions[sourceOptionKey] = sourceOption;
|
|
30
|
+
}
|
|
31
|
+
return resolvedSourceOptions;
|
|
32
|
+
}
|
|
33
|
+
async submitAsync() {
|
|
34
|
+
const resolvedSourceOptions = await this.getSourceOptionsAsync();
|
|
35
|
+
const input = await this.createSubmissionInputAsync(resolvedSourceOptions);
|
|
36
|
+
return await this.createSubmissionWithAnalyticsAsync(input);
|
|
12
37
|
}
|
|
13
38
|
async createSubmissionAsync(submissionInput) {
|
|
14
39
|
log_1.default.addNewLineIfNone();
|
|
@@ -24,5 +49,13 @@ class BaseSubmitter {
|
|
|
24
49
|
throw err;
|
|
25
50
|
}
|
|
26
51
|
}
|
|
52
|
+
async createSubmissionWithAnalyticsAsync(submissionInput) {
|
|
53
|
+
return await (0, common_1.withAnalyticsAsync)(async () => this.createSubmissionAsync(submissionInput), {
|
|
54
|
+
attemptEvent: events_1.SubmissionEvent.SUBMIT_REQUEST_ATTEMPT,
|
|
55
|
+
successEvent: events_1.SubmissionEvent.SUBMIT_REQUEST_SUCCESS,
|
|
56
|
+
failureEvent: events_1.SubmissionEvent.SUBMIT_REQUEST_FAIL,
|
|
57
|
+
trackingCtx: this.ctx.trackingCtx,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
27
60
|
}
|
|
28
61
|
exports.default = BaseSubmitter;
|
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
import { Platform } from '@expo/eas-build-job';
|
|
2
2
|
import { AndroidSubmissionConfigInput, SubmissionFragment } from '../../graphql/generated';
|
|
3
|
-
import { ArchiveSource } from '../ArchiveSource';
|
|
3
|
+
import { Archive, ArchiveSource } from '../ArchiveSource';
|
|
4
4
|
import BaseSubmitter, { SubmissionInput } from '../BaseSubmitter';
|
|
5
|
+
import { SubmissionContext } from '../context';
|
|
5
6
|
import { AndroidPackageSource } from './AndroidPackageSource';
|
|
6
|
-
import { ServiceAccountSource } from './ServiceAccountSource';
|
|
7
|
+
import { ServiceAccountKeyResult, ServiceAccountSource } from './ServiceAccountSource';
|
|
7
8
|
export interface AndroidSubmissionOptions extends Pick<AndroidSubmissionConfigInput, 'track' | 'releaseStatus' | 'changesNotSentForReview'> {
|
|
8
9
|
projectId: string;
|
|
9
10
|
androidPackageSource: AndroidPackageSource;
|
|
10
11
|
archiveSource: ArchiveSource;
|
|
11
12
|
serviceAccountSource: ServiceAccountSource;
|
|
12
13
|
}
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
interface ResolvedSourceOptions {
|
|
15
|
+
archive: Archive;
|
|
16
|
+
serviceAccountKeyResult: ServiceAccountKeyResult;
|
|
17
|
+
}
|
|
18
|
+
export default class AndroidSubmitter extends BaseSubmitter<Platform.ANDROID, ResolvedSourceOptions, AndroidSubmissionOptions> {
|
|
19
|
+
constructor(ctx: SubmissionContext<Platform.ANDROID>, options: AndroidSubmissionOptions);
|
|
20
|
+
createSubmissionInputAsync(resolvedSourceOptions: ResolvedSourceOptions): Promise<SubmissionInput<Platform.ANDROID>>;
|
|
15
21
|
protected createPlatformSubmissionAsync({ projectId, submissionConfig, buildId, }: SubmissionInput<Platform.ANDROID>): Promise<SubmissionFragment>;
|
|
16
|
-
private
|
|
17
|
-
private formatSubmissionConfigAsync;
|
|
22
|
+
private formatSubmissionConfig;
|
|
18
23
|
private prepareSummaryData;
|
|
19
24
|
}
|
|
25
|
+
export {};
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const chalk_1 = (0, tslib_1.__importDefault)(require("chalk"));
|
|
5
|
+
const events_1 = require("../../analytics/events");
|
|
5
6
|
const SubmissionMutation_1 = require("../../graphql/mutations/SubmissionMutation");
|
|
6
7
|
const formatFields_1 = (0, tslib_1.__importDefault)(require("../../utils/formatFields"));
|
|
7
8
|
const ArchiveSource_1 = require("../ArchiveSource");
|
|
@@ -10,16 +11,39 @@ const summary_1 = require("../utils/summary");
|
|
|
10
11
|
const AndroidPackageSource_1 = require("./AndroidPackageSource");
|
|
11
12
|
const ServiceAccountSource_1 = require("./ServiceAccountSource");
|
|
12
13
|
class AndroidSubmitter extends BaseSubmitter_1.default {
|
|
13
|
-
|
|
14
|
+
constructor(ctx, options) {
|
|
15
|
+
const sourceOptionsResolver = {
|
|
16
|
+
// eslint-disable-next-line async-protect/async-suffix
|
|
17
|
+
archive: async () => await (0, ArchiveSource_1.getArchiveAsync)(this.options.archiveSource),
|
|
18
|
+
// eslint-disable-next-line async-protect/async-suffix
|
|
19
|
+
serviceAccountKeyResult: async () => {
|
|
20
|
+
const androidPackage = await (0, AndroidPackageSource_1.getAndroidPackageAsync)(this.options.androidPackageSource);
|
|
21
|
+
return await (0, ServiceAccountSource_1.getServiceAccountKeyResultAsync)(this.ctx, this.options.serviceAccountSource, androidPackage);
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
const sourceOptionsAnalytics = {
|
|
25
|
+
archive: {
|
|
26
|
+
attemptEvent: events_1.SubmissionEvent.GATHER_ARCHIVE_ATTEMPT,
|
|
27
|
+
successEvent: events_1.SubmissionEvent.GATHER_ARCHIVE_SUCCESS,
|
|
28
|
+
failureEvent: events_1.SubmissionEvent.GATHER_ARCHIVE_FAIL,
|
|
29
|
+
},
|
|
30
|
+
serviceAccountKeyResult: {
|
|
31
|
+
attemptEvent: events_1.SubmissionEvent.GATHER_CREDENTIALS_ATTEMPT,
|
|
32
|
+
successEvent: events_1.SubmissionEvent.GATHER_CREDENTIALS_SUCCESS,
|
|
33
|
+
failureEvent: events_1.SubmissionEvent.GATHER_CREDENTIALS_FAIL,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
super(ctx, options, sourceOptionsResolver, sourceOptionsAnalytics);
|
|
37
|
+
}
|
|
38
|
+
async createSubmissionInputAsync(resolvedSourceOptions) {
|
|
14
39
|
var _a;
|
|
15
|
-
const
|
|
16
|
-
const submissionConfig = await this.formatSubmissionConfigAsync(this.options, resolvedSourceOptions);
|
|
40
|
+
const submissionConfig = await this.formatSubmissionConfig(this.options, resolvedSourceOptions);
|
|
17
41
|
(0, summary_1.printSummary)(this.prepareSummaryData(this.options, resolvedSourceOptions), SummaryHumanReadableKeys);
|
|
18
|
-
return
|
|
42
|
+
return {
|
|
19
43
|
projectId: this.options.projectId,
|
|
20
44
|
submissionConfig,
|
|
21
45
|
buildId: (_a = resolvedSourceOptions.archive.build) === null || _a === void 0 ? void 0 : _a.id,
|
|
22
|
-
}
|
|
46
|
+
};
|
|
23
47
|
}
|
|
24
48
|
async createPlatformSubmissionAsync({ projectId, submissionConfig, buildId, }) {
|
|
25
49
|
return await SubmissionMutation_1.SubmissionMutation.createAndroidSubmissionAsync({
|
|
@@ -28,20 +52,9 @@ class AndroidSubmitter extends BaseSubmitter_1.default {
|
|
|
28
52
|
submittedBuildId: buildId,
|
|
29
53
|
});
|
|
30
54
|
}
|
|
31
|
-
|
|
32
|
-
const androidPackage = await (0, AndroidPackageSource_1.getAndroidPackageAsync)(this.options.androidPackageSource);
|
|
33
|
-
const archive = await (0, ArchiveSource_1.getArchiveAsync)(this.options.archiveSource);
|
|
34
|
-
const serviceAccountKeyResult = await (0, ServiceAccountSource_1.getServiceAccountKeyResultAsync)(this.ctx, this.options.serviceAccountSource, androidPackage);
|
|
35
|
-
return {
|
|
36
|
-
androidPackage,
|
|
37
|
-
archive,
|
|
38
|
-
serviceAccountKeyResult,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
async formatSubmissionConfigAsync(options, { archive, androidPackage, serviceAccountKeyResult }) {
|
|
55
|
+
formatSubmissionConfig(options, { archive, serviceAccountKeyResult }) {
|
|
42
56
|
const { track, releaseStatus, changesNotSentForReview } = options;
|
|
43
57
|
return {
|
|
44
|
-
applicationIdentifier: androidPackage,
|
|
45
58
|
archiveUrl: archive.url,
|
|
46
59
|
track,
|
|
47
60
|
changesNotSentForReview,
|
|
@@ -49,12 +62,11 @@ class AndroidSubmitter extends BaseSubmitter_1.default {
|
|
|
49
62
|
...serviceAccountKeyResult.result,
|
|
50
63
|
};
|
|
51
64
|
}
|
|
52
|
-
prepareSummaryData(options, { archive,
|
|
65
|
+
prepareSummaryData(options, { archive, serviceAccountKeyResult }) {
|
|
53
66
|
const { projectId, track, releaseStatus, changesNotSentForReview } = options;
|
|
54
67
|
// structuring order affects table rows order
|
|
55
68
|
return {
|
|
56
69
|
projectId,
|
|
57
|
-
androidPackage,
|
|
58
70
|
track,
|
|
59
71
|
changesNotSentForReview: changesNotSentForReview !== null && changesNotSentForReview !== void 0 ? changesNotSentForReview : undefined,
|
|
60
72
|
releaseStatus: releaseStatus !== null && releaseStatus !== void 0 ? releaseStatus : undefined,
|
|
@@ -65,7 +77,6 @@ class AndroidSubmitter extends BaseSubmitter_1.default {
|
|
|
65
77
|
}
|
|
66
78
|
exports.default = AndroidSubmitter;
|
|
67
79
|
const SummaryHumanReadableKeys = {
|
|
68
|
-
androidPackage: 'Android package',
|
|
69
80
|
archivePath: 'Archive path',
|
|
70
81
|
archiveUrl: 'Download URL',
|
|
71
82
|
changesNotSentForReview: 'Changes not sent for a review',
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { ExpoConfig } from '@expo/config';
|
|
2
2
|
import { Platform } from '@expo/eas-build-job';
|
|
3
3
|
import { SubmitProfile } from '@expo/eas-json';
|
|
4
|
+
import { TrackingContext } from '../analytics/common';
|
|
4
5
|
import { CredentialsContext } from '../credentials/context';
|
|
5
6
|
import { Actor } from '../user/User';
|
|
6
7
|
export interface SubmissionContext<T extends Platform> {
|
|
7
8
|
accountName: string;
|
|
8
9
|
archiveFlags: SubmitArchiveFlags;
|
|
9
10
|
credentialsCtx: CredentialsContext;
|
|
11
|
+
trackingCtx: TrackingContext;
|
|
10
12
|
exp: ExpoConfig;
|
|
11
13
|
nonInteractive: boolean;
|
|
12
14
|
platform: T;
|
package/build/submit/context.js
CHANGED
|
@@ -1,21 +1,34 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createSubmissionContextAsync = void 0;
|
|
4
|
+
const uuid_1 = require("uuid");
|
|
5
|
+
const events_1 = require("../analytics/events");
|
|
4
6
|
const context_1 = require("../credentials/context");
|
|
5
7
|
const expoConfig_1 = require("../project/expoConfig");
|
|
6
8
|
const projectUtils_1 = require("../project/projectUtils");
|
|
9
|
+
const Account_1 = require("../user/Account");
|
|
7
10
|
const actions_1 = require("../user/actions");
|
|
8
11
|
async function createSubmissionContextAsync(params) {
|
|
12
|
+
var _a;
|
|
9
13
|
const { projectDir, nonInteractive } = params;
|
|
10
14
|
const exp = (0, expoConfig_1.getExpoConfig)(projectDir, { env: params.env });
|
|
11
15
|
const { env, ...rest } = params;
|
|
12
16
|
const user = await (0, actions_1.ensureLoggedInAsync)();
|
|
13
17
|
const projectName = exp.slug;
|
|
14
18
|
const accountName = (0, projectUtils_1.getProjectAccountName)(exp, user);
|
|
19
|
+
const accountId = (_a = (0, Account_1.findAccountByName)(user.accounts, accountName)) === null || _a === void 0 ? void 0 : _a.id;
|
|
15
20
|
let credentialsCtx = params.credentialsCtx;
|
|
16
21
|
if (!credentialsCtx) {
|
|
17
22
|
credentialsCtx = new context_1.CredentialsContext({ projectDir, user, exp, nonInteractive });
|
|
18
23
|
}
|
|
24
|
+
const trackingCtx = {
|
|
25
|
+
tracking_id: (0, uuid_1.v4)(),
|
|
26
|
+
platform: params.platform,
|
|
27
|
+
...(accountId && { account_id: accountId }),
|
|
28
|
+
account_name: accountName,
|
|
29
|
+
project_id: params.projectId,
|
|
30
|
+
};
|
|
31
|
+
events_1.Analytics.logEvent(events_1.SubmissionEvent.SUBMIT_COMMAND, trackingCtx);
|
|
19
32
|
return {
|
|
20
33
|
...rest,
|
|
21
34
|
accountName,
|
|
@@ -23,6 +36,7 @@ async function createSubmissionContextAsync(params) {
|
|
|
23
36
|
exp,
|
|
24
37
|
projectName,
|
|
25
38
|
user,
|
|
39
|
+
trackingCtx,
|
|
26
40
|
};
|
|
27
41
|
}
|
|
28
42
|
exports.createSubmissionContextAsync = createSubmissionContextAsync;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Platform } from '@expo/eas-build-job';
|
|
2
|
+
import { SubmissionContext } from '../context';
|
|
1
3
|
export declare enum AppSpecificPasswordSourceType {
|
|
2
4
|
userDefined = 0
|
|
3
5
|
}
|
|
@@ -8,6 +10,11 @@ interface AppSpecificPasswordUserDefinedSource extends AppSpecificPasswordSource
|
|
|
8
10
|
sourceType: AppSpecificPasswordSourceType.userDefined;
|
|
9
11
|
appSpecificPassword: string;
|
|
10
12
|
}
|
|
13
|
+
export interface AppSpecificPasswordCredentials {
|
|
14
|
+
password: string;
|
|
15
|
+
appleIdUsername: string;
|
|
16
|
+
}
|
|
11
17
|
export declare type AppSpecificPasswordSource = AppSpecificPasswordUserDefinedSource;
|
|
12
|
-
export declare function
|
|
18
|
+
export declare function getAppSpecificPasswordLocallyAsync(ctx: SubmissionContext<Platform.IOS>, source: AppSpecificPasswordSource): Promise<AppSpecificPasswordCredentials>;
|
|
19
|
+
export declare function getAppleIdUsernameAsync(ctx: SubmissionContext<Platform.IOS>): Promise<string>;
|
|
13
20
|
export {};
|
|
@@ -1,18 +1,58 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.getAppleIdUsernameAsync = exports.getAppSpecificPasswordLocallyAsync = exports.AppSpecificPasswordSourceType = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const getenv_1 = (0, tslib_1.__importDefault)(require("getenv"));
|
|
6
|
+
const prompts_1 = require("../../prompts");
|
|
7
|
+
const UserSettings_1 = (0, tslib_1.__importDefault)(require("../../user/UserSettings"));
|
|
4
8
|
var AppSpecificPasswordSourceType;
|
|
5
9
|
(function (AppSpecificPasswordSourceType) {
|
|
6
10
|
AppSpecificPasswordSourceType[AppSpecificPasswordSourceType["userDefined"] = 0] = "userDefined";
|
|
7
11
|
})(AppSpecificPasswordSourceType = exports.AppSpecificPasswordSourceType || (exports.AppSpecificPasswordSourceType = {}));
|
|
8
|
-
async function
|
|
12
|
+
async function getAppSpecificPasswordLocallyAsync(ctx, source) {
|
|
9
13
|
var _a;
|
|
10
14
|
if (source.sourceType === AppSpecificPasswordSourceType.userDefined) {
|
|
11
|
-
return
|
|
15
|
+
return {
|
|
16
|
+
password: source.appSpecificPassword,
|
|
17
|
+
appleIdUsername: await getAppleIdUsernameAsync(ctx),
|
|
18
|
+
};
|
|
12
19
|
}
|
|
13
20
|
else {
|
|
14
21
|
// exhaustive -- should never happen
|
|
15
22
|
throw new Error(`Unknown app specific password source type "${(_a = source) === null || _a === void 0 ? void 0 : _a.sourceType}"`);
|
|
16
23
|
}
|
|
17
24
|
}
|
|
18
|
-
exports.
|
|
25
|
+
exports.getAppSpecificPasswordLocallyAsync = getAppSpecificPasswordLocallyAsync;
|
|
26
|
+
async function getAppleIdUsernameAsync(ctx) {
|
|
27
|
+
var _a;
|
|
28
|
+
if (ctx.profile.appleId) {
|
|
29
|
+
return ctx.profile.appleId;
|
|
30
|
+
}
|
|
31
|
+
const envAppleId = getenv_1.default.string('EXPO_APPLE_ID', '');
|
|
32
|
+
if (envAppleId) {
|
|
33
|
+
return envAppleId;
|
|
34
|
+
}
|
|
35
|
+
if ((_a = ctx.credentialsCtx.appStore.authCtx) === null || _a === void 0 ? void 0 : _a.appleId) {
|
|
36
|
+
return ctx.credentialsCtx.appStore.authCtx.appleId;
|
|
37
|
+
}
|
|
38
|
+
// Get the email address that was last used and set it as
|
|
39
|
+
// the default value for quicker authentication.
|
|
40
|
+
const lastAppleId = await UserSettings_1.default.getAsync('appleId', null);
|
|
41
|
+
if (ctx.nonInteractive) {
|
|
42
|
+
if (lastAppleId) {
|
|
43
|
+
return lastAppleId;
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
throw new Error('Set appleId in the submit profile (eas.json).');
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const { appleId } = await (0, prompts_1.promptAsync)({
|
|
50
|
+
type: 'text',
|
|
51
|
+
name: 'appleId',
|
|
52
|
+
message: `Enter your Apple ID:`,
|
|
53
|
+
validate: (val) => !!val,
|
|
54
|
+
initial: lastAppleId !== null && lastAppleId !== void 0 ? lastAppleId : undefined,
|
|
55
|
+
});
|
|
56
|
+
return appleId;
|
|
57
|
+
}
|
|
58
|
+
exports.getAppleIdUsernameAsync = getAppleIdUsernameAsync;
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { Platform } from '@expo/eas-build-job';
|
|
2
2
|
import { SubmissionContext } from '../context';
|
|
3
|
+
import { AppSpecificPasswordCredentials } from './AppSpecificPasswordSource';
|
|
3
4
|
import { AscApiKeyResult } from './AscApiKeySource';
|
|
4
5
|
/**
|
|
5
|
-
* The Credentials Service will either return an ASC
|
|
6
|
+
* The Credentials Service will either return an ASC API Key or an App Specific Password
|
|
6
7
|
* When we no longer support the App Specific Password user prompt, refactor this into the AscApiKeySource
|
|
7
8
|
*/
|
|
8
9
|
export declare const CREDENTIALS_SERVICE_SOURCE = "CREDENTIALS_SERVICE_SOURCE";
|
|
9
10
|
export declare type CredentialsServiceSource = typeof CREDENTIALS_SERVICE_SOURCE;
|
|
10
11
|
export declare function getFromCredentialsServiceAsync(ctx: SubmissionContext<Platform.IOS>): Promise<{
|
|
11
|
-
appSpecificPassword:
|
|
12
|
+
appSpecificPassword: AppSpecificPasswordCredentials;
|
|
12
13
|
} | {
|
|
13
14
|
ascApiKeyResult: AscApiKeyResult;
|
|
14
15
|
}>;
|
|
@@ -7,8 +7,9 @@ const SetUpSubmissionCredentials_1 = require("../../credentials/ios/actions/SetU
|
|
|
7
7
|
const log_1 = (0, tslib_1.__importDefault)(require("../../log"));
|
|
8
8
|
const bundleIdentifier_1 = require("../../project/ios/bundleIdentifier");
|
|
9
9
|
const Account_1 = require("../../user/Account");
|
|
10
|
+
const AppSpecificPasswordSource_1 = require("./AppSpecificPasswordSource");
|
|
10
11
|
/**
|
|
11
|
-
* The Credentials Service will either return an ASC
|
|
12
|
+
* The Credentials Service will either return an ASC API Key or an App Specific Password
|
|
12
13
|
* When we no longer support the App Specific Password user prompt, refactor this into the AscApiKeySource
|
|
13
14
|
*/
|
|
14
15
|
exports.CREDENTIALS_SERVICE_SOURCE = 'CREDENTIALS_SERVICE_SOURCE';
|
|
@@ -24,10 +25,15 @@ async function getFromCredentialsServiceAsync(ctx) {
|
|
|
24
25
|
const ascOrAsp = await setupSubmissionCredentialsAction.runAsync(ctx.credentialsCtx);
|
|
25
26
|
const isAppSpecificPassword = typeof ascOrAsp === 'string';
|
|
26
27
|
if (isAppSpecificPassword) {
|
|
27
|
-
return {
|
|
28
|
+
return {
|
|
29
|
+
appSpecificPassword: {
|
|
30
|
+
password: ascOrAsp,
|
|
31
|
+
appleIdUsername: await (0, AppSpecificPasswordSource_1.getAppleIdUsernameAsync)(ctx),
|
|
32
|
+
},
|
|
33
|
+
};
|
|
28
34
|
}
|
|
29
35
|
else {
|
|
30
|
-
const ascKeyForSubmissions = (0, nullthrows_1.default)(ascOrAsp.appStoreConnectApiKeyForSubmissions, `An EAS Submit ASC
|
|
36
|
+
const ascKeyForSubmissions = (0, nullthrows_1.default)(ascOrAsp.appStoreConnectApiKeyForSubmissions, `An EAS Submit ASC API Key could not be found for ${ascOrAsp.appleAppIdentifier.bundleIdentifier}`);
|
|
31
37
|
const { id, keyIdentifier, name } = ascKeyForSubmissions;
|
|
32
38
|
return {
|
|
33
39
|
ascApiKeyResult: {
|
|
@@ -5,11 +5,10 @@ export default class IosSubmitCommand {
|
|
|
5
5
|
private ctx;
|
|
6
6
|
constructor(ctx: SubmissionContext<Platform.IOS>);
|
|
7
7
|
runAsync(): Promise<SubmissionFragment>;
|
|
8
|
-
private
|
|
8
|
+
private resolveCredentialSubmissionOptions;
|
|
9
9
|
private resolveSubmissionOptionsAsync;
|
|
10
10
|
private resolveAppSpecificPasswordSource;
|
|
11
11
|
private resolveAscApiKeySource;
|
|
12
12
|
private resolveArchiveSource;
|
|
13
13
|
private resolveAscAppIdentifierAsync;
|
|
14
|
-
private resolveAppleIdUsernameAsync;
|
|
15
14
|
}
|
|
@@ -8,8 +8,6 @@ const getenv_1 = (0, tslib_1.__importDefault)(require("getenv"));
|
|
|
8
8
|
const wrap_ansi_1 = (0, tslib_1.__importDefault)(require("wrap-ansi"));
|
|
9
9
|
const errors_1 = require("../../credentials/errors");
|
|
10
10
|
const log_1 = (0, tslib_1.__importStar)(require("../../log"));
|
|
11
|
-
const prompts_1 = require("../../prompts");
|
|
12
|
-
const UserSettings_1 = (0, tslib_1.__importDefault)(require("../../user/UserSettings"));
|
|
13
11
|
const commons_1 = require("../commons");
|
|
14
12
|
const AppProduce_1 = require("./AppProduce");
|
|
15
13
|
const AppSpecificPasswordSource_1 = require("./AppSpecificPasswordSource");
|
|
@@ -26,7 +24,7 @@ class IosSubmitCommand {
|
|
|
26
24
|
const submitter = new IosSubmitter_1.default(this.ctx, options);
|
|
27
25
|
return await submitter.submitAsync();
|
|
28
26
|
}
|
|
29
|
-
|
|
27
|
+
resolveCredentialSubmissionOptions() {
|
|
30
28
|
const ascApiKeySource = this.resolveAscApiKeySource();
|
|
31
29
|
const shouldSkipAscApiKeySource = !ascApiKeySource.ok && ascApiKeySource.enforceError() instanceof errors_1.MissingCredentialsError;
|
|
32
30
|
if (!shouldSkipAscApiKeySource) {
|
|
@@ -44,7 +42,7 @@ class IosSubmitCommand {
|
|
|
44
42
|
}
|
|
45
43
|
async resolveSubmissionOptionsAsync() {
|
|
46
44
|
const archiveSource = this.resolveArchiveSource();
|
|
47
|
-
const credentialsSource =
|
|
45
|
+
const credentialsSource = this.resolveCredentialSubmissionOptions();
|
|
48
46
|
const maybeAppSpecificPasswordSource = 'appSpecificPasswordSource' in credentialsSource
|
|
49
47
|
? credentialsSource.appSpecificPasswordSource
|
|
50
48
|
: null;
|
|
@@ -53,14 +51,12 @@ class IosSubmitCommand {
|
|
|
53
51
|
? credentialsSource.credentialsServiceSource
|
|
54
52
|
: null;
|
|
55
53
|
const ascAppIdentifier = await this.resolveAscAppIdentifierAsync();
|
|
56
|
-
const appleIdUsername = await this.resolveAppleIdUsernameAsync();
|
|
57
54
|
const errored = [
|
|
58
55
|
archiveSource,
|
|
59
56
|
...(maybeAppSpecificPasswordSource ? [maybeAppSpecificPasswordSource] : []),
|
|
60
57
|
...(maybeAscApiKeySource ? [maybeAscApiKeySource] : []),
|
|
61
58
|
...(maybeCredentialsServiceSource ? [maybeCredentialsServiceSource] : []),
|
|
62
59
|
ascAppIdentifier,
|
|
63
|
-
appleIdUsername,
|
|
64
60
|
].filter(r => !r.ok);
|
|
65
61
|
if (errored.length > 0) {
|
|
66
62
|
const message = errored.map(err => { var _a; return (_a = err.reason) === null || _a === void 0 ? void 0 : _a.message; }).join('\n');
|
|
@@ -69,7 +65,6 @@ class IosSubmitCommand {
|
|
|
69
65
|
}
|
|
70
66
|
return {
|
|
71
67
|
projectId: this.ctx.projectId,
|
|
72
|
-
appleIdUsername: appleIdUsername.enforceValue(),
|
|
73
68
|
ascAppIdentifier: ascAppIdentifier.enforceValue(),
|
|
74
69
|
archiveSource: archiveSource.enforceValue(),
|
|
75
70
|
...(maybeAppSpecificPasswordSource
|
|
@@ -148,37 +143,5 @@ class IosSubmitCommand {
|
|
|
148
143
|
}
|
|
149
144
|
}
|
|
150
145
|
}
|
|
151
|
-
async resolveAppleIdUsernameAsync() {
|
|
152
|
-
var _a;
|
|
153
|
-
if (this.ctx.profile.appleId) {
|
|
154
|
-
return (0, results_1.result)(this.ctx.profile.appleId);
|
|
155
|
-
}
|
|
156
|
-
const envAppleId = getenv_1.default.string('EXPO_APPLE_ID', '');
|
|
157
|
-
if (envAppleId) {
|
|
158
|
-
return (0, results_1.result)(envAppleId);
|
|
159
|
-
}
|
|
160
|
-
if ((_a = this.ctx.credentialsCtx.appStore.authCtx) === null || _a === void 0 ? void 0 : _a.appleId) {
|
|
161
|
-
return (0, results_1.result)(this.ctx.credentialsCtx.appStore.authCtx.appleId);
|
|
162
|
-
}
|
|
163
|
-
// Get the email address that was last used and set it as
|
|
164
|
-
// the default value for quicker authentication.
|
|
165
|
-
const lastAppleId = await UserSettings_1.default.getAsync('appleId', null);
|
|
166
|
-
if (this.ctx.nonInteractive) {
|
|
167
|
-
if (lastAppleId) {
|
|
168
|
-
return (0, results_1.result)(lastAppleId);
|
|
169
|
-
}
|
|
170
|
-
else {
|
|
171
|
-
return (0, results_1.result)(new Error('Set appleId in the submit profile (eas.json).'));
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
const { appleId } = await (0, prompts_1.promptAsync)({
|
|
175
|
-
type: 'text',
|
|
176
|
-
name: 'appleId',
|
|
177
|
-
message: `Enter your Apple ID:`,
|
|
178
|
-
validate: (val) => !!val,
|
|
179
|
-
initial: lastAppleId !== null && lastAppleId !== void 0 ? lastAppleId : undefined,
|
|
180
|
-
});
|
|
181
|
-
return (0, results_1.result)(appleId);
|
|
182
|
-
}
|
|
183
146
|
}
|
|
184
147
|
exports.default = IosSubmitCommand;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Platform } from '@expo/eas-build-job';
|
|
2
2
|
import { IosSubmissionConfigInput, SubmissionFragment } from '../../graphql/generated';
|
|
3
|
-
import { ArchiveSource } from '../ArchiveSource';
|
|
3
|
+
import { Archive, ArchiveSource } from '../ArchiveSource';
|
|
4
4
|
import BaseSubmitter, { SubmissionInput } from '../BaseSubmitter';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { SubmissionContext } from '../context';
|
|
6
|
+
import { AppSpecificPasswordCredentials, AppSpecificPasswordSource } from './AppSpecificPasswordSource';
|
|
7
|
+
import { AscApiKeyResult, AscApiKeySource } from './AscApiKeySource';
|
|
7
8
|
import { CredentialsServiceSource } from './CredentialsServiceSource';
|
|
8
9
|
export interface IosSubmissionOptions extends Pick<IosSubmissionConfigInput, 'appleIdUsername' | 'ascAppIdentifier'> {
|
|
9
10
|
projectId: string;
|
|
@@ -12,11 +13,20 @@ export interface IosSubmissionOptions extends Pick<IosSubmissionConfigInput, 'ap
|
|
|
12
13
|
ascApiKeySource?: AscApiKeySource;
|
|
13
14
|
credentialsServiceSource?: CredentialsServiceSource;
|
|
14
15
|
}
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
interface ResolvedSourceOptions {
|
|
17
|
+
archive: Archive;
|
|
18
|
+
credentials: {
|
|
19
|
+
appSpecificPassword?: AppSpecificPasswordCredentials;
|
|
20
|
+
ascApiKeyResult?: AscApiKeyResult;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export default class IosSubmitter extends BaseSubmitter<Platform.IOS, ResolvedSourceOptions, IosSubmissionOptions> {
|
|
24
|
+
constructor(ctx: SubmissionContext<Platform.IOS>, options: IosSubmissionOptions);
|
|
25
|
+
createSubmissionInputAsync(resolvedSourceOptions: ResolvedSourceOptions): Promise<SubmissionInput<Platform.IOS>>;
|
|
17
26
|
protected createPlatformSubmissionAsync({ projectId, submissionConfig, buildId, }: SubmissionInput<Platform.IOS>): Promise<SubmissionFragment>;
|
|
18
|
-
private
|
|
19
|
-
private
|
|
27
|
+
private formatSubmissionConfig;
|
|
28
|
+
private formatAppSpecificPassword;
|
|
20
29
|
private formatAscApiKeyResult;
|
|
21
30
|
private prepareSummaryData;
|
|
22
31
|
}
|
|
32
|
+
export {};
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const chalk_1 = (0, tslib_1.__importDefault)(require("chalk"));
|
|
5
|
+
const events_1 = require("../../analytics/events");
|
|
5
6
|
const SubmissionMutation_1 = require("../../graphql/mutations/SubmissionMutation");
|
|
6
7
|
const formatFields_1 = (0, tslib_1.__importDefault)(require("../../utils/formatFields"));
|
|
7
8
|
const ArchiveSource_1 = require("../ArchiveSource");
|
|
@@ -11,16 +12,51 @@ const AppSpecificPasswordSource_1 = require("./AppSpecificPasswordSource");
|
|
|
11
12
|
const AscApiKeySource_1 = require("./AscApiKeySource");
|
|
12
13
|
const CredentialsServiceSource_1 = require("./CredentialsServiceSource");
|
|
13
14
|
class IosSubmitter extends BaseSubmitter_1.default {
|
|
14
|
-
|
|
15
|
+
constructor(ctx, options) {
|
|
16
|
+
const sourceOptionsResolver = {
|
|
17
|
+
// eslint-disable-next-line async-protect/async-suffix
|
|
18
|
+
archive: async () => await (0, ArchiveSource_1.getArchiveAsync)(this.options.archiveSource),
|
|
19
|
+
// eslint-disable-next-line async-protect/async-suffix
|
|
20
|
+
credentials: async () => {
|
|
21
|
+
const maybeAppSpecificPassword = this.options.appSpecificPasswordSource
|
|
22
|
+
? await (0, AppSpecificPasswordSource_1.getAppSpecificPasswordLocallyAsync)(this.ctx, this.options.appSpecificPasswordSource)
|
|
23
|
+
: null;
|
|
24
|
+
const maybeAppStoreConnectApiKey = this.options.ascApiKeySource
|
|
25
|
+
? await (0, AscApiKeySource_1.getAscApiKeyLocallyAsync)(this.ctx, this.options.ascApiKeySource)
|
|
26
|
+
: null;
|
|
27
|
+
const maybeAscOrAspFromCredentialsService = this.options.credentialsServiceSource
|
|
28
|
+
? await (0, CredentialsServiceSource_1.getFromCredentialsServiceAsync)(this.ctx)
|
|
29
|
+
: null;
|
|
30
|
+
return {
|
|
31
|
+
...(maybeAppSpecificPassword ? { appSpecificPassword: maybeAppSpecificPassword } : null),
|
|
32
|
+
...(maybeAppStoreConnectApiKey ? { ascApiKeyResult: maybeAppStoreConnectApiKey } : null),
|
|
33
|
+
...(maybeAscOrAspFromCredentialsService ? maybeAscOrAspFromCredentialsService : null),
|
|
34
|
+
};
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
const sourceOptionsAnalytics = {
|
|
38
|
+
archive: {
|
|
39
|
+
attemptEvent: events_1.SubmissionEvent.GATHER_ARCHIVE_ATTEMPT,
|
|
40
|
+
successEvent: events_1.SubmissionEvent.GATHER_ARCHIVE_SUCCESS,
|
|
41
|
+
failureEvent: events_1.SubmissionEvent.GATHER_ARCHIVE_FAIL,
|
|
42
|
+
},
|
|
43
|
+
credentials: {
|
|
44
|
+
attemptEvent: events_1.SubmissionEvent.GATHER_CREDENTIALS_ATTEMPT,
|
|
45
|
+
successEvent: events_1.SubmissionEvent.GATHER_CREDENTIALS_SUCCESS,
|
|
46
|
+
failureEvent: events_1.SubmissionEvent.GATHER_CREDENTIALS_FAIL,
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
super(ctx, options, sourceOptionsResolver, sourceOptionsAnalytics);
|
|
50
|
+
}
|
|
51
|
+
async createSubmissionInputAsync(resolvedSourceOptions) {
|
|
15
52
|
var _a;
|
|
16
|
-
const
|
|
17
|
-
const submissionConfig = await this.formatSubmissionConfigAsync(this.options, resolvedSourceOptions);
|
|
53
|
+
const submissionConfig = this.formatSubmissionConfig(this.options, resolvedSourceOptions);
|
|
18
54
|
(0, summary_1.printSummary)(this.prepareSummaryData(this.options, resolvedSourceOptions), SummaryHumanReadableKeys);
|
|
19
|
-
return
|
|
55
|
+
return {
|
|
20
56
|
projectId: this.options.projectId,
|
|
21
57
|
submissionConfig,
|
|
22
58
|
buildId: (_a = resolvedSourceOptions.archive.build) === null || _a === void 0 ? void 0 : _a.id,
|
|
23
|
-
}
|
|
59
|
+
};
|
|
24
60
|
}
|
|
25
61
|
async createPlatformSubmissionAsync({ projectId, submissionConfig, buildId, }) {
|
|
26
62
|
return await SubmissionMutation_1.SubmissionMutation.createIosSubmissionAsync({
|
|
@@ -29,34 +65,23 @@ class IosSubmitter extends BaseSubmitter_1.default {
|
|
|
29
65
|
submittedBuildId: buildId,
|
|
30
66
|
});
|
|
31
67
|
}
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
const maybeAppSpecificPassword = this.options.appSpecificPasswordSource
|
|
35
|
-
? await (0, AppSpecificPasswordSource_1.getAppSpecificPasswordAsync)(this.options.appSpecificPasswordSource)
|
|
36
|
-
: null;
|
|
37
|
-
const maybeAppStoreConnectApiKey = this.options.ascApiKeySource
|
|
38
|
-
? await (0, AscApiKeySource_1.getAscApiKeyLocallyAsync)(this.ctx, this.options.ascApiKeySource)
|
|
39
|
-
: null;
|
|
40
|
-
const maybeAscOrAspFromCredentialsService = this.options.credentialsServiceSource
|
|
41
|
-
? await (0, CredentialsServiceSource_1.getFromCredentialsServiceAsync)(this.ctx)
|
|
42
|
-
: null;
|
|
43
|
-
return {
|
|
44
|
-
archive,
|
|
45
|
-
...(maybeAppSpecificPassword ? { appSpecificPassword: maybeAppSpecificPassword } : null),
|
|
46
|
-
...(maybeAppStoreConnectApiKey ? { ascApiKeyResult: maybeAppStoreConnectApiKey } : null),
|
|
47
|
-
...(maybeAscOrAspFromCredentialsService ? maybeAscOrAspFromCredentialsService : null),
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
async formatSubmissionConfigAsync(options, { archive, appSpecificPassword, ascApiKeyResult }) {
|
|
68
|
+
formatSubmissionConfig(options, { archive, credentials }) {
|
|
69
|
+
const { appSpecificPassword, ascApiKeyResult } = credentials;
|
|
51
70
|
const { appleIdUsername, ascAppIdentifier } = options;
|
|
52
71
|
return {
|
|
53
72
|
ascAppIdentifier,
|
|
54
73
|
appleIdUsername,
|
|
55
74
|
archiveUrl: archive.url,
|
|
56
|
-
|
|
75
|
+
...(appSpecificPassword ? this.formatAppSpecificPassword(appSpecificPassword) : null),
|
|
57
76
|
...((ascApiKeyResult === null || ascApiKeyResult === void 0 ? void 0 : ascApiKeyResult.result) ? this.formatAscApiKeyResult(ascApiKeyResult.result) : null),
|
|
58
77
|
};
|
|
59
78
|
}
|
|
79
|
+
formatAppSpecificPassword(appSpecificPassword) {
|
|
80
|
+
return {
|
|
81
|
+
appleAppSpecificPassword: appSpecificPassword.password,
|
|
82
|
+
appleIdUsername: appSpecificPassword.appleIdUsername,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
60
85
|
formatAscApiKeyResult(result) {
|
|
61
86
|
return 'ascApiKeyId' in result
|
|
62
87
|
? { ascApiKeyId: result.ascApiKeyId }
|
|
@@ -68,13 +93,14 @@ class IosSubmitter extends BaseSubmitter_1.default {
|
|
|
68
93
|
},
|
|
69
94
|
};
|
|
70
95
|
}
|
|
71
|
-
prepareSummaryData(options, { archive,
|
|
72
|
-
const {
|
|
96
|
+
prepareSummaryData(options, { archive, credentials }) {
|
|
97
|
+
const { ascApiKeyResult, appSpecificPassword } = credentials;
|
|
98
|
+
const { ascAppIdentifier, projectId } = options;
|
|
73
99
|
// structuring order affects table rows order
|
|
74
100
|
return {
|
|
75
101
|
ascAppIdentifier,
|
|
76
|
-
appleIdUsername: appleIdUsername !== null && appleIdUsername !== void 0 ? appleIdUsername : undefined,
|
|
77
102
|
projectId,
|
|
103
|
+
...(appSpecificPassword ? { appleIdUsername: appSpecificPassword.appleIdUsername } : null),
|
|
78
104
|
...(ascApiKeyResult ? { formattedAscApiKey: formatAscApiKeySummary(ascApiKeyResult) } : null),
|
|
79
105
|
...(0, summary_1.formatArchiveSourceSummary)(archive),
|
|
80
106
|
};
|
|
@@ -88,7 +114,7 @@ const SummaryHumanReadableKeys = {
|
|
|
88
114
|
archiveUrl: 'Archive URL',
|
|
89
115
|
archivePath: 'Archive Path',
|
|
90
116
|
formattedBuild: 'Build',
|
|
91
|
-
formattedAscApiKey: 'App Store Connect
|
|
117
|
+
formattedAscApiKey: 'App Store Connect API Key',
|
|
92
118
|
};
|
|
93
119
|
function formatAscApiKeySummary({ summary }) {
|
|
94
120
|
const { source, path, keyId, name } = summary;
|