eas-cli 14.7.1 → 15.0.1
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 +88 -81
- package/build/build/runBuildAndSubmit.d.ts +2 -0
- package/build/build/runBuildAndSubmit.js +11 -2
- package/build/commands/build/dev.d.ts +1 -0
- package/build/commands/build/dev.js +30 -16
- package/build/commands/build/internal.js +7 -3
- package/build/commands/build/run.js +1 -6
- package/build/commands/fingerprint/compare.d.ts +2 -8
- package/build/commands/fingerprint/compare.js +218 -66
- package/build/commands/project/onboarding.js +4 -1
- package/build/commands/submit/internal.js +7 -3
- package/build/graphql/generated.d.ts +141 -0
- package/build/graphql/queries/UpdateQuery.d.ts +2 -1
- package/build/graphql/queries/UpdateQuery.js +16 -0
- package/build/graphql/types/Build.js +5 -0
- package/build/graphql/types/Update.js +1 -0
- package/build/run/run.d.ts +1 -0
- package/build/run/run.js +8 -1
- package/build/vcs/clients/git.d.ts +6 -2
- package/build/vcs/clients/git.js +87 -27
- package/build/vcs/index.js +10 -10
- package/build/vcs/local.d.ts +1 -0
- package/build/vcs/local.js +3 -3
- package/oclif.manifest.json +17 -5
- package/package.json +3 -3
- package/build/vcs/clients/gitNoCommit.d.ts +0 -8
- package/build/vcs/clients/gitNoCommit.js +0 -42
|
@@ -5,6 +5,7 @@ import { LocalBuildOptions } from './local';
|
|
|
5
5
|
import { Analytics } from '../analytics/AnalyticsManager';
|
|
6
6
|
import { DynamicConfigContextFn } from '../commandUtils/context/DynamicProjectConfigContextField';
|
|
7
7
|
import { ExpoGraphqlClient } from '../commandUtils/context/contextUtils/createGraphqlClient';
|
|
8
|
+
import { BuildFragment } from '../graphql/generated';
|
|
8
9
|
import { RequestedPlatform } from '../platform';
|
|
9
10
|
import { Actor } from '../user/User';
|
|
10
11
|
import { Client } from '../vcs/vcs';
|
|
@@ -37,3 +38,4 @@ export declare function runBuildAndSubmitAsync({ graphqlClient, analytics, vcsCl
|
|
|
37
38
|
}): Promise<{
|
|
38
39
|
buildIds: string[];
|
|
39
40
|
}>;
|
|
41
|
+
export declare function downloadAndRunAsync(build: BuildFragment): Promise<void>;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.runBuildAndSubmitAsync = void 0;
|
|
3
|
+
exports.downloadAndRunAsync = exports.runBuildAndSubmitAsync = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const eas_build_job_1 = require("@expo/eas-build-job");
|
|
6
6
|
const eas_json_1 = require("@expo/eas-json");
|
|
7
7
|
const logger_1 = require("@expo/logger");
|
|
8
8
|
const assert_1 = tslib_1.__importDefault(require("assert"));
|
|
9
9
|
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
10
|
+
const fs_extra_1 = require("fs-extra");
|
|
10
11
|
const nullthrows_1 = tslib_1.__importDefault(require("nullthrows"));
|
|
11
12
|
const build_1 = require("./android/build");
|
|
12
13
|
const build_2 = require("./build");
|
|
@@ -340,9 +341,17 @@ function exitWithNonZeroCodeIfSomeBuildsFailed(maybeBuilds) {
|
|
|
340
341
|
}
|
|
341
342
|
async function downloadAndRunAsync(build) {
|
|
342
343
|
(0, assert_1.default)(build.artifacts?.applicationArchiveUrl);
|
|
343
|
-
const
|
|
344
|
+
const cachedAppPath = (0, run_1.getEasBuildRunCachedAppPath)(build.project.id, build.id, build.platform);
|
|
345
|
+
if (await (0, fs_extra_1.pathExists)(cachedAppPath)) {
|
|
346
|
+
log_1.default.newLine();
|
|
347
|
+
log_1.default.log(`Using cached app...`);
|
|
348
|
+
await (0, run_1.runAsync)(cachedAppPath, build.platform);
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
const buildPath = await (0, download_1.downloadAndMaybeExtractAppAsync)(build.artifacts.applicationArchiveUrl, build.platform, cachedAppPath);
|
|
344
352
|
await (0, run_1.runAsync)(buildPath, build.platform);
|
|
345
353
|
}
|
|
354
|
+
exports.downloadAndRunAsync = downloadAndRunAsync;
|
|
346
355
|
async function maybeDownloadAndRunSimulatorBuildsAsync(builds, flags, autoConfirm) {
|
|
347
356
|
const simBuilds = builds.filter(filter_1.truthy).filter(utils_1.isRunnableOnSimulatorOrEmulator);
|
|
348
357
|
if (simBuilds.length > 0 && !flags.autoSubmit && !flags.nonInteractive) {
|
|
@@ -16,8 +16,6 @@ const log_1 = tslib_1.__importDefault(require("../../log"));
|
|
|
16
16
|
const platform_1 = require("../../platform");
|
|
17
17
|
const workflow_1 = require("../../project/workflow");
|
|
18
18
|
const prompts_1 = require("../../prompts");
|
|
19
|
-
const run_1 = require("../../run/run");
|
|
20
|
-
const download_1 = require("../../utils/download");
|
|
21
19
|
const fingerprintCli_1 = require("../../utils/fingerprintCli");
|
|
22
20
|
const profiles_1 = require("../../utils/profiles");
|
|
23
21
|
const DEFAULT_EAS_BUILD_RUN_PROFILE_NAME = 'development-simulator';
|
|
@@ -84,25 +82,17 @@ class BuildDev extends EasCommand_1.default {
|
|
|
84
82
|
}
|
|
85
83
|
log_1.default.log(`✨ Calculated fingerprint hash: ${fingerprint.hash}`);
|
|
86
84
|
log_1.default.newLine();
|
|
87
|
-
const builds = await
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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,
|
|
85
|
+
const builds = await this.getBuildsAsync({
|
|
86
|
+
graphqlClient,
|
|
87
|
+
projectId,
|
|
88
|
+
platform,
|
|
89
|
+
fingerprint,
|
|
99
90
|
});
|
|
100
91
|
if (builds.length !== 0) {
|
|
101
92
|
const build = builds[0];
|
|
102
93
|
log_1.default.succeed(`🎯 Found successful build with matching fingerprint on EAS servers. Running it...`);
|
|
103
94
|
if (build.artifacts?.applicationArchiveUrl) {
|
|
104
|
-
|
|
105
|
-
await (0, run_1.runAsync)(buildPath, build.platform);
|
|
95
|
+
await (0, runBuildAndSubmit_1.downloadAndRunAsync)(build);
|
|
106
96
|
return;
|
|
107
97
|
}
|
|
108
98
|
else {
|
|
@@ -110,6 +100,15 @@ class BuildDev extends EasCommand_1.default {
|
|
|
110
100
|
}
|
|
111
101
|
}
|
|
112
102
|
log_1.default.log('🚀 No successful build with matching fingerprint found. Starting a new build...');
|
|
103
|
+
const previousBuildsForSelectedProfile = await this.getBuildsAsync({
|
|
104
|
+
graphqlClient,
|
|
105
|
+
projectId,
|
|
106
|
+
platform,
|
|
107
|
+
});
|
|
108
|
+
if (previousBuildsForSelectedProfile.length > 0 &&
|
|
109
|
+
previousBuildsForSelectedProfile[0].metrics?.buildDuration) {
|
|
110
|
+
log_1.default.log(`🕒 Previous build for "${buildProfile.profileName}" profile completed in ${Math.floor(previousBuildsForSelectedProfile[0].metrics.buildDuration / 60000)} minutes.`);
|
|
111
|
+
}
|
|
113
112
|
await (0, runBuildAndSubmit_1.runBuildAndSubmitAsync)({
|
|
114
113
|
graphqlClient,
|
|
115
114
|
analytics,
|
|
@@ -221,5 +220,20 @@ class BuildDev extends EasCommand_1.default {
|
|
|
221
220
|
});
|
|
222
221
|
return buildProfile;
|
|
223
222
|
}
|
|
223
|
+
async getBuildsAsync({ graphqlClient, projectId, platform, fingerprint, }) {
|
|
224
|
+
return await BuildQuery_1.BuildQuery.viewBuildsOnAppAsync(graphqlClient, {
|
|
225
|
+
appId: projectId,
|
|
226
|
+
filter: {
|
|
227
|
+
platform: (0, AppPlatform_1.toAppPlatform)(platform),
|
|
228
|
+
fingerprintHash: fingerprint?.hash,
|
|
229
|
+
status: generated_1.BuildStatus.Finished,
|
|
230
|
+
simulator: platform === eas_build_job_1.Platform.IOS ? true : undefined,
|
|
231
|
+
distribution: platform === eas_build_job_1.Platform.ANDROID ? generated_1.DistributionType.Internal : undefined,
|
|
232
|
+
developmentClient: true,
|
|
233
|
+
},
|
|
234
|
+
offset: 0,
|
|
235
|
+
limit: 1,
|
|
236
|
+
});
|
|
237
|
+
}
|
|
224
238
|
}
|
|
225
239
|
exports.default = BuildDev;
|
|
@@ -7,8 +7,7 @@ const local_1 = require("../../build/local");
|
|
|
7
7
|
const runBuildAndSubmit_1 = require("../../build/runBuildAndSubmit");
|
|
8
8
|
const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
|
|
9
9
|
const json_1 = require("../../utils/json");
|
|
10
|
-
const
|
|
11
|
-
const noVcs_1 = tslib_1.__importDefault(require("../../vcs/clients/noVcs"));
|
|
10
|
+
const git_1 = tslib_1.__importDefault(require("../../vcs/clients/git"));
|
|
12
11
|
/**
|
|
13
12
|
* This command will be run on the EAS Build workers, when building
|
|
14
13
|
* directly from git. This command resolves credentials and other
|
|
@@ -52,9 +51,14 @@ class BuildInternal extends EasCommand_1.default {
|
|
|
52
51
|
(0, json_1.enableJsonOutput)();
|
|
53
52
|
const { loggedIn: { actor, graphqlClient }, getDynamicPrivateProjectConfigAsync, projectDir, analytics, vcsClient, } = await this.getContextAsync(BuildInternal, {
|
|
54
53
|
nonInteractive: true,
|
|
55
|
-
vcsClientOverride: process.env.EAS_NO_VCS ? new noVcs_1.default() : new gitNoCommit_1.default(),
|
|
56
54
|
withServerSideEnvironment: null,
|
|
57
55
|
});
|
|
56
|
+
if (vcsClient instanceof git_1.default) {
|
|
57
|
+
// `build:internal` is run on EAS workers and the repo may have been changed
|
|
58
|
+
// by pre-install hooks or other scripts. We don't want to require committing changes
|
|
59
|
+
// to continue the build.
|
|
60
|
+
vcsClient.requireCommit = false;
|
|
61
|
+
}
|
|
58
62
|
await (0, _1.handleDeprecatedEasJsonAsync)(projectDir, flags.nonInteractive);
|
|
59
63
|
await (0, runBuildAndSubmit_1.runBuildAndSubmitAsync)({
|
|
60
64
|
graphqlClient,
|
|
@@ -4,7 +4,6 @@ const tslib_1 = require("tslib");
|
|
|
4
4
|
const core_1 = require("@oclif/core");
|
|
5
5
|
const assert_1 = tslib_1.__importDefault(require("assert"));
|
|
6
6
|
const fs_extra_1 = require("fs-extra");
|
|
7
|
-
const path_1 = tslib_1.__importDefault(require("path"));
|
|
8
7
|
const queries_1 = require("../../build/queries");
|
|
9
8
|
const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
|
|
10
9
|
const pagination_1 = require("../../commandUtils/pagination");
|
|
@@ -17,7 +16,6 @@ const prompts_1 = require("../../prompts");
|
|
|
17
16
|
const run_1 = require("../../run/run");
|
|
18
17
|
const utils_1 = require("../../run/utils");
|
|
19
18
|
const download_1 = require("../../utils/download");
|
|
20
|
-
const paths_1 = require("../../utils/paths");
|
|
21
19
|
class Run extends EasCommand_1.default {
|
|
22
20
|
static description = 'run simulator/emulator builds from eas-cli';
|
|
23
21
|
static flags = {
|
|
@@ -167,13 +165,10 @@ async function maybeGetBuildAsync(graphqlClient, flags, projectId, paginatedQuer
|
|
|
167
165
|
return null;
|
|
168
166
|
}
|
|
169
167
|
}
|
|
170
|
-
function getEasBuildRunCachedAppPath(projectId, buildId, platform) {
|
|
171
|
-
return path_1.default.join((0, paths_1.getEasBuildRunCacheDirectoryPath)(), `${projectId}_${buildId}.${platform === generated_1.AppPlatform.Ios ? 'app' : 'apk'}`);
|
|
172
|
-
}
|
|
173
168
|
async function getPathToSimulatorBuildAppAsync(graphqlClient, projectId, flags, queryOptions) {
|
|
174
169
|
const maybeBuild = await maybeGetBuildAsync(graphqlClient, flags, projectId, queryOptions);
|
|
175
170
|
if (maybeBuild) {
|
|
176
|
-
const cachedAppPath = getEasBuildRunCachedAppPath(projectId, maybeBuild.id, flags.selectedPlatform);
|
|
171
|
+
const cachedAppPath = (0, run_1.getEasBuildRunCachedAppPath)(projectId, maybeBuild.id, flags.selectedPlatform);
|
|
177
172
|
if (await (0, fs_extra_1.pathExists)(cachedAppPath)) {
|
|
178
173
|
log_1.default.newLine();
|
|
179
174
|
log_1.default.log(`Using cached app...`);
|
|
@@ -2,13 +2,6 @@ import EasCommand from '../../commandUtils/EasCommand';
|
|
|
2
2
|
import { ExpoGraphqlClient } from '../../commandUtils/context/contextUtils/createGraphqlClient';
|
|
3
3
|
import { BuildStatus } from '../../graphql/generated';
|
|
4
4
|
import { RequestedPlatform } from '../../platform';
|
|
5
|
-
export interface FingerprintCompareFlags {
|
|
6
|
-
buildId?: string;
|
|
7
|
-
hash1?: string;
|
|
8
|
-
hash2?: string;
|
|
9
|
-
nonInteractive: boolean;
|
|
10
|
-
json: boolean;
|
|
11
|
-
}
|
|
12
5
|
export default class FingerprintCompare extends EasCommand {
|
|
13
6
|
static description: string;
|
|
14
7
|
static strict: boolean;
|
|
@@ -21,7 +14,8 @@ export default class FingerprintCompare extends EasCommand {
|
|
|
21
14
|
static flags: {
|
|
22
15
|
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
23
16
|
'non-interactive': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
24
|
-
'build-id': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined>;
|
|
17
|
+
'build-id': import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined>;
|
|
18
|
+
'update-id': import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined>;
|
|
25
19
|
};
|
|
26
20
|
static contextDefinition: {
|
|
27
21
|
vcsClient: import("../../commandUtils/context/VcsClientContextField").default;
|
|
@@ -5,19 +5,24 @@ const tslib_1 = require("tslib");
|
|
|
5
5
|
const eas_build_job_1 = require("@expo/eas-build-job");
|
|
6
6
|
const core_1 = require("@oclif/core");
|
|
7
7
|
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
8
|
+
const api_1 = require("../../api");
|
|
9
|
+
const queries_1 = require("../../branch/queries");
|
|
8
10
|
const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
|
|
9
11
|
const builds_1 = require("../../commandUtils/builds");
|
|
10
12
|
const flags_1 = require("../../commandUtils/flags");
|
|
11
13
|
const generated_1 = require("../../graphql/generated");
|
|
12
14
|
const FingerprintMutation_1 = require("../../graphql/mutations/FingerprintMutation");
|
|
15
|
+
const AppQuery_1 = require("../../graphql/queries/AppQuery");
|
|
13
16
|
const BuildQuery_1 = require("../../graphql/queries/BuildQuery");
|
|
14
17
|
const FingerprintQuery_1 = require("../../graphql/queries/FingerprintQuery");
|
|
18
|
+
const UpdateQuery_1 = require("../../graphql/queries/UpdateQuery");
|
|
15
19
|
const log_1 = tslib_1.__importDefault(require("../../log"));
|
|
16
20
|
const ora_1 = require("../../ora");
|
|
17
21
|
const maybeUploadFingerprintAsync_1 = require("../../project/maybeUploadFingerprintAsync");
|
|
18
22
|
const projectUtils_1 = require("../../project/projectUtils");
|
|
19
23
|
const workflow_1 = require("../../project/workflow");
|
|
20
24
|
const prompts_1 = require("../../prompts");
|
|
25
|
+
const queries_2 = require("../../update/queries");
|
|
21
26
|
const fingerprintCli_1 = require("../../utils/fingerprintCli");
|
|
22
27
|
const fingerprintDiff_1 = require("../../utils/fingerprintDiff");
|
|
23
28
|
const formatFields_1 = tslib_1.__importDefault(require("../../utils/formatFields"));
|
|
@@ -25,6 +30,7 @@ const json_1 = require("../../utils/json");
|
|
|
25
30
|
var FingerprintOriginType;
|
|
26
31
|
(function (FingerprintOriginType) {
|
|
27
32
|
FingerprintOriginType["Build"] = "build";
|
|
33
|
+
FingerprintOriginType["Update"] = "update";
|
|
28
34
|
FingerprintOriginType["Hash"] = "hash";
|
|
29
35
|
FingerprintOriginType["Project"] = "project";
|
|
30
36
|
})(FingerprintOriginType || (FingerprintOriginType = {}));
|
|
@@ -33,9 +39,12 @@ class FingerprintCompare extends EasCommand_1.default {
|
|
|
33
39
|
static strict = false;
|
|
34
40
|
static examples = [
|
|
35
41
|
'$ eas fingerprint:compare \t # Compare fingerprints in interactive mode',
|
|
36
|
-
'$ eas fingerprint:compare
|
|
37
|
-
'$ eas fingerprint:compare
|
|
38
|
-
'$ eas fingerprint:compare --build-id
|
|
42
|
+
'$ eas fingerprint:compare <FINGERPRINT-HASH> \t # Compare fingerprint against local directory',
|
|
43
|
+
'$ eas fingerprint:compare <FINGERPRINT-HASH-1> <FINGERPRINT-HASH-2> \t # Compare provided fingerprints',
|
|
44
|
+
'$ eas fingerprint:compare --build-id <BUILD-ID> \t # Compare fingerprint from build against local directory',
|
|
45
|
+
'$ eas fingerprint:compare --build-id <BUILD-ID-1> --build-id <BUILD-ID-2>\t # Compare fingerprint from a build against another build',
|
|
46
|
+
'$ eas fingerprint:compare --build-id <BUILD-ID> --update-id <UPDATE-ID>\t # Compare fingerprint from build against fingerprint from update',
|
|
47
|
+
'$ eas fingerprint:compare <FINGERPRINT-HASH> --update-id <UPDATE-ID> \t # Compare fingerprint from update against provided fingerprint',
|
|
39
48
|
];
|
|
40
49
|
static args = [
|
|
41
50
|
{
|
|
@@ -53,6 +62,12 @@ class FingerprintCompare extends EasCommand_1.default {
|
|
|
53
62
|
'build-id': core_1.Flags.string({
|
|
54
63
|
aliases: ['buildId'],
|
|
55
64
|
description: 'Compare the fingerprint with the build with the specified ID',
|
|
65
|
+
multiple: true,
|
|
66
|
+
}),
|
|
67
|
+
'update-id': core_1.Flags.string({
|
|
68
|
+
aliases: ['updateId'],
|
|
69
|
+
description: 'Compare the fingerprint with the update with the specified ID',
|
|
70
|
+
multiple: true,
|
|
56
71
|
}),
|
|
57
72
|
...flags_1.EasNonInteractiveAndJsonFlags,
|
|
58
73
|
};
|
|
@@ -65,8 +80,9 @@ class FingerprintCompare extends EasCommand_1.default {
|
|
|
65
80
|
async runAsync() {
|
|
66
81
|
const { args, flags } = await this.parse(FingerprintCompare);
|
|
67
82
|
const { hash1, hash2 } = args;
|
|
68
|
-
const { json, 'non-interactive': nonInteractive, 'build-id':
|
|
69
|
-
const
|
|
83
|
+
const { json, 'non-interactive': nonInteractive, 'build-id': buildIds, 'update-id': updateIds, } = flags;
|
|
84
|
+
const [buildId1, buildId2] = buildIds ?? [];
|
|
85
|
+
const [updateId1, updateId2] = updateIds ?? [];
|
|
70
86
|
const { projectId, privateProjectConfig: { projectDir }, loggedIn: { graphqlClient }, vcsClient, } = await this.getContextAsync(FingerprintCompare, {
|
|
71
87
|
nonInteractive,
|
|
72
88
|
withServerSideEnvironment: null,
|
|
@@ -74,16 +90,29 @@ class FingerprintCompare extends EasCommand_1.default {
|
|
|
74
90
|
if (json) {
|
|
75
91
|
(0, json_1.enableJsonOutput)();
|
|
76
92
|
}
|
|
77
|
-
const firstFingerprintInfo = await
|
|
93
|
+
const firstFingerprintInfo = await getFingerprintInfoAsync(graphqlClient, projectDir, projectId, vcsClient, {
|
|
94
|
+
nonInteractive,
|
|
95
|
+
buildId: buildId1,
|
|
96
|
+
updateId: updateId1,
|
|
97
|
+
hash: hash1,
|
|
98
|
+
});
|
|
78
99
|
const { fingerprint: firstFingerprint, origin: firstFingerprintOrigin } = firstFingerprintInfo;
|
|
79
|
-
const
|
|
100
|
+
const isFirstFingerprintSpecifiedByFlagOrArg = hash1 || buildId1 || updateId1;
|
|
101
|
+
const isSecondFingerprintSpecifiedByFlagOrArg = hash2 || buildId2 || updateId2;
|
|
102
|
+
const secondFingerprintInfo = await getFingerprintInfoAsync(graphqlClient, projectDir, projectId, vcsClient, {
|
|
103
|
+
nonInteractive,
|
|
104
|
+
buildId: buildId2,
|
|
105
|
+
updateId: updateId2,
|
|
106
|
+
hash: hash2,
|
|
107
|
+
useProjectFingerprint: isFirstFingerprintSpecifiedByFlagOrArg && !isSecondFingerprintSpecifiedByFlagOrArg,
|
|
108
|
+
}, firstFingerprintInfo);
|
|
80
109
|
const { fingerprint: secondFingerprint, origin: secondFingerprintOrigin } = secondFingerprintInfo;
|
|
81
110
|
if (json) {
|
|
82
111
|
(0, json_1.printJsonOnlyOutput)({ fingerprint1: firstFingerprint, fingerprint2: secondFingerprint });
|
|
83
112
|
return;
|
|
84
113
|
}
|
|
85
114
|
if (firstFingerprint.hash === secondFingerprint.hash) {
|
|
86
|
-
log_1.default.log(`✅ ${capitalizeFirstLetter(prettyPrintFingerprint(firstFingerprint, firstFingerprintOrigin))} matches
|
|
115
|
+
log_1.default.log(`✅ ${capitalizeFirstLetter(prettyPrintFingerprint(firstFingerprint, firstFingerprintOrigin))} matches ${prettyPrintFingerprint(secondFingerprint, secondFingerprintOrigin)}`);
|
|
87
116
|
return;
|
|
88
117
|
}
|
|
89
118
|
else {
|
|
@@ -141,77 +170,95 @@ class FingerprintCompare extends EasCommand_1.default {
|
|
|
141
170
|
}
|
|
142
171
|
}
|
|
143
172
|
exports.default = FingerprintCompare;
|
|
144
|
-
function
|
|
145
|
-
if (
|
|
146
|
-
return
|
|
173
|
+
async function getFingerprintInfoAsync(graphqlClient, projectDir, projectId, vcsClient, { buildId, updateId, hash, useProjectFingerprint, nonInteractive, }, firstFingerprintInfo) {
|
|
174
|
+
if (hash) {
|
|
175
|
+
return await getFingerprintInfoFromHashAsync(graphqlClient, projectId, hash);
|
|
147
176
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
if (
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
let platforms;
|
|
158
|
-
const fingerprintBuilds = fingerprintFragment.builds?.edges.map(edge => edge.node) ?? [];
|
|
159
|
-
const fingerprintUpdates = fingerprintFragment.updates?.edges.map(edge => edge.node) ?? [];
|
|
160
|
-
if (fingerprintBuilds.length > 0) {
|
|
161
|
-
platforms = [fingerprintBuilds[0].platform];
|
|
162
|
-
}
|
|
163
|
-
else if (fingerprintUpdates.length > 0) {
|
|
164
|
-
platforms = [stringToAppPlatform(fingerprintUpdates[0].platform)];
|
|
177
|
+
else if (updateId) {
|
|
178
|
+
return await getFingerprintInfoFromUpdateGroupIdOrUpdateIdAsync(graphqlClient, projectId, nonInteractive, updateId);
|
|
179
|
+
}
|
|
180
|
+
else if (buildId) {
|
|
181
|
+
return await getFingerprintInfoFromBuildIdAsync(graphqlClient, buildId);
|
|
182
|
+
}
|
|
183
|
+
else if (useProjectFingerprint) {
|
|
184
|
+
if (!firstFingerprintInfo) {
|
|
185
|
+
throw new Error('First fingerprint must be provided in order to compare against the project.');
|
|
165
186
|
}
|
|
166
|
-
return
|
|
167
|
-
fingerprint,
|
|
168
|
-
platforms,
|
|
169
|
-
origin: {
|
|
170
|
-
type: FingerprintOriginType.Hash,
|
|
171
|
-
},
|
|
172
|
-
};
|
|
187
|
+
return await getFingerprintInfoFromLocalProjectAsync(graphqlClient, projectDir, projectId, vcsClient, firstFingerprintInfo);
|
|
173
188
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
189
|
+
if (nonInteractive) {
|
|
190
|
+
throw new Error('Insufficent arguments provided for fingerprint comparison in non-interactive mode');
|
|
191
|
+
}
|
|
192
|
+
return await getFingerprintInfoInteractiveAsync(graphqlClient, projectDir, projectId, vcsClient, firstFingerprintInfo);
|
|
193
|
+
}
|
|
194
|
+
async function getFingerprintInfoInteractiveAsync(graphqlClient, projectDir, projectId, vcsClient, firstFingerprintInfo) {
|
|
195
|
+
const prompt = firstFingerprintInfo
|
|
196
|
+
? 'Select the second fingerprint to compare against'
|
|
197
|
+
: 'Select a reference fingerprint for comparison';
|
|
198
|
+
const originType = await (0, prompts_1.selectAsync)(prompt, [
|
|
199
|
+
...(firstFingerprintInfo
|
|
200
|
+
? [{ title: 'Current project fingerprint', value: FingerprintOriginType.Project }]
|
|
201
|
+
: []),
|
|
202
|
+
{ title: 'Build fingerprint', value: FingerprintOriginType.Build },
|
|
203
|
+
{ title: 'Update fingerprint', value: FingerprintOriginType.Update },
|
|
204
|
+
{ title: 'Enter a fingerprint hash manually', value: FingerprintOriginType.Hash },
|
|
205
|
+
]);
|
|
206
|
+
if (originType === FingerprintOriginType.Project) {
|
|
207
|
+
if (!firstFingerprintInfo) {
|
|
208
|
+
throw new Error('First fingerprint must be provided in order to compare against the project.');
|
|
178
209
|
}
|
|
210
|
+
return await getFingerprintInfoFromLocalProjectAsync(graphqlClient, projectDir, projectId, vcsClient, firstFingerprintInfo);
|
|
211
|
+
}
|
|
212
|
+
else if (originType === FingerprintOriginType.Build) {
|
|
179
213
|
const displayName = await (0, projectUtils_1.getDisplayNameForProjectIdAsync)(graphqlClient, projectId);
|
|
180
|
-
buildId = await selectBuildToCompareAsync(graphqlClient, projectId, displayName, {
|
|
214
|
+
const buildId = await selectBuildToCompareAsync(graphqlClient, projectId, displayName, {
|
|
181
215
|
filters: { hasFingerprint: true },
|
|
182
216
|
});
|
|
183
217
|
if (!buildId) {
|
|
184
218
|
throw new Error('Must select build with fingerprint for comparison.');
|
|
185
219
|
}
|
|
220
|
+
return await getFingerprintInfoFromBuildIdAsync(graphqlClient, buildId);
|
|
221
|
+
}
|
|
222
|
+
else if (originType === FingerprintOriginType.Update) {
|
|
223
|
+
const selectedBranch = await (0, queries_1.selectBranchOnAppAsync)(graphqlClient, {
|
|
224
|
+
projectId,
|
|
225
|
+
promptTitle: 'On which branch would you like search for an update?',
|
|
226
|
+
displayTextForListItem: updateBranch => ({
|
|
227
|
+
title: updateBranch.name,
|
|
228
|
+
}),
|
|
229
|
+
paginatedQueryOptions: {
|
|
230
|
+
json: false,
|
|
231
|
+
nonInteractive: false,
|
|
232
|
+
offset: 0,
|
|
233
|
+
},
|
|
234
|
+
});
|
|
235
|
+
const selectedUpdateGroup = await (0, queries_2.selectUpdateGroupOnBranchAsync)(graphqlClient, {
|
|
236
|
+
projectId,
|
|
237
|
+
branchName: selectedBranch.name,
|
|
238
|
+
paginatedQueryOptions: {
|
|
239
|
+
json: false,
|
|
240
|
+
nonInteractive: false,
|
|
241
|
+
offset: 0,
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
const updateGroupId = selectedUpdateGroup[0].group;
|
|
245
|
+
return await getFingerprintInfoFromUpdateGroupIdOrUpdateIdAsync(graphqlClient, projectId, false, updateGroupId);
|
|
246
|
+
}
|
|
247
|
+
else if (originType === FingerprintOriginType.Hash) {
|
|
248
|
+
const { hash } = await (0, prompts_1.promptAsync)({
|
|
249
|
+
type: 'text',
|
|
250
|
+
name: 'hash',
|
|
251
|
+
message: 'Provide the fingerprint hash',
|
|
252
|
+
validate: (value) => !!value.trim(),
|
|
253
|
+
hint: '0000000000000000000000000000000000000000',
|
|
254
|
+
});
|
|
255
|
+
return await getFingerprintInfoFromHashAsync(graphqlClient, projectId, hash);
|
|
186
256
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
if (!buildWithFingerprint.fingerprint) {
|
|
190
|
-
throw new Error(`Fingerprint for build ${buildId} was not computed.`);
|
|
191
|
-
}
|
|
192
|
-
else if (!buildWithFingerprint.fingerprint.debugInfoUrl) {
|
|
193
|
-
throw new Error(`Fingerprint source for build ${buildId} was not computed.`);
|
|
257
|
+
else {
|
|
258
|
+
throw new Error(`Unsupported fingerprint origin type: ${originType}`);
|
|
194
259
|
}
|
|
195
|
-
return {
|
|
196
|
-
fingerprint: await getFingerprintFromFingerprintFragmentAsync(buildWithFingerprint.fingerprint),
|
|
197
|
-
platforms: [buildWithFingerprint.platform],
|
|
198
|
-
origin: {
|
|
199
|
-
type: FingerprintOriginType.Build,
|
|
200
|
-
build: buildWithFingerprint,
|
|
201
|
-
},
|
|
202
|
-
};
|
|
203
260
|
}
|
|
204
|
-
async function
|
|
205
|
-
if (hash2) {
|
|
206
|
-
const fingerprintFragment = await getFingerprintFragmentFromHashAsync(graphqlClient, projectId, hash2);
|
|
207
|
-
if (!fingerprintFragment) {
|
|
208
|
-
throw new Error(`Fingerprint with hash ${hash2} was not uploaded.`);
|
|
209
|
-
}
|
|
210
|
-
return {
|
|
211
|
-
fingerprint: await getFingerprintFromFingerprintFragmentAsync(fingerprintFragment),
|
|
212
|
-
origin: { type: FingerprintOriginType.Hash },
|
|
213
|
-
};
|
|
214
|
-
}
|
|
261
|
+
async function getFingerprintInfoFromLocalProjectAsync(graphqlClient, projectDir, projectId, vcsClient, firstFingerprintInfo) {
|
|
215
262
|
const firstFingerprintPlatforms = firstFingerprintInfo.platforms;
|
|
216
263
|
if (!firstFingerprintPlatforms) {
|
|
217
264
|
throw new Error(`Cannot compare the local directory against the provided fingerprint hash "${firstFingerprintInfo.fingerprint.hash}" because the associated platform could not be determined. Ensure the fingerprint is linked to a build or update to identify the platform.`);
|
|
@@ -241,6 +288,96 @@ async function getSecondFingerprintInfoAsync(graphqlClient, projectDir, projectI
|
|
|
241
288
|
});
|
|
242
289
|
return { fingerprint: projectFingerprint, origin: { type: FingerprintOriginType.Project } };
|
|
243
290
|
}
|
|
291
|
+
async function getFingerprintFromUpdateFragmentAsync(updateWithFingerprint) {
|
|
292
|
+
if (!updateWithFingerprint.fingerprint) {
|
|
293
|
+
throw new Error(`Fingerprint for update ${updateWithFingerprint.id} was not computed.`);
|
|
294
|
+
}
|
|
295
|
+
else if (!updateWithFingerprint.fingerprint.debugInfoUrl) {
|
|
296
|
+
throw new Error(`Fingerprint source for update ${updateWithFingerprint.id} was not computed.`);
|
|
297
|
+
}
|
|
298
|
+
return {
|
|
299
|
+
fingerprint: await getFingerprintFromFingerprintFragmentAsync(updateWithFingerprint.fingerprint),
|
|
300
|
+
platforms: [stringToAppPlatform(updateWithFingerprint.platform)],
|
|
301
|
+
origin: {
|
|
302
|
+
type: FingerprintOriginType.Update,
|
|
303
|
+
update: updateWithFingerprint,
|
|
304
|
+
},
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
async function getFingerprintInfoFromHashAsync(graphqlClient, projectId, hash) {
|
|
308
|
+
const fingerprintFragment = await getFingerprintFragmentFromHashAsync(graphqlClient, projectId, hash);
|
|
309
|
+
const fingerprint = await getFingerprintFromFingerprintFragmentAsync(fingerprintFragment);
|
|
310
|
+
let platforms;
|
|
311
|
+
const fingerprintBuilds = fingerprintFragment.builds?.edges.map(edge => edge.node) ?? [];
|
|
312
|
+
const fingerprintUpdates = fingerprintFragment.updates?.edges.map(edge => edge.node) ?? [];
|
|
313
|
+
if (fingerprintBuilds.length > 0) {
|
|
314
|
+
platforms = [fingerprintBuilds[0].platform];
|
|
315
|
+
}
|
|
316
|
+
else if (fingerprintUpdates.length > 0) {
|
|
317
|
+
platforms = [stringToAppPlatform(fingerprintUpdates[0].platform)];
|
|
318
|
+
}
|
|
319
|
+
return {
|
|
320
|
+
fingerprint,
|
|
321
|
+
platforms,
|
|
322
|
+
origin: {
|
|
323
|
+
type: FingerprintOriginType.Hash,
|
|
324
|
+
},
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
async function getFingerprintInfoFromUpdateGroupIdOrUpdateIdAsync(graphqlClient, projectId, nonInteractive, updateGroupIdOrUpdateId) {
|
|
328
|
+
// Some people may pass in update group id instead of update id, so add interactive support for that
|
|
329
|
+
try {
|
|
330
|
+
const maybeUpdateGroupId = updateGroupIdOrUpdateId;
|
|
331
|
+
const updateGroup = await UpdateQuery_1.UpdateQuery.viewUpdateGroupAsync(graphqlClient, {
|
|
332
|
+
groupId: maybeUpdateGroupId,
|
|
333
|
+
});
|
|
334
|
+
if (updateGroup.length === 1) {
|
|
335
|
+
const update = updateGroup[0];
|
|
336
|
+
return await getFingerprintFromUpdateFragmentAsync(update);
|
|
337
|
+
}
|
|
338
|
+
if (nonInteractive) {
|
|
339
|
+
const [accountName, project] = await Promise.all([
|
|
340
|
+
(await (0, projectUtils_1.getOwnerAccountForProjectIdAsync)(graphqlClient, projectId)).name,
|
|
341
|
+
AppQuery_1.AppQuery.byIdAsync(graphqlClient, projectId),
|
|
342
|
+
]);
|
|
343
|
+
const updateUrl = (0, api_1.getExpoWebsiteBaseUrl)() +
|
|
344
|
+
`/accounts/${accountName}/projects/${project.name}/updates/${maybeUpdateGroupId}`;
|
|
345
|
+
throw new Error(`Please pass in your update ID from ${updateUrl} or use interactive mode to select the update ID.`);
|
|
346
|
+
}
|
|
347
|
+
const update = await (0, prompts_1.selectAsync)('Select a platform to compute the fingerprint from', updateGroup.map(update => ({
|
|
348
|
+
title: update.platform,
|
|
349
|
+
value: update,
|
|
350
|
+
})));
|
|
351
|
+
return await getFingerprintFromUpdateFragmentAsync(update);
|
|
352
|
+
}
|
|
353
|
+
catch (error) {
|
|
354
|
+
if (!error?.message.includes('Could not find any updates with group ID')) {
|
|
355
|
+
throw error;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
const updateId = updateGroupIdOrUpdateId;
|
|
359
|
+
const updateWithFingerprint = await UpdateQuery_1.UpdateQuery.viewByUpdateAsync(graphqlClient, {
|
|
360
|
+
updateId,
|
|
361
|
+
});
|
|
362
|
+
return await getFingerprintFromUpdateFragmentAsync(updateWithFingerprint);
|
|
363
|
+
}
|
|
364
|
+
async function getFingerprintInfoFromBuildIdAsync(graphqlClient, buildId) {
|
|
365
|
+
const buildWithFingerprint = await BuildQuery_1.BuildQuery.withFingerprintByIdAsync(graphqlClient, buildId);
|
|
366
|
+
if (!buildWithFingerprint.fingerprint) {
|
|
367
|
+
throw new Error(`Fingerprint for build ${buildId} was not computed.`);
|
|
368
|
+
}
|
|
369
|
+
else if (!buildWithFingerprint.fingerprint.debugInfoUrl) {
|
|
370
|
+
throw new Error(`Fingerprint source for build ${buildId} was not computed.`);
|
|
371
|
+
}
|
|
372
|
+
return {
|
|
373
|
+
fingerprint: await getFingerprintFromFingerprintFragmentAsync(buildWithFingerprint.fingerprint),
|
|
374
|
+
platforms: [buildWithFingerprint.platform],
|
|
375
|
+
origin: {
|
|
376
|
+
type: FingerprintOriginType.Build,
|
|
377
|
+
build: buildWithFingerprint,
|
|
378
|
+
},
|
|
379
|
+
};
|
|
380
|
+
}
|
|
244
381
|
async function getFingerprintFragmentFromHashAsync(graphqlClient, projectId, hash) {
|
|
245
382
|
const fingerprint = await FingerprintQuery_1.FingerprintQuery.byHashAsync(graphqlClient, {
|
|
246
383
|
appId: projectId,
|
|
@@ -412,6 +549,21 @@ function printContentsDiff(contents1, contents2) {
|
|
|
412
549
|
: stringifiedContents2;
|
|
413
550
|
(0, fingerprintDiff_1.abridgedDiff)(prettifiedContents1, prettifiedContents2, 0);
|
|
414
551
|
}
|
|
552
|
+
function prettyPrintFingerprint(fingerprint, origin) {
|
|
553
|
+
if (origin.type === FingerprintOriginType.Project) {
|
|
554
|
+
return `fingerprint ${fingerprint.hash} from local directory`;
|
|
555
|
+
}
|
|
556
|
+
else if (origin.type === FingerprintOriginType.Update) {
|
|
557
|
+
return `fingerprint ${fingerprint.hash} from ${origin.update?.platform ? stringToAppPlatform(origin.update?.platform) : ''} ${origin.type}`;
|
|
558
|
+
}
|
|
559
|
+
else if (origin.type === FingerprintOriginType.Build) {
|
|
560
|
+
return `fingerprint ${fingerprint.hash} from ${origin.build?.platform} ${origin.type}`;
|
|
561
|
+
}
|
|
562
|
+
return `fingerprint ${fingerprint.hash}`;
|
|
563
|
+
}
|
|
564
|
+
function capitalizeFirstLetter(string) {
|
|
565
|
+
return string.charAt(0).toUpperCase() + string.slice(1);
|
|
566
|
+
}
|
|
415
567
|
function isJSON(str) {
|
|
416
568
|
try {
|
|
417
569
|
JSON.parse(str);
|
|
@@ -108,7 +108,10 @@ class Onboarding extends EasCommand_1.default {
|
|
|
108
108
|
targetProjectDir: initialTargetProjectDirectory,
|
|
109
109
|
cloneMethod,
|
|
110
110
|
});
|
|
111
|
-
const vcsClient = new git_2.default(
|
|
111
|
+
const vcsClient = new git_2.default({
|
|
112
|
+
maybeCwdOverride: finalTargetProjectDirectory,
|
|
113
|
+
requireCommit: false,
|
|
114
|
+
});
|
|
112
115
|
if (!app.githubRepository) {
|
|
113
116
|
await fs_extra_1.default.remove(path_1.default.join(finalTargetProjectDirectory, '.git'));
|
|
114
117
|
await (0, runCommand_1.runCommandAsync)({
|
|
@@ -13,8 +13,7 @@ const AndroidSubmitCommand_1 = tslib_1.__importDefault(require("../../submit/and
|
|
|
13
13
|
const context_1 = require("../../submit/context");
|
|
14
14
|
const IosSubmitCommand_1 = tslib_1.__importDefault(require("../../submit/ios/IosSubmitCommand"));
|
|
15
15
|
const json_1 = require("../../utils/json");
|
|
16
|
-
const
|
|
17
|
-
const noVcs_1 = tslib_1.__importDefault(require("../../vcs/clients/noVcs"));
|
|
16
|
+
const git_1 = tslib_1.__importDefault(require("../../vcs/clients/git"));
|
|
18
17
|
/**
|
|
19
18
|
* This command will be run on the EAS workers.
|
|
20
19
|
* This command resolves credentials and other
|
|
@@ -49,9 +48,14 @@ class SubmitInternal extends EasCommand_1.default {
|
|
|
49
48
|
(0, json_1.enableJsonOutput)();
|
|
50
49
|
const { loggedIn: { actor, graphqlClient }, privateProjectConfig: { exp, projectId, projectDir }, analytics, vcsClient, } = await this.getContextAsync(SubmitInternal, {
|
|
51
50
|
nonInteractive: true,
|
|
52
|
-
vcsClientOverride: process.env.EAS_NO_VCS ? new noVcs_1.default() : new gitNoCommit_1.default(),
|
|
53
51
|
withServerSideEnvironment: null,
|
|
54
52
|
});
|
|
53
|
+
if (vcsClient instanceof git_1.default) {
|
|
54
|
+
// `build:internal` is run on EAS workers and the repo may have been changed
|
|
55
|
+
// by pre-install hooks or other scripts. We don't want to require committing changes
|
|
56
|
+
// to continue the build.
|
|
57
|
+
vcsClient.requireCommit = false;
|
|
58
|
+
}
|
|
55
59
|
const submissionProfile = await eas_json_1.EasJsonUtils.getSubmitProfileAsync(eas_json_1.EasJsonAccessor.fromProjectPath(projectDir), flags.platform, flags.profile);
|
|
56
60
|
const ctx = await (0, context_1.createSubmissionContextAsync)({
|
|
57
61
|
platform: flags.platform,
|