eas-cli 18.4.0 → 18.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 +92 -90
- package/build/build/android/prepareJob.js +2 -2
- package/build/build/ios/prepareJob.js +2 -2
- package/build/build/metadata.js +2 -1
- package/build/commandUtils/EasCommand.js +23 -2
- package/build/commandUtils/context/contextUtils/getProjectIdAsync.js +2 -0
- package/build/commandUtils/pagination.d.ts +2 -1
- package/build/commandUtils/pagination.js +3 -2
- package/build/commandUtils/workflow/fetchLogs.js +11 -2
- package/build/commandUtils/workflow/types.d.ts +5 -1
- package/build/commandUtils/workflow/utils.js +22 -16
- package/build/commands/deploy/index.js +18 -2
- package/build/commands/metadata/pull.d.ts +1 -0
- package/build/commands/metadata/pull.js +9 -4
- package/build/commands/metadata/push.d.ts +1 -0
- package/build/commands/metadata/push.js +9 -4
- package/build/commands/observe/events.d.ts +27 -0
- package/build/commands/observe/events.js +140 -0
- package/build/commands/observe/metrics.d.ts +21 -0
- package/build/commands/observe/metrics.js +111 -0
- package/build/commands/observe/versions.d.ts +19 -0
- package/build/commands/observe/versions.js +69 -0
- package/build/commands/project/onboarding.js +3 -0
- package/build/commands/workflow/logs.js +12 -12
- package/build/credentials/ios/IosCredentialsProvider.js +8 -4
- package/build/credentials/ios/utils/provisioningProfile.d.ts +1 -0
- package/build/credentials/ios/utils/provisioningProfile.js +15 -1
- package/build/graphql/generated.d.ts +1273 -73
- package/build/graphql/generated.js +59 -19
- package/build/graphql/queries/ObserveQuery.d.ts +35 -0
- package/build/graphql/queries/ObserveQuery.js +109 -0
- package/build/graphql/queries/UserQuery.js +3 -0
- package/build/graphql/types/Observe.d.ts +3 -0
- package/build/graphql/types/Observe.js +84 -0
- package/build/graphql/types/Update.js +3 -0
- package/build/metadata/apple/config/reader.d.ts +13 -1
- package/build/metadata/apple/config/reader.js +33 -0
- package/build/metadata/apple/config/writer.d.ts +11 -1
- package/build/metadata/apple/config/writer.js +57 -0
- package/build/metadata/apple/data.d.ts +7 -2
- package/build/metadata/apple/rules/infoRestrictedWords.js +6 -1
- package/build/metadata/apple/tasks/age-rating.d.ts +1 -1
- package/build/metadata/apple/tasks/age-rating.js +19 -3
- package/build/metadata/apple/tasks/app-clip.d.ts +37 -0
- package/build/metadata/apple/tasks/app-clip.js +404 -0
- package/build/metadata/apple/tasks/app-review-detail.js +7 -2
- package/build/metadata/apple/tasks/index.js +6 -0
- package/build/metadata/apple/tasks/previews.d.ts +18 -0
- package/build/metadata/apple/tasks/previews.js +212 -0
- package/build/metadata/apple/tasks/screenshots.d.ts +18 -0
- package/build/metadata/apple/tasks/screenshots.js +235 -0
- package/build/metadata/apple/types.d.ts +61 -1
- package/build/metadata/auth.d.ts +11 -1
- package/build/metadata/auth.js +96 -2
- package/build/metadata/download.d.ts +5 -1
- package/build/metadata/download.js +16 -8
- package/build/metadata/upload.d.ts +5 -1
- package/build/metadata/upload.js +11 -4
- package/build/observe/fetchEvents.d.ts +27 -0
- package/build/observe/fetchEvents.js +83 -0
- package/build/observe/fetchMetrics.d.ts +11 -0
- package/build/observe/fetchMetrics.js +78 -0
- package/build/observe/fetchVersions.d.ts +7 -0
- package/build/observe/fetchVersions.js +31 -0
- package/build/observe/formatEvents.d.ts +31 -0
- package/build/observe/formatEvents.js +99 -0
- package/build/observe/formatMetrics.d.ts +38 -0
- package/build/observe/formatMetrics.js +206 -0
- package/build/observe/formatVersions.d.ts +32 -0
- package/build/observe/formatVersions.js +92 -0
- package/build/observe/metricNames.d.ts +4 -0
- package/build/observe/metricNames.js +33 -0
- package/build/observe/startAndEndTime.d.ts +18 -0
- package/build/observe/startAndEndTime.js +36 -0
- package/build/project/projectUtils.d.ts +0 -2
- package/build/project/projectUtils.js +0 -12
- package/build/project/workflow.js +1 -1
- package/build/sentry.d.ts +2 -0
- package/build/sentry.js +22 -0
- package/build/update/utils.d.ts +2 -2
- package/build/update/utils.js +1 -0
- package/build/user/SessionManager.js +11 -0
- package/build/user/User.d.ts +2 -2
- package/build/user/User.js +3 -0
- package/build/user/expoBrowserAuthFlowLauncher.js +70 -13
- package/build/worker/upload.js +15 -5
- package/oclif.manifest.json +1794 -1306
- package/package.json +15 -11
- package/schema/metadata-0.json +213 -0
|
@@ -6,13 +6,13 @@ const eas_build_job_1 = require("@expo/eas-build-job");
|
|
|
6
6
|
const path_1 = tslib_1.__importDefault(require("path"));
|
|
7
7
|
const slash_1 = tslib_1.__importDefault(require("slash"));
|
|
8
8
|
const customBuildConfig_1 = require("../../project/customBuildConfig");
|
|
9
|
-
const
|
|
9
|
+
const User_1 = require("../../user/User");
|
|
10
10
|
const cacheDefaults = {
|
|
11
11
|
disabled: false,
|
|
12
12
|
paths: [],
|
|
13
13
|
};
|
|
14
14
|
async function prepareJobAsync(ctx, jobData) {
|
|
15
|
-
const username = (0,
|
|
15
|
+
const username = (0, User_1.getActorUsername)(ctx.user) ?? undefined;
|
|
16
16
|
const buildProfile = ctx.buildProfile;
|
|
17
17
|
const projectRootDirectory = (0, slash_1.default)(path_1.default.relative(await ctx.vcsClient.getRootPathAsync(), ctx.projectDir)) || '.';
|
|
18
18
|
const { credentials } = jobData;
|
|
@@ -8,13 +8,13 @@ const nullthrows_1 = tslib_1.__importDefault(require("nullthrows"));
|
|
|
8
8
|
const path_1 = tslib_1.__importDefault(require("path"));
|
|
9
9
|
const slash_1 = tslib_1.__importDefault(require("slash"));
|
|
10
10
|
const customBuildConfig_1 = require("../../project/customBuildConfig");
|
|
11
|
-
const
|
|
11
|
+
const User_1 = require("../../user/User");
|
|
12
12
|
const cacheDefaults = {
|
|
13
13
|
disabled: false,
|
|
14
14
|
paths: [],
|
|
15
15
|
};
|
|
16
16
|
async function prepareJobAsync(ctx, jobData) {
|
|
17
|
-
const username = (0,
|
|
17
|
+
const username = (0, User_1.getActorUsername)(ctx.user) ?? undefined;
|
|
18
18
|
const buildProfile = ctx.buildProfile;
|
|
19
19
|
const projectRootDirectory = (0, slash_1.default)(path_1.default.relative(await ctx.vcsClient.getRootPathAsync(), ctx.projectDir)) || '.';
|
|
20
20
|
const buildCredentials = {};
|
package/build/build/metadata.js
CHANGED
|
@@ -16,6 +16,7 @@ const projectUtils_1 = require("../project/projectUtils");
|
|
|
16
16
|
const UpdatesModule_1 = require("../update/android/UpdatesModule");
|
|
17
17
|
const UpdatesModule_2 = require("../update/ios/UpdatesModule");
|
|
18
18
|
const easCli_1 = require("../utils/easCli");
|
|
19
|
+
const User_1 = require("../user/User");
|
|
19
20
|
async function collectMetadataAsync(ctx, runtimeAndFingerprintMetadata) {
|
|
20
21
|
const channelObject = await resolveChannelAsync(ctx);
|
|
21
22
|
const distribution = ctx.buildProfile.distribution ?? types_1.BuildDistributionType.STORE;
|
|
@@ -39,7 +40,7 @@ async function collectMetadataAsync(ctx, runtimeAndFingerprintMetadata) {
|
|
|
39
40
|
isGitWorkingTreeDirty: ctx.localBuildOptions.localBuildMode === local_1.LocalBuildMode.INTERNAL
|
|
40
41
|
? false
|
|
41
42
|
: await ctx.vcsClient.hasUncommittedChangesAsync(),
|
|
42
|
-
username: (0,
|
|
43
|
+
username: (0, User_1.getActorUsername)(ctx.user) ?? undefined,
|
|
43
44
|
message: ctx.message,
|
|
44
45
|
...(ctx.platform === eas_build_job_1.Platform.IOS && {
|
|
45
46
|
iosEnterpriseProvisioning: resolveIosEnterpriseProvisioning(ctx),
|
|
@@ -20,7 +20,9 @@ const VcsClientContextField_1 = tslib_1.__importDefault(require("./context/VcsCl
|
|
|
20
20
|
const errors_1 = require("./errors");
|
|
21
21
|
const AnalyticsManager_1 = require("../analytics/AnalyticsManager");
|
|
22
22
|
const log_1 = tslib_1.__importStar(require("../log"));
|
|
23
|
+
const sentry_1 = tslib_1.__importDefault(require("../sentry"));
|
|
23
24
|
const SessionManager_1 = tslib_1.__importDefault(require("../user/SessionManager"));
|
|
25
|
+
const User_1 = require("../user/User");
|
|
24
26
|
const BASE_GRAPHQL_ERROR_MESSAGE = 'GraphQL request failed.';
|
|
25
27
|
class EasCommand extends core_1.Command {
|
|
26
28
|
static ContextOptions = {
|
|
@@ -159,7 +161,13 @@ class EasCommand extends core_1.Command {
|
|
|
159
161
|
this.sessionManagerInternal = new SessionManager_1.default(this.analytics);
|
|
160
162
|
// this is needed for logEvent call below as it identifies the user in the analytics system
|
|
161
163
|
// if possible
|
|
162
|
-
await this.sessionManager.getUserAsync();
|
|
164
|
+
const actor = await this.sessionManager.getUserAsync();
|
|
165
|
+
if (actor) {
|
|
166
|
+
sentry_1.default.setUser({
|
|
167
|
+
id: actor.id,
|
|
168
|
+
username: (0, User_1.getActorDisplayName)(actor),
|
|
169
|
+
});
|
|
170
|
+
}
|
|
163
171
|
this.analytics.logEvent(AnalyticsManager_1.CommandEvent.ACTION, {
|
|
164
172
|
// id is assigned by oclif in constructor based on the filepath:
|
|
165
173
|
// commands/submit === submit, commands/build/list === build:list
|
|
@@ -170,10 +178,12 @@ class EasCommand extends core_1.Command {
|
|
|
170
178
|
// eslint-disable-next-line async-protect/async-suffix
|
|
171
179
|
async finally(err) {
|
|
172
180
|
await this.analytics.flushAsync();
|
|
181
|
+
await sentry_1.default.flush(2000);
|
|
173
182
|
return await super.finally(err);
|
|
174
183
|
}
|
|
175
184
|
catch(err) {
|
|
176
|
-
|
|
185
|
+
const commandId = this.id ?? 'unknown';
|
|
186
|
+
let baseMessage = `${commandId} command failed.`;
|
|
177
187
|
if (err instanceof errors_1.EasCommandError) {
|
|
178
188
|
log_1.default.error(err.message);
|
|
179
189
|
}
|
|
@@ -206,6 +216,17 @@ class EasCommand extends core_1.Command {
|
|
|
206
216
|
log_1.default.error(err.message);
|
|
207
217
|
}
|
|
208
218
|
log_1.default.debug(err);
|
|
219
|
+
sentry_1.default.withScope(scope => {
|
|
220
|
+
scope.setTag('command', commandId);
|
|
221
|
+
scope.setTag('error_name', err.name);
|
|
222
|
+
scope.setExtra('commandId', commandId);
|
|
223
|
+
scope.setExtra('commandMessage', baseMessage);
|
|
224
|
+
scope.setExtra('originalMessage', err.message);
|
|
225
|
+
if (err instanceof core_2.CombinedError) {
|
|
226
|
+
scope.setExtra('graphQLErrorCount', err.graphQLErrors.length);
|
|
227
|
+
}
|
|
228
|
+
sentry_1.default.captureException(err);
|
|
229
|
+
});
|
|
209
230
|
const sanitizedError = new Error(baseMessage);
|
|
210
231
|
sanitizedError.stack = err.stack;
|
|
211
232
|
throw sanitizedError;
|
|
@@ -114,6 +114,8 @@ async function validateOrSetProjectIdAsync({ exp, graphqlClient, actor, options,
|
|
|
114
114
|
return user.username;
|
|
115
115
|
case 'SSOUser':
|
|
116
116
|
return user.username;
|
|
117
|
+
case 'PartnerActor':
|
|
118
|
+
return user.username;
|
|
117
119
|
case 'Robot':
|
|
118
120
|
throw new Error('Must configure EAS project by running "eas init" before using a robot user to manage the project.');
|
|
119
121
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Interfaces } from '@oclif/core';
|
|
2
2
|
import { EasNonInteractiveAndJsonFlags } from './flags';
|
|
3
3
|
export declare const getPaginatedQueryOptions: (flags: Partial<Record<keyof typeof EasPaginatedQueryFlags | keyof typeof EasNonInteractiveAndJsonFlags, any>>) => PaginatedQueryOptions;
|
|
4
|
-
export declare const getLimitFlagWithCustomValues: ({ defaultTo, limit, }: {
|
|
4
|
+
export declare const getLimitFlagWithCustomValues: ({ defaultTo, limit, description, }: {
|
|
5
5
|
defaultTo: number;
|
|
6
6
|
limit: number;
|
|
7
|
+
description?: string;
|
|
7
8
|
}) => Interfaces.OptionFlag<number | undefined>;
|
|
8
9
|
export declare const EasPaginatedQueryFlags: {
|
|
9
10
|
offset: Interfaces.OptionFlag<number | undefined, Interfaces.CustomOptions>;
|
|
@@ -23,8 +23,9 @@ const parseFlagInputStringAsInteger = (input, flagName, lowerLimit, upperLimit)
|
|
|
23
23
|
}
|
|
24
24
|
return inputAsNumber;
|
|
25
25
|
};
|
|
26
|
-
const getLimitFlagWithCustomValues = ({ defaultTo, limit, }) => core_1.Flags.integer({
|
|
27
|
-
description:
|
|
26
|
+
const getLimitFlagWithCustomValues = ({ defaultTo, limit, description, }) => core_1.Flags.integer({
|
|
27
|
+
description: description ??
|
|
28
|
+
`The number of items to fetch each query. Defaults to ${defaultTo} and is capped at ${limit}.`,
|
|
28
29
|
// eslint-disable-next-line async-protect/async-suffix
|
|
29
30
|
parse: async (input) => parseFlagInputStringAsInteger(input, 'limit', 1, limit),
|
|
30
31
|
});
|
|
@@ -16,6 +16,16 @@ async function fetchRawLogsForCustomJobAsync(job) {
|
|
|
16
16
|
return rawLogs;
|
|
17
17
|
}
|
|
18
18
|
async function fetchRawLogsForBuildJobAsync(state, job) {
|
|
19
|
+
// Prefer turtleJobRun logs, which contain JSONL-formatted step logs
|
|
20
|
+
// for both built-in and custom build steps
|
|
21
|
+
const turtleLogFileUrl = job.turtleJobRun?.logFileUrls?.[0];
|
|
22
|
+
if (turtleLogFileUrl) {
|
|
23
|
+
const response = await fetch(turtleLogFileUrl, {
|
|
24
|
+
method: 'GET',
|
|
25
|
+
});
|
|
26
|
+
return await response.text();
|
|
27
|
+
}
|
|
28
|
+
// Fall back to build logFiles
|
|
19
29
|
const buildId = job.outputs?.build_id;
|
|
20
30
|
if (!buildId) {
|
|
21
31
|
return null;
|
|
@@ -30,6 +40,5 @@ async function fetchRawLogsForBuildJobAsync(state, job) {
|
|
|
30
40
|
const response = await fetch(firstLogFileUrl, {
|
|
31
41
|
method: 'GET',
|
|
32
42
|
});
|
|
33
|
-
|
|
34
|
-
return rawLogs;
|
|
43
|
+
return await response.text();
|
|
35
44
|
}
|
|
@@ -74,15 +74,14 @@ function choiceFromWorkflowJob(job, index) {
|
|
|
74
74
|
};
|
|
75
75
|
}
|
|
76
76
|
function choicesFromWorkflowLogs(logs) {
|
|
77
|
-
return Array.from(logs.
|
|
78
|
-
.map(
|
|
79
|
-
const
|
|
80
|
-
const stepStatus = logLines?.filter((line) => line.marker === 'end-step')[0]?.result ?? '';
|
|
77
|
+
return Array.from(logs.values())
|
|
78
|
+
.map(({ key, label, logLines }) => {
|
|
79
|
+
const stepStatus = logLines?.filter((line) => line.marker === 'end-step' || line.marker === 'END_PHASE')[0]?.result ?? '';
|
|
81
80
|
return {
|
|
82
|
-
title: `${
|
|
83
|
-
name:
|
|
81
|
+
title: `${label} - ${stepStatus}`,
|
|
82
|
+
name: label,
|
|
84
83
|
status: stepStatus,
|
|
85
|
-
value:
|
|
84
|
+
value: key,
|
|
86
85
|
logLines,
|
|
87
86
|
};
|
|
88
87
|
})
|
|
@@ -123,19 +122,26 @@ async function fetchAndProcessLogsFromJobAsync(state, job) {
|
|
|
123
122
|
}
|
|
124
123
|
log_1.default.debug(`rawLogs = ${JSON.stringify(rawLogs, null, 2)}`);
|
|
125
124
|
const logs = new Map();
|
|
126
|
-
const logKeys = new Set();
|
|
127
125
|
rawLogs.split('\n').forEach((line, index) => {
|
|
128
126
|
log_1.default.debug(`line ${index} = ${JSON.stringify(line, null, 2)}`);
|
|
129
127
|
try {
|
|
130
128
|
const parsedLine = JSON.parse(line);
|
|
131
|
-
const { buildStepDisplayName,
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
logs.set(
|
|
129
|
+
const { buildStepDisplayName, buildStepId, phase, time, msg, result, marker, err } = parsedLine;
|
|
130
|
+
const stepKey = buildStepId ?? buildStepDisplayName ?? phase;
|
|
131
|
+
const stepLabel = buildStepDisplayName ?? buildStepId ?? phase;
|
|
132
|
+
if (stepKey && stepLabel) {
|
|
133
|
+
if (!logs.has(stepKey)) {
|
|
134
|
+
logs.set(stepKey, {
|
|
135
|
+
key: stepKey,
|
|
136
|
+
label: stepLabel,
|
|
137
|
+
logLines: [],
|
|
138
|
+
});
|
|
137
139
|
}
|
|
138
|
-
logs.get(
|
|
140
|
+
const logGroup = logs.get(stepKey);
|
|
141
|
+
if (buildStepDisplayName) {
|
|
142
|
+
logGroup.label = buildStepDisplayName;
|
|
143
|
+
}
|
|
144
|
+
logGroup.logLines.push({ time, msg, result, marker, err });
|
|
139
145
|
}
|
|
140
146
|
}
|
|
141
147
|
catch { }
|
|
@@ -212,7 +218,7 @@ async function infoForFailedWorkflowRunAsync(graphqlClient, workflowRun, maxLogL
|
|
|
212
218
|
statusValues.push({ label: '', value: '' });
|
|
213
219
|
statusValues.push({ label: ' Failed job', value: job.name });
|
|
214
220
|
if (steps.length > 0) {
|
|
215
|
-
const failedStep = steps.find(step => step.status === 'fail');
|
|
221
|
+
const failedStep = steps.find(step => step.status === 'fail' || step.status === 'failed');
|
|
216
222
|
if (failedStep) {
|
|
217
223
|
const logs = failedStep.logLines?.map(line => line.msg).slice(-logLinesToKeep) ?? [];
|
|
218
224
|
statusValues.push({ label: ' Failed step', value: failedStep.name });
|
|
@@ -243,8 +243,24 @@ class WorkerDeploy extends EasCommand_1.default {
|
|
|
243
243
|
}
|
|
244
244
|
throw error;
|
|
245
245
|
}
|
|
246
|
-
|
|
247
|
-
|
|
246
|
+
let uploadError;
|
|
247
|
+
try {
|
|
248
|
+
await uploadAssetsAsync(assetFiles, deployResult);
|
|
249
|
+
}
|
|
250
|
+
catch (error) {
|
|
251
|
+
uploadError = error;
|
|
252
|
+
}
|
|
253
|
+
try {
|
|
254
|
+
await finalizeDeployAsync(deployResult);
|
|
255
|
+
}
|
|
256
|
+
catch (finalizeError) {
|
|
257
|
+
if (!uploadError) {
|
|
258
|
+
throw finalizeError;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (uploadError) {
|
|
262
|
+
throw uploadError;
|
|
263
|
+
}
|
|
248
264
|
let deploymentAlias = null;
|
|
249
265
|
if (flags.aliasName) {
|
|
250
266
|
progress = (0, ora_1.ora)((0, chalk_1.default) `Assigning alias {bold ${flags.aliasName}} to deployment`).start();
|
|
@@ -2,6 +2,7 @@ import EasCommand from '../../commandUtils/EasCommand';
|
|
|
2
2
|
export default class MetadataPull extends EasCommand {
|
|
3
3
|
static description: string;
|
|
4
4
|
static flags: {
|
|
5
|
+
'non-interactive': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
5
6
|
profile: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
6
7
|
};
|
|
7
8
|
static contextDefinition: {
|
|
@@ -8,6 +8,7 @@ const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
|
8
8
|
const path_1 = tslib_1.__importDefault(require("path"));
|
|
9
9
|
const configure_1 = require("../../build/configure");
|
|
10
10
|
const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
|
|
11
|
+
const flags_1 = require("../../commandUtils/flags");
|
|
11
12
|
const context_1 = require("../../credentials/context");
|
|
12
13
|
const log_1 = tslib_1.__importStar(require("../../log"));
|
|
13
14
|
const download_1 = require("../../metadata/download");
|
|
@@ -20,6 +21,7 @@ class MetadataPull extends EasCommand_1.default {
|
|
|
20
21
|
char: 'e',
|
|
21
22
|
description: 'Name of the submit profile from eas.json. Defaults to "production" if defined in eas.json.',
|
|
22
23
|
}),
|
|
24
|
+
...flags_1.EASNonInteractiveFlag,
|
|
23
25
|
};
|
|
24
26
|
static contextDefinition = {
|
|
25
27
|
...this.ContextOptions.ProjectConfig,
|
|
@@ -30,12 +32,12 @@ class MetadataPull extends EasCommand_1.default {
|
|
|
30
32
|
async runAsync() {
|
|
31
33
|
log_1.default.warn('EAS Metadata is in beta and subject to breaking changes.');
|
|
32
34
|
const { flags } = await this.parse(MetadataPull);
|
|
35
|
+
const nonInteractive = flags['non-interactive'];
|
|
33
36
|
const { loggedIn: { actor, graphqlClient }, privateProjectConfig: { exp, projectId, projectDir }, analytics, vcsClient, } = await this.getContextAsync(MetadataPull, {
|
|
34
|
-
nonInteractive
|
|
37
|
+
nonInteractive,
|
|
35
38
|
withServerSideEnvironment: null,
|
|
36
39
|
});
|
|
37
|
-
|
|
38
|
-
await (0, configure_1.ensureProjectConfiguredAsync)({ projectDir, nonInteractive: false, vcsClient });
|
|
40
|
+
await (0, configure_1.ensureProjectConfiguredAsync)({ projectDir, nonInteractive, vcsClient });
|
|
39
41
|
const submitProfiles = await (0, profiles_1.getProfilesAsync)({
|
|
40
42
|
type: 'submit',
|
|
41
43
|
easJsonAccessor: eas_json_1.EasJsonAccessor.fromProjectPath(projectDir),
|
|
@@ -53,7 +55,7 @@ class MetadataPull extends EasCommand_1.default {
|
|
|
53
55
|
user: actor,
|
|
54
56
|
graphqlClient,
|
|
55
57
|
analytics,
|
|
56
|
-
nonInteractive
|
|
58
|
+
nonInteractive,
|
|
57
59
|
vcsClient,
|
|
58
60
|
});
|
|
59
61
|
try {
|
|
@@ -63,6 +65,9 @@ class MetadataPull extends EasCommand_1.default {
|
|
|
63
65
|
credentialsCtx,
|
|
64
66
|
projectDir,
|
|
65
67
|
profile: submitProfile,
|
|
68
|
+
nonInteractive,
|
|
69
|
+
graphqlClient,
|
|
70
|
+
projectId,
|
|
66
71
|
});
|
|
67
72
|
const relativePath = path_1.default.relative(process.cwd(), filePath);
|
|
68
73
|
log_1.default.addNewLineIfNone();
|
|
@@ -2,6 +2,7 @@ import EasCommand from '../../commandUtils/EasCommand';
|
|
|
2
2
|
export default class MetadataPush extends EasCommand {
|
|
3
3
|
static description: string;
|
|
4
4
|
static flags: {
|
|
5
|
+
'non-interactive': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
5
6
|
profile: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
6
7
|
};
|
|
7
8
|
static contextDefinition: {
|
|
@@ -6,6 +6,7 @@ const eas_json_1 = require("@expo/eas-json");
|
|
|
6
6
|
const core_1 = require("@oclif/core");
|
|
7
7
|
const configure_1 = require("../../build/configure");
|
|
8
8
|
const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
|
|
9
|
+
const flags_1 = require("../../commandUtils/flags");
|
|
9
10
|
const context_1 = require("../../credentials/context");
|
|
10
11
|
const log_1 = tslib_1.__importStar(require("../../log"));
|
|
11
12
|
const errors_1 = require("../../metadata/errors");
|
|
@@ -18,6 +19,7 @@ class MetadataPush extends EasCommand_1.default {
|
|
|
18
19
|
char: 'e',
|
|
19
20
|
description: 'Name of the submit profile from eas.json. Defaults to "production" if defined in eas.json.',
|
|
20
21
|
}),
|
|
22
|
+
...flags_1.EASNonInteractiveFlag,
|
|
21
23
|
};
|
|
22
24
|
static contextDefinition = {
|
|
23
25
|
...this.ContextOptions.ProjectConfig,
|
|
@@ -28,12 +30,12 @@ class MetadataPush extends EasCommand_1.default {
|
|
|
28
30
|
async runAsync() {
|
|
29
31
|
log_1.default.warn('EAS Metadata is in beta and subject to breaking changes.');
|
|
30
32
|
const { flags } = await this.parse(MetadataPush);
|
|
33
|
+
const nonInteractive = flags['non-interactive'];
|
|
31
34
|
const { loggedIn: { actor, graphqlClient }, privateProjectConfig: { exp, projectId, projectDir }, analytics, vcsClient, } = await this.getContextAsync(MetadataPush, {
|
|
32
|
-
nonInteractive
|
|
35
|
+
nonInteractive,
|
|
33
36
|
withServerSideEnvironment: null,
|
|
34
37
|
});
|
|
35
|
-
|
|
36
|
-
await (0, configure_1.ensureProjectConfiguredAsync)({ projectDir, nonInteractive: false, vcsClient });
|
|
38
|
+
await (0, configure_1.ensureProjectConfiguredAsync)({ projectDir, nonInteractive, vcsClient });
|
|
37
39
|
const submitProfiles = await (0, profiles_1.getProfilesAsync)({
|
|
38
40
|
type: 'submit',
|
|
39
41
|
easJsonAccessor: eas_json_1.EasJsonAccessor.fromProjectPath(projectDir),
|
|
@@ -51,7 +53,7 @@ class MetadataPush extends EasCommand_1.default {
|
|
|
51
53
|
user: actor,
|
|
52
54
|
graphqlClient,
|
|
53
55
|
analytics,
|
|
54
|
-
nonInteractive
|
|
56
|
+
nonInteractive,
|
|
55
57
|
vcsClient,
|
|
56
58
|
});
|
|
57
59
|
try {
|
|
@@ -61,6 +63,9 @@ class MetadataPush extends EasCommand_1.default {
|
|
|
61
63
|
credentialsCtx,
|
|
62
64
|
projectDir,
|
|
63
65
|
profile: submitProfile,
|
|
66
|
+
nonInteractive,
|
|
67
|
+
graphqlClient,
|
|
68
|
+
projectId,
|
|
64
69
|
});
|
|
65
70
|
log_1.default.addNewLineIfNone();
|
|
66
71
|
log_1.default.log(`🎉 Store configuration is synced with the app stores.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import EasCommand from '../../commandUtils/EasCommand';
|
|
2
|
+
export default class ObserveEvents extends EasCommand {
|
|
3
|
+
static hidden: boolean;
|
|
4
|
+
static description: string;
|
|
5
|
+
static args: {
|
|
6
|
+
metric: import("@oclif/core/lib/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
7
|
+
};
|
|
8
|
+
static flags: {
|
|
9
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
'non-interactive': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
11
|
+
sort: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
12
|
+
platform: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
13
|
+
after: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
14
|
+
limit: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined>;
|
|
15
|
+
start: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
16
|
+
end: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
17
|
+
days: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
18
|
+
'app-version': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
19
|
+
'update-id': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
20
|
+
'project-id': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
21
|
+
};
|
|
22
|
+
static contextDefinition: {
|
|
23
|
+
loggedIn: import("../../commandUtils/context/LoggedInContextField").default;
|
|
24
|
+
projectId: import("../../commandUtils/context/ProjectIdContextField").ProjectIdContextField;
|
|
25
|
+
};
|
|
26
|
+
runAsync(): Promise<void>;
|
|
27
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const core_1 = require("@oclif/core");
|
|
5
|
+
const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
|
|
6
|
+
const errors_1 = require("../../commandUtils/errors");
|
|
7
|
+
const flags_1 = require("../../commandUtils/flags");
|
|
8
|
+
const pagination_1 = require("../../commandUtils/pagination");
|
|
9
|
+
const generated_1 = require("../../graphql/generated");
|
|
10
|
+
const log_1 = tslib_1.__importDefault(require("../../log"));
|
|
11
|
+
const fetchEvents_1 = require("../../observe/fetchEvents");
|
|
12
|
+
const metricNames_1 = require("../../observe/metricNames");
|
|
13
|
+
const formatEvents_1 = require("../../observe/formatEvents");
|
|
14
|
+
const startAndEndTime_1 = require("../../observe/startAndEndTime");
|
|
15
|
+
const prompts_1 = require("../../prompts");
|
|
16
|
+
const json_1 = require("../../utils/json");
|
|
17
|
+
const DEFAULT_EVENTS_LIMIT = 10;
|
|
18
|
+
class ObserveEvents extends EasCommand_1.default {
|
|
19
|
+
static hidden = true;
|
|
20
|
+
static description = 'display individual app performance events ordered by metric value';
|
|
21
|
+
static args = {
|
|
22
|
+
metric: core_1.Args.string({
|
|
23
|
+
description: 'Metric to query (e.g. tti, cold_launch)',
|
|
24
|
+
required: false,
|
|
25
|
+
options: Object.keys(metricNames_1.METRIC_ALIASES),
|
|
26
|
+
}),
|
|
27
|
+
};
|
|
28
|
+
static flags = {
|
|
29
|
+
sort: core_1.Flags.option({
|
|
30
|
+
description: 'Sort order for events',
|
|
31
|
+
options: Object.values(fetchEvents_1.EventsOrderPreset).map(s => s.toLowerCase()),
|
|
32
|
+
required: false,
|
|
33
|
+
default: fetchEvents_1.EventsOrderPreset.Oldest.valueOf().toLowerCase(),
|
|
34
|
+
})(),
|
|
35
|
+
platform: core_1.Flags.option({
|
|
36
|
+
description: 'Filter by platform',
|
|
37
|
+
options: Object.values(generated_1.AppObservePlatform).map(s => s.toLowerCase()),
|
|
38
|
+
})(),
|
|
39
|
+
after: core_1.Flags.string({
|
|
40
|
+
description: 'Cursor for pagination. Use the endCursor from a previous query to fetch the next page.',
|
|
41
|
+
}),
|
|
42
|
+
limit: (0, pagination_1.getLimitFlagWithCustomValues)({
|
|
43
|
+
defaultTo: DEFAULT_EVENTS_LIMIT,
|
|
44
|
+
limit: 100,
|
|
45
|
+
}),
|
|
46
|
+
start: core_1.Flags.string({
|
|
47
|
+
description: 'Start of time range (ISO date)',
|
|
48
|
+
exclusive: ['days'],
|
|
49
|
+
}),
|
|
50
|
+
end: core_1.Flags.string({
|
|
51
|
+
description: 'End of time range (ISO date)',
|
|
52
|
+
exclusive: ['days'],
|
|
53
|
+
}),
|
|
54
|
+
days: core_1.Flags.integer({
|
|
55
|
+
description: 'Show events from the last N days (mutually exclusive with --start/--end)',
|
|
56
|
+
min: 1,
|
|
57
|
+
exclusive: ['start', 'end'],
|
|
58
|
+
}),
|
|
59
|
+
'app-version': core_1.Flags.string({
|
|
60
|
+
description: 'Filter by app version',
|
|
61
|
+
}),
|
|
62
|
+
'update-id': core_1.Flags.string({
|
|
63
|
+
description: 'Filter by EAS update ID',
|
|
64
|
+
}),
|
|
65
|
+
'project-id': core_1.Flags.string({
|
|
66
|
+
description: 'EAS project ID (defaults to the project ID of the current directory)',
|
|
67
|
+
}),
|
|
68
|
+
...flags_1.EasNonInteractiveAndJsonFlags,
|
|
69
|
+
};
|
|
70
|
+
static contextDefinition = {
|
|
71
|
+
...this.ContextOptions.ProjectId,
|
|
72
|
+
...this.ContextOptions.LoggedIn,
|
|
73
|
+
};
|
|
74
|
+
async runAsync() {
|
|
75
|
+
const { flags, args } = await this.parse(ObserveEvents);
|
|
76
|
+
const { projectId: contextProjectId, loggedIn: { graphqlClient }, } = await this.getContextAsync(ObserveEvents, {
|
|
77
|
+
nonInteractive: flags['non-interactive'],
|
|
78
|
+
});
|
|
79
|
+
const projectId = flags['project-id'] ?? contextProjectId;
|
|
80
|
+
if (flags.json) {
|
|
81
|
+
(0, json_1.enableJsonOutput)();
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
log_1.default.warn('EAS Observe is in preview and subject to breaking changes.');
|
|
85
|
+
}
|
|
86
|
+
let metricName;
|
|
87
|
+
if (args.metric) {
|
|
88
|
+
metricName = (0, metricNames_1.resolveMetricName)(args.metric);
|
|
89
|
+
}
|
|
90
|
+
else if (flags['non-interactive']) {
|
|
91
|
+
throw new errors_1.EasCommandError('A metric argument is required in non-interactive mode. Available metrics: ' +
|
|
92
|
+
Object.keys(metricNames_1.METRIC_ALIASES).join(', '));
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
const choices = Object.entries(metricNames_1.METRIC_SHORT_NAMES).map(([fullName, displayName]) => ({
|
|
96
|
+
title: `${displayName} (${fullName})`,
|
|
97
|
+
value: fullName,
|
|
98
|
+
}));
|
|
99
|
+
metricName = await (0, prompts_1.selectAsync)('Select a metric', choices);
|
|
100
|
+
}
|
|
101
|
+
const orderBy = (0, fetchEvents_1.resolveOrderBy)(flags.sort);
|
|
102
|
+
const { daysBack, startTime, endTime } = (0, startAndEndTime_1.resolveTimeRange)(flags);
|
|
103
|
+
const platform = flags.platform
|
|
104
|
+
? flags.platform === 'android'
|
|
105
|
+
? generated_1.AppObservePlatform.Android
|
|
106
|
+
: generated_1.AppObservePlatform.Ios
|
|
107
|
+
: undefined;
|
|
108
|
+
const platforms = platform
|
|
109
|
+
? [platform === generated_1.AppObservePlatform.Android ? generated_1.AppPlatform.Android : generated_1.AppPlatform.Ios]
|
|
110
|
+
: [generated_1.AppPlatform.Android, generated_1.AppPlatform.Ios];
|
|
111
|
+
const [{ events, pageInfo }, totalEventCount] = await Promise.all([
|
|
112
|
+
(0, fetchEvents_1.fetchObserveEventsAsync)(graphqlClient, projectId, {
|
|
113
|
+
metricName,
|
|
114
|
+
orderBy,
|
|
115
|
+
limit: flags.limit ?? DEFAULT_EVENTS_LIMIT,
|
|
116
|
+
...(flags.after && { after: flags.after }),
|
|
117
|
+
startTime,
|
|
118
|
+
endTime,
|
|
119
|
+
platform,
|
|
120
|
+
appVersion: flags['app-version'],
|
|
121
|
+
updateId: flags['update-id'],
|
|
122
|
+
}),
|
|
123
|
+
(0, fetchEvents_1.fetchTotalEventCountAsync)(graphqlClient, projectId, metricName, platforms, startTime, endTime),
|
|
124
|
+
]);
|
|
125
|
+
if (flags.json) {
|
|
126
|
+
(0, json_1.printJsonOnlyOutput)((0, formatEvents_1.buildObserveEventsJson)(events, pageInfo));
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
log_1.default.addNewLineIfNone();
|
|
130
|
+
log_1.default.log((0, formatEvents_1.buildObserveEventsTable)(events, pageInfo, {
|
|
131
|
+
metricName,
|
|
132
|
+
daysBack,
|
|
133
|
+
startTime,
|
|
134
|
+
endTime,
|
|
135
|
+
totalEventCount,
|
|
136
|
+
}));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
exports.default = ObserveEvents;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import EasCommand from '../../commandUtils/EasCommand';
|
|
2
|
+
export default class ObserveMetrics extends EasCommand {
|
|
3
|
+
static hidden: boolean;
|
|
4
|
+
static description: string;
|
|
5
|
+
static flags: {
|
|
6
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
7
|
+
'non-interactive': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
platform: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
9
|
+
metric: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
10
|
+
stat: import("@oclif/core/lib/interfaces").OptionFlag<("min" | "max" | "median" | "average" | "p80" | "p90" | "p99" | "eventCount")[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
11
|
+
start: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
12
|
+
end: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
13
|
+
days: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
14
|
+
'project-id': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
15
|
+
};
|
|
16
|
+
static contextDefinition: {
|
|
17
|
+
loggedIn: import("../../commandUtils/context/LoggedInContextField").default;
|
|
18
|
+
projectId: import("../../commandUtils/context/ProjectIdContextField").ProjectIdContextField;
|
|
19
|
+
};
|
|
20
|
+
runAsync(): Promise<void>;
|
|
21
|
+
}
|