eas-cli 14.5.0 → 14.6.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 +126 -72
- package/build/build/android/graphql.js +2 -0
- package/build/build/android/prepareJob.js +1 -0
- package/build/build/android/version.d.ts +1 -0
- package/build/build/android/version.js +5 -1
- package/build/build/configure.d.ts +11 -0
- package/build/build/configure.js +46 -1
- package/build/build/evaluateConfigWithEnvVarsAsync.js +2 -4
- package/build/build/ios/build.js +2 -0
- package/build/build/ios/graphql.js +2 -0
- package/build/build/ios/prepareJob.js +1 -0
- package/build/build/ios/version.js +4 -1
- package/build/build/local.js +1 -1
- package/build/build/metadata.js +0 -1
- package/build/build/runBuildAndSubmit.d.ts +12 -1
- package/build/build/runBuildAndSubmit.js +16 -13
- package/build/build/utils/environment.d.ts +4 -0
- package/build/build/utils/environment.js +20 -0
- package/build/commands/build/dev.d.ts +23 -0
- package/build/commands/build/dev.js +225 -0
- package/build/commands/build/index.js +9 -1
- package/build/commands/build/inspect.js +26 -18
- package/build/commands/build/internal.js +22 -14
- package/build/commands/fingerprint/compare.d.ts +14 -1
- package/build/commands/fingerprint/compare.js +192 -53
- package/build/commands/project/onboarding.js +23 -14
- package/build/credentials/ios/appstore/ensureAppExists.d.ts +22 -1
- package/build/credentials/ios/appstore/ensureAppExists.js +73 -2
- package/build/credentials/ios/appstore/ensureTestFlightGroup.d.ts +7 -0
- package/build/credentials/ios/appstore/ensureTestFlightGroup.js +158 -0
- package/build/credentials/ios/appstore/provisioningProfile.js +1 -0
- package/build/graphql/generated.d.ts +193 -3
- package/build/graphql/generated.js +11 -2
- package/build/graphql/queries/FingerprintQuery.d.ts +16 -0
- package/build/graphql/queries/FingerprintQuery.js +61 -0
- package/build/graphql/types/Fingerprint.js +18 -0
- package/build/project/ios/exemptEncryption.d.ts +7 -0
- package/build/project/ios/exemptEncryption.js +80 -0
- package/build/submit/ios/AppProduce.js +12 -23
- package/build/utils/fingerprintCli.d.ts +2 -1
- package/build/utils/fingerprintCli.js +11 -3
- package/oclif.manifest.json +60 -4
- package/package.json +4 -4
|
@@ -4,6 +4,7 @@ exports.transformJob = void 0;
|
|
|
4
4
|
const eas_build_job_1 = require("@expo/eas-build-job");
|
|
5
5
|
const generated_1 = require("../../graphql/generated");
|
|
6
6
|
const graphql_1 = require("../graphql");
|
|
7
|
+
const environment_1 = require("../utils/environment");
|
|
7
8
|
function transformJob(job) {
|
|
8
9
|
return {
|
|
9
10
|
type: (0, graphql_1.transformWorkflow)(job.type),
|
|
@@ -24,6 +25,7 @@ function transformJob(job) {
|
|
|
24
25
|
experimental: job.experimental,
|
|
25
26
|
mode: (0, graphql_1.transformBuildMode)(job.mode),
|
|
26
27
|
customBuildConfig: job.customBuildConfig,
|
|
28
|
+
environment: (0, environment_1.buildProfileEnvironmentToEnvironment)(job.environment),
|
|
27
29
|
loggerLevel: job.loggerLevel
|
|
28
30
|
? graphql_1.loggerLevelToGraphQLWorkerLoggerLevel[job.loggerLevel]
|
|
29
31
|
: undefined,
|
|
@@ -72,6 +72,7 @@ async function prepareJobAsync(ctx, jobData) {
|
|
|
72
72
|
gradleCommand: buildProfile.gradleCommand,
|
|
73
73
|
applicationArchivePath: buildProfile.applicationArchivePath ?? buildProfile.artifactPath,
|
|
74
74
|
buildArtifactPaths: buildProfile.buildArtifactPaths,
|
|
75
|
+
environment: ctx.buildProfile.environment,
|
|
75
76
|
buildType,
|
|
76
77
|
username,
|
|
77
78
|
...(ctx.android.versionCodeOverride && {
|
|
@@ -21,6 +21,7 @@ export declare function bumpVersionInAppJsonAsync({ bumpStrategy, projectDir, ex
|
|
|
21
21
|
export declare function maybeResolveVersionsAsync(projectDir: string, exp: ExpoConfig, buildProfile: BuildProfile<Platform.ANDROID>, vcsClient: Client): Promise<{
|
|
22
22
|
appVersion?: string;
|
|
23
23
|
appBuildVersion?: string;
|
|
24
|
+
isVersionInitialized?: boolean;
|
|
24
25
|
}>;
|
|
25
26
|
export declare function updateNativeVersionsAsync({ projectDir, version, versionCode, }: {
|
|
26
27
|
projectDir: string;
|
|
@@ -73,6 +73,7 @@ async function maybeResolveVersionsAsync(projectDir, exp, buildProfile, vcsClien
|
|
|
73
73
|
return {
|
|
74
74
|
appVersion: (0, gradleUtils_1.resolveConfigValue)(buildGradle, 'versionName', parsedGradleCommand?.flavor) ?? '1.0.0',
|
|
75
75
|
appBuildVersion: (0, gradleUtils_1.resolveConfigValue)(buildGradle, 'versionCode', parsedGradleCommand?.flavor) ?? '1',
|
|
76
|
+
isVersionInitialized: !(0, gradleUtils_1.resolveConfigValue)(buildGradle, 'versionCode', parsedGradleCommand?.flavor),
|
|
76
77
|
};
|
|
77
78
|
}
|
|
78
79
|
catch {
|
|
@@ -121,6 +122,7 @@ async function resolveRemoteVersionCodeAsync(graphqlClient, { projectDir, projec
|
|
|
121
122
|
const remoteVersions = await AppVersionQuery_1.AppVersionQuery.latestVersionAsync(graphqlClient, projectId, generated_1.AppPlatform.Android, applicationId);
|
|
122
123
|
const localVersions = await maybeResolveVersionsAsync(projectDir, exp, buildProfile, vcsClient);
|
|
123
124
|
let currentBuildVersion;
|
|
125
|
+
let shouldInitializeVersionCode = false;
|
|
124
126
|
if (remoteVersions?.buildVersion) {
|
|
125
127
|
currentBuildVersion = remoteVersions.buildVersion;
|
|
126
128
|
}
|
|
@@ -128,6 +130,7 @@ async function resolveRemoteVersionCodeAsync(graphqlClient, { projectDir, projec
|
|
|
128
130
|
if (localVersions.appBuildVersion) {
|
|
129
131
|
log_1.default.log(chalk_1.default.green('No remote versions are configured for this project, versionCode will be initialized based on the value from the local project.'));
|
|
130
132
|
currentBuildVersion = localVersions.appBuildVersion;
|
|
133
|
+
shouldInitializeVersionCode = localVersions.isVersionInitialized ?? false;
|
|
131
134
|
}
|
|
132
135
|
else {
|
|
133
136
|
log_1.default.error(`Remote versions are not configured and EAS CLI was not able to read the current version from your project. Use "eas build:version:set" to initialize remote versions.`);
|
|
@@ -137,7 +140,8 @@ async function resolveRemoteVersionCodeAsync(graphqlClient, { projectDir, projec
|
|
|
137
140
|
if (!buildProfile.autoIncrement && remoteVersions?.buildVersion) {
|
|
138
141
|
return currentBuildVersion;
|
|
139
142
|
}
|
|
140
|
-
else if (!buildProfile.autoIncrement && !remoteVersions?.buildVersion)
|
|
143
|
+
else if ((!buildProfile.autoIncrement && !remoteVersions?.buildVersion) ||
|
|
144
|
+
shouldInitializeVersionCode) {
|
|
141
145
|
const spinner = (0, ora_1.ora)(`Initializing versionCode with ${chalk_1.default.bold(currentBuildVersion)}.`).start();
|
|
142
146
|
try {
|
|
143
147
|
await AppVersionMutation_1.AppVersionMutation.createAppVersionAsync(graphqlClient, {
|
|
@@ -13,4 +13,15 @@ export declare function easJsonExistsAsync(projectDir: string): Promise<boolean>
|
|
|
13
13
|
* - true - if eas.json was created by the function
|
|
14
14
|
*/
|
|
15
15
|
export declare function ensureProjectConfiguredAsync(configureParams: ConfigureParams): Promise<boolean>;
|
|
16
|
+
export declare function doesBuildProfileExistAsync({ projectDir, profileName, }: {
|
|
17
|
+
projectDir: string;
|
|
18
|
+
profileName: string;
|
|
19
|
+
}): Promise<boolean>;
|
|
20
|
+
export declare function createBuildProfileAsync({ projectDir, profileName, profileContents, vcsClient, nonInteractive, }: {
|
|
21
|
+
projectDir: string;
|
|
22
|
+
profileName: string;
|
|
23
|
+
profileContents: Record<string, any>;
|
|
24
|
+
vcsClient: Client;
|
|
25
|
+
nonInteractive: boolean;
|
|
26
|
+
}): Promise<void>;
|
|
16
27
|
export {};
|
package/build/build/configure.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ensureProjectConfiguredAsync = exports.easJsonExistsAsync = void 0;
|
|
3
|
+
exports.createBuildProfileAsync = exports.doesBuildProfileExistAsync = exports.ensureProjectConfiguredAsync = exports.easJsonExistsAsync = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const eas_json_1 = require("@expo/eas-json");
|
|
6
6
|
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
7
7
|
const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
|
|
8
8
|
const repository_1 = require("./utils/repository");
|
|
9
9
|
const log_1 = tslib_1.__importStar(require("../log"));
|
|
10
|
+
const ora_1 = require("../ora");
|
|
10
11
|
const easCli_1 = require("../utils/easCli");
|
|
11
12
|
async function easJsonExistsAsync(projectDir) {
|
|
12
13
|
return await fs_extra_1.default.pathExists(eas_json_1.EasJsonAccessor.formatEasJsonPath(projectDir));
|
|
@@ -37,6 +38,50 @@ async function configureAsync({ projectDir, nonInteractive, vcsClient, }) {
|
|
|
37
38
|
});
|
|
38
39
|
}
|
|
39
40
|
}
|
|
41
|
+
async function doesBuildProfileExistAsync({ projectDir, profileName, }) {
|
|
42
|
+
try {
|
|
43
|
+
const easJsonAccessor = eas_json_1.EasJsonAccessor.fromProjectPath(projectDir);
|
|
44
|
+
const easJson = await easJsonAccessor.readRawJsonAsync();
|
|
45
|
+
if (!easJson.build?.[profileName]) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
log_1.default.error(`We were unable to read ${chalk_1.default.bold('eas.json')} contents. Error: ${error}.`);
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
exports.doesBuildProfileExistAsync = doesBuildProfileExistAsync;
|
|
56
|
+
async function createBuildProfileAsync({ projectDir, profileName, profileContents, vcsClient, nonInteractive, }) {
|
|
57
|
+
const spinner = (0, ora_1.ora)(`Adding "${profileName}" build profile to ${chalk_1.default.bold('eas.json')}`).start();
|
|
58
|
+
try {
|
|
59
|
+
const easJsonAccessor = eas_json_1.EasJsonAccessor.fromProjectPath(projectDir);
|
|
60
|
+
await easJsonAccessor.readRawJsonAsync();
|
|
61
|
+
easJsonAccessor.patch(easJsonRawObject => {
|
|
62
|
+
return {
|
|
63
|
+
...easJsonRawObject,
|
|
64
|
+
build: {
|
|
65
|
+
...easJsonRawObject.build,
|
|
66
|
+
[profileName]: profileContents,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
});
|
|
70
|
+
await easJsonAccessor.writeAsync();
|
|
71
|
+
spinner.succeed(`Successfully added "${profileName}" build profile to ${chalk_1.default.bold('eas.json')}.`);
|
|
72
|
+
if (await vcsClient.isCommitRequiredAsync()) {
|
|
73
|
+
log_1.default.newLine();
|
|
74
|
+
await (0, repository_1.reviewAndCommitChangesAsync)(vcsClient, `Add "${profileName}" build profile to eas.json`, {
|
|
75
|
+
nonInteractive,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
spinner.fail(`We were not able to configure "${profileName}" build profile inside of ${chalk_1.default.bold('eas.json')}. Error: ${error}.`);
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
exports.createBuildProfileAsync = createBuildProfileAsync;
|
|
40
85
|
const EAS_JSON_DEFAULT = {
|
|
41
86
|
cli: {
|
|
42
87
|
version: `>= ${easCli_1.easCliVersion}`,
|
|
@@ -2,12 +2,10 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.evaluateConfigWithEnvVarsAsync = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
+
const environment_1 = require("./utils/environment");
|
|
5
6
|
const generated_1 = require("../graphql/generated");
|
|
6
7
|
const EnvironmentVariablesQuery_1 = require("../graphql/queries/EnvironmentVariablesQuery");
|
|
7
8
|
const log_1 = tslib_1.__importStar(require("../log"));
|
|
8
|
-
function isEnvironment(env) {
|
|
9
|
-
return Object.values(generated_1.EnvironmentVariableEnvironment).includes(env);
|
|
10
|
-
}
|
|
11
9
|
async function evaluateConfigWithEnvVarsAsync({ buildProfile, buildProfileName, graphqlClient, getProjectConfig, opts, }) {
|
|
12
10
|
if (!graphqlClient) {
|
|
13
11
|
log_1.default.warn('An Expo user account is required to fetch environment variables.');
|
|
@@ -28,7 +26,7 @@ exports.evaluateConfigWithEnvVarsAsync = evaluateConfigWithEnvVarsAsync;
|
|
|
28
26
|
async function resolveEnvVarsAsync({ buildProfile, buildProfileName, graphqlClient, projectId, }) {
|
|
29
27
|
const environment = buildProfile.environment?.toUpperCase() ??
|
|
30
28
|
resolveSuggestedEnvironmentForBuildProfileConfiguration(buildProfile);
|
|
31
|
-
if (!isEnvironment(environment)) {
|
|
29
|
+
if (!(0, environment_1.isEnvironment)(environment)) {
|
|
32
30
|
log_1.default.log(`Loaded "env" configuration for the "${buildProfileName}" profile: ${buildProfile.env && Object.keys(buildProfile.env).length > 0
|
|
33
31
|
? Object.keys(buildProfile.env).join(', ')
|
|
34
32
|
: 'no environment variables specified'}. ${(0, log_1.learnMore)('https://docs.expo.dev/build-reference/variables/')}`);
|
package/build/build/ios/build.js
CHANGED
|
@@ -10,6 +10,7 @@ const syncProjectConfiguration_1 = require("./syncProjectConfiguration");
|
|
|
10
10
|
const version_1 = require("./version");
|
|
11
11
|
const BuildMutation_1 = require("../../graphql/mutations/BuildMutation");
|
|
12
12
|
const bundleIdentifier_1 = require("../../project/ios/bundleIdentifier");
|
|
13
|
+
const exemptEncryption_1 = require("../../project/ios/exemptEncryption");
|
|
13
14
|
const scheme_1 = require("../../project/ios/scheme");
|
|
14
15
|
const target_1 = require("../../project/ios/target");
|
|
15
16
|
const build_1 = require("../build");
|
|
@@ -19,6 +20,7 @@ async function createIosContextAsync(ctx) {
|
|
|
19
20
|
const { buildProfile, env } = ctx;
|
|
20
21
|
if (ctx.workflow === eas_build_job_1.Workflow.MANAGED) {
|
|
21
22
|
await (0, bundleIdentifier_1.ensureBundleIdentifierIsDefinedForManagedProjectAsync)(ctx);
|
|
23
|
+
await (0, exemptEncryption_1.ensureNonExemptEncryptionIsDefinedForManagedProjectAsync)(ctx);
|
|
22
24
|
}
|
|
23
25
|
(0, validate_1.checkNodeEnvVariable)(ctx);
|
|
24
26
|
await (0, validate_1.checkGoogleServicesFileAsync)(ctx);
|
|
@@ -4,6 +4,7 @@ exports.transformIosSecrets = exports.transformJob = void 0;
|
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const nullthrows_1 = tslib_1.__importDefault(require("nullthrows"));
|
|
6
6
|
const graphql_1 = require("../graphql");
|
|
7
|
+
const environment_1 = require("../utils/environment");
|
|
7
8
|
function transformJob(job) {
|
|
8
9
|
return {
|
|
9
10
|
type: (0, graphql_1.transformWorkflow)(job.type),
|
|
@@ -25,6 +26,7 @@ function transformJob(job) {
|
|
|
25
26
|
experimental: job.experimental,
|
|
26
27
|
mode: (0, graphql_1.transformBuildMode)(job.mode),
|
|
27
28
|
customBuildConfig: job.customBuildConfig,
|
|
29
|
+
environment: (0, environment_1.buildProfileEnvironmentToEnvironment)(job.environment),
|
|
28
30
|
loggerLevel: job.loggerLevel
|
|
29
31
|
? graphql_1.loggerLevelToGraphQLWorkerLoggerLevel[job.loggerLevel]
|
|
30
32
|
: undefined,
|
|
@@ -67,6 +67,7 @@ async function prepareJobAsync(ctx, jobData) {
|
|
|
67
67
|
buildConfiguration: buildProfile.buildConfiguration,
|
|
68
68
|
applicationArchivePath: buildProfile.applicationArchivePath ?? buildProfile.artifactPath,
|
|
69
69
|
buildArtifactPaths: buildProfile.buildArtifactPaths,
|
|
70
|
+
environment: ctx.buildProfile.environment,
|
|
70
71
|
username,
|
|
71
72
|
...(ctx.ios.buildNumberOverride && {
|
|
72
73
|
version: {
|
|
@@ -209,6 +209,7 @@ async function resolveRemoteBuildNumberAsync(graphqlClient, { projectDir, projec
|
|
|
209
209
|
const localBuildNumber = await readBuildNumberAsync(projectDir, exp, applicationTarget.buildSettings ?? {}, vcsClient);
|
|
210
210
|
const localShortVersion = await readShortVersionAsync(projectDir, exp, applicationTarget.buildSettings ?? {}, vcsClient);
|
|
211
211
|
let currentBuildVersion;
|
|
212
|
+
let shouldInitializeBuildNumber = false;
|
|
212
213
|
if (remoteVersions?.buildVersion) {
|
|
213
214
|
currentBuildVersion = remoteVersions.buildVersion;
|
|
214
215
|
}
|
|
@@ -216,6 +217,7 @@ async function resolveRemoteBuildNumberAsync(graphqlClient, { projectDir, projec
|
|
|
216
217
|
if (localBuildNumber) {
|
|
217
218
|
log_1.default.log(chalk_1.default.green('No remote versions are configured for this project, buildNumber will be initialized based on the value from the local project.'));
|
|
218
219
|
currentBuildVersion = localBuildNumber;
|
|
220
|
+
shouldInitializeBuildNumber = localBuildNumber === '1';
|
|
219
221
|
}
|
|
220
222
|
else {
|
|
221
223
|
log_1.default.error(`Remote versions are not configured and EAS CLI was not able to read the current version from your project. Use "eas build:version:set" to initialize remote versions.`);
|
|
@@ -225,7 +227,8 @@ async function resolveRemoteBuildNumberAsync(graphqlClient, { projectDir, projec
|
|
|
225
227
|
if (!buildProfile.autoIncrement && remoteVersions?.buildVersion) {
|
|
226
228
|
return currentBuildVersion;
|
|
227
229
|
}
|
|
228
|
-
else if (!buildProfile.autoIncrement && !remoteVersions?.buildVersion)
|
|
230
|
+
else if ((!buildProfile.autoIncrement && !remoteVersions?.buildVersion) ||
|
|
231
|
+
shouldInitializeBuildNumber) {
|
|
229
232
|
const spinner = (0, ora_1.ora)(`Initializing buildNumber with ${chalk_1.default.bold(currentBuildVersion)}.`).start();
|
|
230
233
|
try {
|
|
231
234
|
await AppVersionMutation_1.AppVersionMutation.createAppVersionAsync(graphqlClient, {
|
package/build/build/local.js
CHANGED
|
@@ -7,7 +7,7 @@ const semver_1 = tslib_1.__importDefault(require("semver"));
|
|
|
7
7
|
const log_1 = tslib_1.__importDefault(require("../log"));
|
|
8
8
|
const ora_1 = require("../ora");
|
|
9
9
|
const PLUGIN_PACKAGE_NAME = 'eas-cli-local-build-plugin';
|
|
10
|
-
const PLUGIN_PACKAGE_VERSION = '1.0.
|
|
10
|
+
const PLUGIN_PACKAGE_VERSION = '1.0.168';
|
|
11
11
|
var LocalBuildMode;
|
|
12
12
|
(function (LocalBuildMode) {
|
|
13
13
|
/**
|
package/build/build/metadata.js
CHANGED
|
@@ -50,7 +50,6 @@ async function collectMetadataAsync(ctx, runtimeAndFingerprintMetadata) {
|
|
|
50
50
|
requiredPackageManager: ctx.requiredPackageManager ?? undefined,
|
|
51
51
|
selectedImage: ctx.buildProfile.image,
|
|
52
52
|
customNodeVersion: ctx.buildProfile.node,
|
|
53
|
-
environment: ctx.buildProfile.environment,
|
|
54
53
|
simulator: 'simulator' in ctx.buildProfile && ctx.buildProfile.simulator,
|
|
55
54
|
};
|
|
56
55
|
return (0, eas_build_job_1.sanitizeMetadata)(metadata);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Env } from '@expo/eas-build-job';
|
|
1
2
|
import { ResourceClass } from '@expo/eas-json';
|
|
2
3
|
import { LoggerLevel } from '@expo/logger';
|
|
3
4
|
import { LocalBuildOptions } from './local';
|
|
@@ -23,6 +24,16 @@ export interface BuildFlags {
|
|
|
23
24
|
freezeCredentials: boolean;
|
|
24
25
|
repack: boolean;
|
|
25
26
|
}
|
|
26
|
-
export declare function runBuildAndSubmitAsync(graphqlClient
|
|
27
|
+
export declare function runBuildAndSubmitAsync({ graphqlClient, analytics, vcsClient, projectDir, flags, actor, getDynamicPrivateProjectConfigAsync, downloadSimBuildAutoConfirm, envOverride, }: {
|
|
28
|
+
graphqlClient: ExpoGraphqlClient;
|
|
29
|
+
analytics: Analytics;
|
|
30
|
+
vcsClient: Client;
|
|
31
|
+
projectDir: string;
|
|
32
|
+
flags: BuildFlags;
|
|
33
|
+
actor: Actor;
|
|
34
|
+
getDynamicPrivateProjectConfigAsync: DynamicConfigContextFn;
|
|
35
|
+
downloadSimBuildAutoConfirm?: boolean;
|
|
36
|
+
envOverride?: Env;
|
|
37
|
+
}): Promise<{
|
|
27
38
|
buildIds: string[];
|
|
28
39
|
}>;
|
|
@@ -42,7 +42,7 @@ const json_1 = require("../utils/json");
|
|
|
42
42
|
const profiles_1 = require("../utils/profiles");
|
|
43
43
|
let metroConfigValidated = false;
|
|
44
44
|
let sdkVersionChecked = false;
|
|
45
|
-
async function runBuildAndSubmitAsync(graphqlClient, analytics, vcsClient, projectDir, flags, actor, getDynamicPrivateProjectConfigAsync) {
|
|
45
|
+
async function runBuildAndSubmitAsync({ graphqlClient, analytics, vcsClient, projectDir, flags, actor, getDynamicPrivateProjectConfigAsync, downloadSimBuildAutoConfirm, envOverride, }) {
|
|
46
46
|
await vcsClient.ensureRepoExistsAsync();
|
|
47
47
|
await (0, repository_1.ensureRepoIsCleanAsync)(vcsClient, flags.nonInteractive);
|
|
48
48
|
await (0, configure_1.ensureProjectConfiguredAsync)({
|
|
@@ -98,13 +98,15 @@ async function runBuildAndSubmitAsync(graphqlClient, analytics, vcsClient, proje
|
|
|
98
98
|
const buildCtxByPlatform = {};
|
|
99
99
|
for (const buildProfile of buildProfiles) {
|
|
100
100
|
const platform = (0, AppPlatform_1.toAppPlatform)(buildProfile.platform);
|
|
101
|
-
const { env } =
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
101
|
+
const { env } = !envOverride
|
|
102
|
+
? await (0, evaluateConfigWithEnvVarsAsync_1.evaluateConfigWithEnvVarsAsync)({
|
|
103
|
+
buildProfile: buildProfile.profile,
|
|
104
|
+
buildProfileName: buildProfile.profileName,
|
|
105
|
+
graphqlClient,
|
|
106
|
+
getProjectConfig: getDynamicPrivateProjectConfigAsync,
|
|
107
|
+
opts: { env: buildProfile.profile.env },
|
|
108
|
+
})
|
|
109
|
+
: { env: envOverride };
|
|
108
110
|
const { build: maybeBuild, buildCtx } = await prepareAndStartBuildAsync({
|
|
109
111
|
projectDir,
|
|
110
112
|
flags,
|
|
@@ -190,7 +192,7 @@ async function runBuildAndSubmitAsync(graphqlClient, analytics, vcsClient, proje
|
|
|
190
192
|
}
|
|
191
193
|
const haveAllBuildsFailedOrCanceled = builds.every(build => build?.status &&
|
|
192
194
|
[generated_1.BuildStatus.Errored, generated_1.BuildStatus.Canceled, generated_1.BuildStatus.PendingCancel].includes(build?.status));
|
|
193
|
-
await maybeDownloadAndRunSimulatorBuildsAsync(builds, flags);
|
|
195
|
+
await maybeDownloadAndRunSimulatorBuildsAsync(builds, flags, downloadSimBuildAutoConfirm);
|
|
194
196
|
if (haveAllBuildsFailedOrCanceled || !flags.autoSubmit) {
|
|
195
197
|
if (flags.json) {
|
|
196
198
|
(0, json_1.printJsonOnlyOutput)(builds);
|
|
@@ -341,15 +343,16 @@ async function downloadAndRunAsync(build) {
|
|
|
341
343
|
const buildPath = await (0, download_1.downloadAndMaybeExtractAppAsync)(build.artifacts.applicationArchiveUrl, build.platform);
|
|
342
344
|
await (0, run_1.runAsync)(buildPath, build.platform);
|
|
343
345
|
}
|
|
344
|
-
async function maybeDownloadAndRunSimulatorBuildsAsync(builds, flags) {
|
|
346
|
+
async function maybeDownloadAndRunSimulatorBuildsAsync(builds, flags, autoConfirm) {
|
|
345
347
|
const simBuilds = builds.filter(filter_1.truthy).filter(utils_1.isRunnableOnSimulatorOrEmulator);
|
|
346
348
|
if (simBuilds.length > 0 && !flags.autoSubmit && !flags.nonInteractive) {
|
|
347
349
|
for (const simBuild of simBuilds) {
|
|
348
350
|
if (simBuild.platform === generated_1.AppPlatform.Android || process.platform === 'darwin') {
|
|
349
351
|
log_1.default.newLine();
|
|
350
|
-
const confirm =
|
|
351
|
-
|
|
352
|
-
|
|
352
|
+
const confirm = autoConfirm ??
|
|
353
|
+
(await (0, prompts_1.confirmAsync)({
|
|
354
|
+
message: `Install and run the ${simBuild.platform === generated_1.AppPlatform.Android ? 'Android' : 'iOS'} build on ${simBuild.platform === generated_1.AppPlatform.Android ? 'an emulator' : 'a simulator'}?`,
|
|
355
|
+
}));
|
|
353
356
|
if (confirm) {
|
|
354
357
|
await downloadAndRunAsync(simBuild);
|
|
355
358
|
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { BuildProfile } from '@expo/eas-json';
|
|
2
|
+
import { EnvironmentVariableEnvironment } from '../../graphql/generated';
|
|
3
|
+
export declare function isEnvironment(env: string): env is EnvironmentVariableEnvironment;
|
|
4
|
+
export declare function buildProfileEnvironmentToEnvironment(environment: BuildProfile['environment']): EnvironmentVariableEnvironment | null;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildProfileEnvironmentToEnvironment = exports.isEnvironment = void 0;
|
|
4
|
+
const generated_1 = require("../../graphql/generated");
|
|
5
|
+
const BuildProfileEnvironmentToEnvironment = {
|
|
6
|
+
production: generated_1.EnvironmentVariableEnvironment.Production,
|
|
7
|
+
preview: generated_1.EnvironmentVariableEnvironment.Preview,
|
|
8
|
+
development: generated_1.EnvironmentVariableEnvironment.Development,
|
|
9
|
+
};
|
|
10
|
+
function isEnvironment(env) {
|
|
11
|
+
return Object.values(generated_1.EnvironmentVariableEnvironment).includes(env);
|
|
12
|
+
}
|
|
13
|
+
exports.isEnvironment = isEnvironment;
|
|
14
|
+
function buildProfileEnvironmentToEnvironment(environment) {
|
|
15
|
+
if (!environment) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
return BuildProfileEnvironmentToEnvironment[environment];
|
|
19
|
+
}
|
|
20
|
+
exports.buildProfileEnvironmentToEnvironment = buildProfileEnvironmentToEnvironment;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Platform } from '@expo/eas-build-job';
|
|
2
|
+
import EasCommand from '../../commandUtils/EasCommand';
|
|
3
|
+
export default class BuildDev extends EasCommand {
|
|
4
|
+
static hidden: true;
|
|
5
|
+
static description: string;
|
|
6
|
+
static flags: {
|
|
7
|
+
platform: import("@oclif/core/lib/interfaces").OptionFlag<Platform | undefined>;
|
|
8
|
+
profile: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined>;
|
|
9
|
+
};
|
|
10
|
+
static contextDefinition: {
|
|
11
|
+
projectId: import("../../commandUtils/context/ProjectIdContextField").ProjectIdContextField;
|
|
12
|
+
analytics: import("../../commandUtils/context/AnalyticsContextField").default;
|
|
13
|
+
vcsClient: import("../../commandUtils/context/VcsClientContextField").default;
|
|
14
|
+
projectDir: import("../../commandUtils/context/ProjectDirContextField").default;
|
|
15
|
+
getDynamicPublicProjectConfigAsync: import("../../commandUtils/context/DynamicProjectConfigContextField").DynamicPublicProjectConfigContextField;
|
|
16
|
+
getDynamicPrivateProjectConfigAsync: import("../../commandUtils/context/DynamicProjectConfigContextField").DynamicPrivateProjectConfigContextField;
|
|
17
|
+
loggedIn: import("../../commandUtils/context/LoggedInContextField").default;
|
|
18
|
+
};
|
|
19
|
+
protected runAsync(): Promise<any>;
|
|
20
|
+
private selectPlatformAsync;
|
|
21
|
+
private validateBuildRunProfileAsync;
|
|
22
|
+
private ensureValidBuildRunProfileExistsAsync;
|
|
23
|
+
}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const eas_build_job_1 = require("@expo/eas-build-job");
|
|
5
|
+
const eas_json_1 = require("@expo/eas-json");
|
|
6
|
+
const core_1 = require("@oclif/core");
|
|
7
|
+
const configure_1 = require("../../build/configure");
|
|
8
|
+
const evaluateConfigWithEnvVarsAsync_1 = require("../../build/evaluateConfigWithEnvVarsAsync");
|
|
9
|
+
const runBuildAndSubmit_1 = require("../../build/runBuildAndSubmit");
|
|
10
|
+
const repository_1 = require("../../build/utils/repository");
|
|
11
|
+
const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
|
|
12
|
+
const generated_1 = require("../../graphql/generated");
|
|
13
|
+
const BuildQuery_1 = require("../../graphql/queries/BuildQuery");
|
|
14
|
+
const AppPlatform_1 = require("../../graphql/types/AppPlatform");
|
|
15
|
+
const log_1 = tslib_1.__importDefault(require("../../log"));
|
|
16
|
+
const platform_1 = require("../../platform");
|
|
17
|
+
const workflow_1 = require("../../project/workflow");
|
|
18
|
+
const prompts_1 = require("../../prompts");
|
|
19
|
+
const run_1 = require("../../run/run");
|
|
20
|
+
const download_1 = require("../../utils/download");
|
|
21
|
+
const fingerprintCli_1 = require("../../utils/fingerprintCli");
|
|
22
|
+
const profiles_1 = require("../../utils/profiles");
|
|
23
|
+
const DEFAULT_EAS_BUILD_RUN_PROFILE_NAME = 'development-simulator';
|
|
24
|
+
class BuildDev extends EasCommand_1.default {
|
|
25
|
+
static hidden;
|
|
26
|
+
static description = 'run dev client simulator/emulator build with matching fingerprint or create a new one';
|
|
27
|
+
static flags = {
|
|
28
|
+
platform: core_1.Flags.enum({
|
|
29
|
+
char: 'p',
|
|
30
|
+
options: [eas_build_job_1.Platform.IOS, eas_build_job_1.Platform.ANDROID],
|
|
31
|
+
}),
|
|
32
|
+
profile: core_1.Flags.string({
|
|
33
|
+
char: 'e',
|
|
34
|
+
description: `Name of the build profile from eas.json. It must be a profile allowing to create emulator/simulator internal distribution dev client builds. The "${DEFAULT_EAS_BUILD_RUN_PROFILE_NAME}" build profile will be selected by default.`,
|
|
35
|
+
helpValue: 'PROFILE_NAME',
|
|
36
|
+
}),
|
|
37
|
+
};
|
|
38
|
+
static contextDefinition = {
|
|
39
|
+
...this.ContextOptions.LoggedIn,
|
|
40
|
+
...this.ContextOptions.DynamicProjectConfig,
|
|
41
|
+
...this.ContextOptions.ProjectDir,
|
|
42
|
+
...this.ContextOptions.Vcs,
|
|
43
|
+
...this.ContextOptions.Analytics,
|
|
44
|
+
...this.ContextOptions.ProjectId,
|
|
45
|
+
};
|
|
46
|
+
async runAsync() {
|
|
47
|
+
const { flags } = await this.parse(BuildDev);
|
|
48
|
+
const { loggedIn: { actor, graphqlClient }, getDynamicPrivateProjectConfigAsync, projectDir, analytics, vcsClient, projectId, } = await this.getContextAsync(BuildDev, {
|
|
49
|
+
nonInteractive: false,
|
|
50
|
+
withServerSideEnvironment: null,
|
|
51
|
+
});
|
|
52
|
+
const platform = await this.selectPlatformAsync(flags.platform);
|
|
53
|
+
if (process.platform !== 'darwin' && platform === eas_build_job_1.Platform.IOS) {
|
|
54
|
+
core_1.Errors.error('Running iOS builds in simulator is only supported on macOS.', { exit: 1 });
|
|
55
|
+
}
|
|
56
|
+
await vcsClient.ensureRepoExistsAsync();
|
|
57
|
+
await (0, repository_1.ensureRepoIsCleanAsync)(vcsClient, flags.nonInteractive);
|
|
58
|
+
await (0, configure_1.ensureProjectConfiguredAsync)({
|
|
59
|
+
projectDir,
|
|
60
|
+
nonInteractive: false,
|
|
61
|
+
vcsClient,
|
|
62
|
+
});
|
|
63
|
+
const buildProfile = await this.ensureValidBuildRunProfileExistsAsync({
|
|
64
|
+
projectDir,
|
|
65
|
+
platform,
|
|
66
|
+
selectedBuildProfileName: flags.profile,
|
|
67
|
+
vcsClient,
|
|
68
|
+
});
|
|
69
|
+
const workflow = await (0, workflow_1.resolveWorkflowAsync)(projectDir, platform, vcsClient);
|
|
70
|
+
const { env } = await (0, evaluateConfigWithEnvVarsAsync_1.evaluateConfigWithEnvVarsAsync)({
|
|
71
|
+
buildProfile: buildProfile.profile,
|
|
72
|
+
buildProfileName: buildProfile.profileName,
|
|
73
|
+
graphqlClient,
|
|
74
|
+
getProjectConfig: getDynamicPrivateProjectConfigAsync,
|
|
75
|
+
opts: { env: buildProfile.profile.env },
|
|
76
|
+
});
|
|
77
|
+
const fingerprint = await (0, fingerprintCli_1.createFingerprintAsync)(projectDir, {
|
|
78
|
+
env,
|
|
79
|
+
workflow,
|
|
80
|
+
platforms: [platform],
|
|
81
|
+
});
|
|
82
|
+
if (!fingerprint) {
|
|
83
|
+
core_1.Errors.error('Failed to calculate fingerprint', { exit: 1 });
|
|
84
|
+
}
|
|
85
|
+
log_1.default.log(`✨ Calculated fingerprint hash: ${fingerprint.hash}`);
|
|
86
|
+
log_1.default.newLine();
|
|
87
|
+
const builds = await BuildQuery_1.BuildQuery.viewBuildsOnAppAsync(graphqlClient, {
|
|
88
|
+
appId: projectId,
|
|
89
|
+
filter: {
|
|
90
|
+
platform: (0, AppPlatform_1.toAppPlatform)(platform),
|
|
91
|
+
fingerprintHash: fingerprint.hash,
|
|
92
|
+
status: generated_1.BuildStatus.Finished,
|
|
93
|
+
simulator: platform === eas_build_job_1.Platform.IOS ? true : undefined,
|
|
94
|
+
distribution: platform === eas_build_job_1.Platform.ANDROID ? generated_1.DistributionType.Internal : undefined,
|
|
95
|
+
developmentClient: true,
|
|
96
|
+
},
|
|
97
|
+
offset: 0,
|
|
98
|
+
limit: 1,
|
|
99
|
+
});
|
|
100
|
+
if (builds.length !== 0) {
|
|
101
|
+
const build = builds[0];
|
|
102
|
+
log_1.default.succeed(`🎯 Found successful build with matching fingerprint on EAS servers. Running it...`);
|
|
103
|
+
if (build.artifacts?.applicationArchiveUrl) {
|
|
104
|
+
const buildPath = await (0, download_1.downloadAndMaybeExtractAppAsync)(build.artifacts.applicationArchiveUrl, build.platform);
|
|
105
|
+
await (0, run_1.runAsync)(buildPath, build.platform);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
log_1.default.warn('Artifacts for this build expired. New build will be started.');
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
log_1.default.log('🚀 No successful build with matching fingerprint found. Starting a new build...');
|
|
113
|
+
await (0, runBuildAndSubmit_1.runBuildAndSubmitAsync)({
|
|
114
|
+
graphqlClient,
|
|
115
|
+
analytics,
|
|
116
|
+
vcsClient,
|
|
117
|
+
projectDir,
|
|
118
|
+
flags: {
|
|
119
|
+
requestedPlatform: platform === eas_build_job_1.Platform.ANDROID ? platform_1.RequestedPlatform.Android : platform_1.RequestedPlatform.Ios,
|
|
120
|
+
nonInteractive: false,
|
|
121
|
+
freezeCredentials: false,
|
|
122
|
+
wait: true,
|
|
123
|
+
clearCache: false,
|
|
124
|
+
json: false,
|
|
125
|
+
autoSubmit: false,
|
|
126
|
+
localBuildOptions: {},
|
|
127
|
+
repack: false,
|
|
128
|
+
profile: flags.profile ?? DEFAULT_EAS_BUILD_RUN_PROFILE_NAME,
|
|
129
|
+
},
|
|
130
|
+
actor,
|
|
131
|
+
getDynamicPrivateProjectConfigAsync,
|
|
132
|
+
downloadSimBuildAutoConfirm: true,
|
|
133
|
+
envOverride: env,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
async selectPlatformAsync(platform) {
|
|
137
|
+
if (platform) {
|
|
138
|
+
return platform;
|
|
139
|
+
}
|
|
140
|
+
const { resolvedPlatform } = await (0, prompts_1.promptAsync)({
|
|
141
|
+
type: 'select',
|
|
142
|
+
message: 'Select platform',
|
|
143
|
+
name: 'resolvedPlatform',
|
|
144
|
+
choices: [
|
|
145
|
+
{ title: 'Android', value: eas_build_job_1.Platform.ANDROID },
|
|
146
|
+
{ title: 'iOS', value: eas_build_job_1.Platform.IOS },
|
|
147
|
+
],
|
|
148
|
+
});
|
|
149
|
+
return resolvedPlatform;
|
|
150
|
+
}
|
|
151
|
+
async validateBuildRunProfileAsync({ platform, buildProfile, buildProfileName, }) {
|
|
152
|
+
if (buildProfile.developmentClient !== true) {
|
|
153
|
+
core_1.Errors.error(`Profile "${buildProfileName}" must specify "developmentClient: true" to create a dev client build. Select a different profile or update the profile in eas.json.`, { exit: 1 });
|
|
154
|
+
}
|
|
155
|
+
if (buildProfile.distribution !== 'internal') {
|
|
156
|
+
core_1.Errors.error(`Profile "${buildProfileName}" must specify "distribution: internal" in order to work with eas build:dev command. Select a different profile or update the profile in eas.json.`, { exit: 1 });
|
|
157
|
+
}
|
|
158
|
+
if (platform === eas_build_job_1.Platform.IOS) {
|
|
159
|
+
const iosProfile = buildProfile;
|
|
160
|
+
if (iosProfile.simulator !== true && iosProfile.withoutCredentials !== true) {
|
|
161
|
+
core_1.Errors.error(`Profile "${buildProfileName}" must specify "ios.simulator: true" or "withoutCredentials: true" to create an iOS simulator build. Select a different profile or update the profile in eas.json.`, { exit: 1 });
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
const androidProfile = buildProfile;
|
|
166
|
+
if (androidProfile.distribution !== 'internal' &&
|
|
167
|
+
androidProfile.withoutCredentials !== true) {
|
|
168
|
+
core_1.Errors.error(`Profile "${buildProfileName}" must specify "distribution: internal" or "withoutCredentials: true" to create an Android emulator build. Select a different profile or update the profile in eas.json.`, { exit: 1 });
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
async ensureValidBuildRunProfileExistsAsync({ projectDir, platform, selectedBuildProfileName, vcsClient, }) {
|
|
173
|
+
if (!!selectedBuildProfileName ||
|
|
174
|
+
(await (0, configure_1.doesBuildProfileExistAsync)({
|
|
175
|
+
projectDir,
|
|
176
|
+
profileName: DEFAULT_EAS_BUILD_RUN_PROFILE_NAME,
|
|
177
|
+
}))) {
|
|
178
|
+
const easJsonAccessor = eas_json_1.EasJsonAccessor.fromProjectPath(projectDir);
|
|
179
|
+
const [buildProfile] = await (0, profiles_1.getProfilesAsync)({
|
|
180
|
+
type: 'build',
|
|
181
|
+
easJsonAccessor,
|
|
182
|
+
platforms: [platform],
|
|
183
|
+
profileName: selectedBuildProfileName ?? DEFAULT_EAS_BUILD_RUN_PROFILE_NAME,
|
|
184
|
+
projectDir,
|
|
185
|
+
});
|
|
186
|
+
await this.validateBuildRunProfileAsync({
|
|
187
|
+
buildProfileName: selectedBuildProfileName ?? DEFAULT_EAS_BUILD_RUN_PROFILE_NAME,
|
|
188
|
+
platform,
|
|
189
|
+
buildProfile: buildProfile.profile,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
const createBuildProfile = await (0, prompts_1.confirmAsync)({
|
|
194
|
+
message: `We want to go ahead and generate "${DEFAULT_EAS_BUILD_RUN_PROFILE_NAME}" build profile for you, that matches eas build:dev criteria. Do you want to proceed?`,
|
|
195
|
+
});
|
|
196
|
+
if (!createBuildProfile) {
|
|
197
|
+
core_1.Errors.error('Come back later or specify different build compliant with eas build:dev requirements by using "--profile" flag.', { exit: 1 });
|
|
198
|
+
}
|
|
199
|
+
await (0, configure_1.createBuildProfileAsync)({
|
|
200
|
+
projectDir,
|
|
201
|
+
profileName: DEFAULT_EAS_BUILD_RUN_PROFILE_NAME,
|
|
202
|
+
profileContents: {
|
|
203
|
+
developmentClient: true,
|
|
204
|
+
distribution: 'internal',
|
|
205
|
+
ios: {
|
|
206
|
+
simulator: true,
|
|
207
|
+
},
|
|
208
|
+
environment: 'development',
|
|
209
|
+
},
|
|
210
|
+
nonInteractive: false,
|
|
211
|
+
vcsClient,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
const easJsonAccessor = eas_json_1.EasJsonAccessor.fromProjectPath(projectDir);
|
|
215
|
+
const [buildProfile] = await (0, profiles_1.getProfilesAsync)({
|
|
216
|
+
type: 'build',
|
|
217
|
+
easJsonAccessor,
|
|
218
|
+
platforms: [platform],
|
|
219
|
+
profileName: selectedBuildProfileName ?? DEFAULT_EAS_BUILD_RUN_PROFILE_NAME,
|
|
220
|
+
projectDir,
|
|
221
|
+
});
|
|
222
|
+
return buildProfile;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
exports.default = BuildDev;
|
|
@@ -118,7 +118,15 @@ class Build extends EasCommand_1.default {
|
|
|
118
118
|
: [generated_1.StatuspageServiceName.EasBuild]);
|
|
119
119
|
}
|
|
120
120
|
const flagsWithPlatform = await this.ensurePlatformSelectedAsync(flags);
|
|
121
|
-
await (0, runBuildAndSubmit_1.runBuildAndSubmitAsync)(
|
|
121
|
+
await (0, runBuildAndSubmit_1.runBuildAndSubmitAsync)({
|
|
122
|
+
graphqlClient,
|
|
123
|
+
analytics,
|
|
124
|
+
vcsClient,
|
|
125
|
+
projectDir,
|
|
126
|
+
flags: flagsWithPlatform,
|
|
127
|
+
actor,
|
|
128
|
+
getDynamicPrivateProjectConfigAsync,
|
|
129
|
+
});
|
|
122
130
|
}
|
|
123
131
|
sanitizeFlags(flags) {
|
|
124
132
|
const nonInteractive = flags['non-interactive'];
|