eas-cli
Version:
EAS command line tool
157 lines (156 loc) • 7.62 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const eas_build_job_1 = require("@expo/eas-build-job");
const results_1 = require("@expo/results");
const chalk_1 = tslib_1.__importDefault(require("chalk"));
const getenv_1 = tslib_1.__importDefault(require("getenv"));
const wrap_ansi_1 = tslib_1.__importDefault(require("wrap-ansi"));
const AppProduce_1 = require("./AppProduce");
const AppSpecificPasswordSource_1 = require("./AppSpecificPasswordSource");
const AscApiKeySource_1 = require("./AscApiKeySource");
const IosSubmitter_1 = tslib_1.__importDefault(require("./IosSubmitter"));
const errors_1 = require("../../credentials/errors");
const log_1 = tslib_1.__importStar(require("../../log"));
const ArchiveSource_1 = require("../ArchiveSource");
const commons_1 = require("../commons");
class IosSubmitCommand {
ctx;
constructor(ctx) {
this.ctx = ctx;
}
async runAsync() {
log_1.default.addNewLineIfNone();
const archiveSource = this.resolveArchiveSource();
if (!archiveSource.ok) {
log_1.default.error(archiveSource.reason?.message);
throw new Error('Submission failed');
}
const archiveSourceValue = archiveSource.enforceValue();
const archive = await (0, ArchiveSource_1.getArchiveAsync)({
graphqlClient: this.ctx.graphqlClient,
platform: eas_build_job_1.Platform.IOS,
projectId: this.ctx.projectId,
nonInteractive: this.ctx.nonInteractive,
}, archiveSourceValue);
const archiveProfile = archive.sourceType === ArchiveSource_1.ArchiveSourceType.build ? archive.build.buildProfile : undefined;
if (archiveProfile && !this.ctx.specifiedProfile) {
this.ctx = await (0, commons_1.refreshContextSubmitProfileAsync)(this.ctx, archiveProfile);
}
const options = await this.resolveSubmissionOptionsAsync(archiveSourceValue);
const submitter = new IosSubmitter_1.default(this.ctx, options, archive);
return submitter;
}
async resolveSubmissionOptionsAsync(archiveSource) {
const credentialsSource = await this.resolveCredentialSubmissionOptionsAsync();
const maybeAppSpecificPasswordSource = 'appSpecificPasswordSource' in credentialsSource
? credentialsSource.appSpecificPasswordSource
: null;
const maybeAscApiKeySource = 'ascApiKeySource' in credentialsSource ? credentialsSource.ascApiKeySource : null;
const ascAppIdentifier = await this.resolveAscAppIdentifierAsync();
const errored = [
...(maybeAppSpecificPasswordSource ? [maybeAppSpecificPasswordSource] : []),
...(maybeAscApiKeySource ? [maybeAscApiKeySource] : []),
ascAppIdentifier,
].filter(r => !r.ok);
if (errored.length > 0) {
const message = errored.map(err => err.reason?.message).join('\n');
log_1.default.error(message);
throw new Error('Submission failed');
}
return {
projectId: this.ctx.projectId,
ascAppIdentifier: ascAppIdentifier.enforceValue(),
archiveSource,
...(maybeAppSpecificPasswordSource
? {
appSpecificPasswordSource: maybeAppSpecificPasswordSource.enforceValue(),
}
: null),
...(maybeAscApiKeySource
? {
ascApiKeySource: maybeAscApiKeySource.enforceValue(),
}
: null),
};
}
async resolveCredentialSubmissionOptionsAsync() {
// if an App Specific Password env var is not specified, use ASC Api Key
const appSpecificPasswordSource = this.resolveAppSpecificPasswordSource();
const shouldSkipAppSpecificPasswordSource = !appSpecificPasswordSource.ok &&
appSpecificPasswordSource.enforceError() instanceof errors_1.MissingCredentialsError;
if (!shouldSkipAppSpecificPasswordSource) {
return { appSpecificPasswordSource: this.resolveAppSpecificPasswordSource() };
}
const ascApiKeySource = this.resolveAscApiKeySource();
return { ascApiKeySource };
}
resolveAppSpecificPasswordSource() {
const envAppSpecificPassword = getenv_1.default.string('EXPO_APPLE_APP_SPECIFIC_PASSWORD', '');
if (envAppSpecificPassword) {
if (!/^[a-z]{4}-[a-z]{4}-[a-z]{4}-[a-z]{4}$/.test(envAppSpecificPassword)) {
throw new Error('EXPO_APPLE_APP_SPECIFIC_PASSWORD must be in the format xxxx-xxxx-xxxx-xxxx, where x is a lowercase letter.');
}
return (0, results_1.result)({
sourceType: AppSpecificPasswordSource_1.AppSpecificPasswordSourceType.userDefined,
appSpecificPassword: envAppSpecificPassword,
});
}
return (0, results_1.result)(new errors_1.MissingCredentialsError('The EXPO_APPLE_APP_SPECIFIC_PASSWORD environment variable must be set.'));
}
resolveAscApiKeySource() {
const { ascApiKeyPath, ascApiKeyIssuerId, ascApiKeyId } = this.ctx.profile;
if (ascApiKeyPath && ascApiKeyIssuerId && ascApiKeyId) {
return (0, results_1.result)({
sourceType: AscApiKeySource_1.AscApiKeySourceType.path,
path: {
keyP8Path: ascApiKeyPath,
issuerId: ascApiKeyIssuerId,
keyId: ascApiKeyId,
},
});
}
// interpret this to mean the user had some intention of passing in ASC Api key
if (ascApiKeyPath || ascApiKeyIssuerId || ascApiKeyId) {
const message = `ascApiKeyPath, ascApiKeyIssuerId and ascApiKeyId must all be defined in eas.json`;
// in non-interactive mode, we should fail
if (this.ctx.nonInteractive) {
throw new Error(message);
}
log_1.default.warn(message);
return (0, results_1.result)({
sourceType: AscApiKeySource_1.AscApiKeySourceType.prompt,
});
}
return (0, results_1.result)({ sourceType: AscApiKeySource_1.AscApiKeySourceType.credentialsService });
}
resolveArchiveSource() {
try {
return (0, results_1.result)((0, commons_1.resolveArchiveSource)(this.ctx));
}
catch (err) {
return (0, results_1.result)(err);
}
}
async resolveAscAppIdentifierAsync() {
const { ascAppId } = this.ctx.profile;
if (ascAppId) {
return (0, results_1.result)(ascAppId);
}
else if (this.ctx.nonInteractive) {
return (0, results_1.result)(new Error('Set ascAppId in the submit profile (eas.json) or re-run this command in interactive mode.'));
}
else {
log_1.default.log((0, wrap_ansi_1.default)(`Ensuring your app exists on App Store Connect. This step can be skipped by providing ${chalk_1.default.bold(`ascAppId`)} in the submit profile. ${(0, log_1.learnMore)('https://expo.fyi/asc-app-id')}`, process.stdout.columns || 80));
log_1.default.addNewLineIfNone();
try {
const { ascAppIdentifier } = await (0, AppProduce_1.ensureAppStoreConnectAppExistsAsync)(this.ctx);
return (0, results_1.result)(ascAppIdentifier);
}
catch (err) {
return (0, results_1.result)(err);
}
}
}
}
exports.default = IosSubmitCommand;
;