eas-cli 18.10.0 → 18.11.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 +107 -102
- package/build/build/runBuildAndSubmit.d.ts +3 -1
- package/build/build/runBuildAndSubmit.js +12 -4
- package/build/build/utils/repository.js +8 -0
- package/build/build/validateLockfile.d.ts +1 -0
- package/build/build/validateLockfile.js +37 -0
- package/build/commandUtils/buildFlags.d.ts +1 -0
- package/build/commandUtils/buildFlags.js +18 -0
- package/build/commandUtils/convex.d.ts +1 -0
- package/build/commandUtils/convex.js +8 -2
- package/build/commands/build/dev.d.ts +1 -0
- package/build/commands/build/dev.js +12 -2
- package/build/commands/build/run.d.ts +1 -0
- package/build/commands/build/run.js +12 -3
- package/build/commands/integrations/convex/connect.js +12 -4
- package/build/commands/integrations/convex/team/invite.js +6 -1
- package/build/commands/observe/events.js +12 -24
- package/build/commands/observe/logs.d.ts +29 -0
- package/build/commands/observe/logs.js +163 -0
- package/build/commands/observe/metrics.js +11 -19
- package/build/commands/observe/versions.js +11 -19
- package/build/commands/simulator/start.js +84 -5
- package/build/commands/simulator/stop.js +1 -1
- package/build/graphql/generated.d.ts +180 -6
- package/build/graphql/generated.js +16 -3
- package/build/graphql/mutations/DeviceRunSessionMutation.d.ts +2 -2
- package/build/graphql/mutations/DeviceRunSessionMutation.js +4 -4
- package/build/graphql/queries/ObserveQuery.d.ts +21 -1
- package/build/graphql/queries/ObserveQuery.js +80 -0
- package/build/graphql/types/ConvexTeamConnection.d.ts +1 -1
- package/build/graphql/types/ConvexTeamConnection.js +1 -0
- package/build/graphql/types/Observe.d.ts +1 -0
- package/build/graphql/types/Observe.js +26 -1
- package/build/observe/fetchCustomEvents.d.ts +19 -0
- package/build/observe/fetchCustomEvents.js +21 -0
- package/build/observe/formatCustomEvents.d.ts +70 -0
- package/build/observe/formatCustomEvents.js +140 -0
- package/build/observe/formatEvents.js +5 -34
- package/build/observe/formatMetrics.js +2 -7
- package/build/observe/formatUtils.d.ts +27 -0
- package/build/observe/formatUtils.js +64 -0
- package/build/observe/formatVersions.js +2 -9
- package/build/observe/platforms.d.ts +21 -0
- package/build/observe/platforms.js +48 -0
- package/build/observe/resolveProjectContext.d.ts +22 -0
- package/build/observe/resolveProjectContext.js +21 -0
- package/build/run/ios/run.d.ts +2 -1
- package/build/run/ios/run.js +6 -2
- package/build/run/ios/simulator.d.ts +4 -1
- package/build/run/ios/simulator.js +14 -2
- package/build/run/run.d.ts +2 -1
- package/build/run/run.js +2 -2
- package/oclif.manifest.json +955 -762
- package/package.json +2 -2
|
@@ -0,0 +1,163 @@
|
|
|
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 flags_1 = require("../../commandUtils/flags");
|
|
7
|
+
const pagination_1 = require("../../commandUtils/pagination");
|
|
8
|
+
const log_1 = tslib_1.__importDefault(require("../../log"));
|
|
9
|
+
const ObserveQuery_1 = require("../../graphql/queries/ObserveQuery");
|
|
10
|
+
const fetchCustomEvents_1 = require("../../observe/fetchCustomEvents");
|
|
11
|
+
const formatCustomEvents_1 = require("../../observe/formatCustomEvents");
|
|
12
|
+
const platforms_1 = require("../../observe/platforms");
|
|
13
|
+
const resolveProjectContext_1 = require("../../observe/resolveProjectContext");
|
|
14
|
+
const startAndEndTime_1 = require("../../observe/startAndEndTime");
|
|
15
|
+
const json_1 = require("../../utils/json");
|
|
16
|
+
const DEFAULT_EVENTS_LIMIT = 10;
|
|
17
|
+
class ObserveLogs extends EasCommand_1.default {
|
|
18
|
+
static hidden = true;
|
|
19
|
+
static description = 'display individual custom events (logs) emitted by the app, filtered by the event name in the argument. With no arguments, a list of the available event names and associated event counts is returned.';
|
|
20
|
+
static args = {
|
|
21
|
+
eventName: core_1.Args.string({
|
|
22
|
+
description: 'Custom event name to filter by',
|
|
23
|
+
required: false,
|
|
24
|
+
}),
|
|
25
|
+
};
|
|
26
|
+
static flags = {
|
|
27
|
+
platform: core_1.Flags.option({
|
|
28
|
+
description: 'Filter by platform',
|
|
29
|
+
options: platforms_1.allowedPlatformFlagValues,
|
|
30
|
+
})(),
|
|
31
|
+
after: core_1.Flags.string({
|
|
32
|
+
description: 'Cursor for pagination. Use the endCursor from a previous query to fetch the next page.',
|
|
33
|
+
}),
|
|
34
|
+
limit: (0, pagination_1.getLimitFlagWithCustomValues)({
|
|
35
|
+
defaultTo: DEFAULT_EVENTS_LIMIT,
|
|
36
|
+
limit: 100,
|
|
37
|
+
}),
|
|
38
|
+
start: core_1.Flags.string({
|
|
39
|
+
description: 'Start of time range (ISO date)',
|
|
40
|
+
exclusive: ['days'],
|
|
41
|
+
}),
|
|
42
|
+
end: core_1.Flags.string({
|
|
43
|
+
description: 'End of time range (ISO date)',
|
|
44
|
+
exclusive: ['days'],
|
|
45
|
+
}),
|
|
46
|
+
days: core_1.Flags.integer({
|
|
47
|
+
description: 'Show events from the last N days (mutually exclusive with --start/--end)',
|
|
48
|
+
min: 1,
|
|
49
|
+
exclusive: ['start', 'end'],
|
|
50
|
+
}),
|
|
51
|
+
'app-version': core_1.Flags.string({
|
|
52
|
+
description: 'Filter by app version',
|
|
53
|
+
}),
|
|
54
|
+
'update-id': core_1.Flags.string({
|
|
55
|
+
description: 'Filter by EAS update ID',
|
|
56
|
+
}),
|
|
57
|
+
'session-id': core_1.Flags.string({
|
|
58
|
+
description: 'Filter by session ID',
|
|
59
|
+
}),
|
|
60
|
+
'all-events': core_1.Flags.boolean({
|
|
61
|
+
description: 'When no event name argument is provided, list all events across all event names instead of a summary of event names + counts.',
|
|
62
|
+
default: false,
|
|
63
|
+
}),
|
|
64
|
+
'project-id': core_1.Flags.string({
|
|
65
|
+
description: 'EAS project ID (defaults to the project ID of the current directory)',
|
|
66
|
+
}),
|
|
67
|
+
...flags_1.EasNonInteractiveAndJsonFlags,
|
|
68
|
+
};
|
|
69
|
+
static contextDefinition = {
|
|
70
|
+
...this.ContextOptions.ProjectId,
|
|
71
|
+
...this.ContextOptions.LoggedIn,
|
|
72
|
+
};
|
|
73
|
+
static loggedInOnlyContextDefinition = {
|
|
74
|
+
...this.ContextOptions.LoggedIn,
|
|
75
|
+
};
|
|
76
|
+
async runAsync() {
|
|
77
|
+
const { flags, args } = await this.parse(ObserveLogs);
|
|
78
|
+
if (args.eventName && flags['all-events']) {
|
|
79
|
+
throw new Error('--all-events cannot be combined with an event name argument. Pass an event name to filter by it, or pass --all-events to list all events across all event names.');
|
|
80
|
+
}
|
|
81
|
+
const { projectId, graphqlClient } = await (0, resolveProjectContext_1.resolveObserveCommandContextAsync)({
|
|
82
|
+
command: this,
|
|
83
|
+
commandClass: ObserveLogs,
|
|
84
|
+
loggedInOnlyContextDefinition: ObserveLogs.loggedInOnlyContextDefinition,
|
|
85
|
+
projectIdOverride: flags['project-id'],
|
|
86
|
+
nonInteractive: flags['non-interactive'],
|
|
87
|
+
});
|
|
88
|
+
if (flags.json) {
|
|
89
|
+
(0, json_1.enableJsonOutput)();
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
log_1.default.warn('EAS Observe is in preview and subject to breaking changes.');
|
|
93
|
+
}
|
|
94
|
+
const { daysBack, startTime, endTime } = (0, startAndEndTime_1.resolveTimeRange)(flags);
|
|
95
|
+
const platform = (0, platforms_1.appObservePlatformFromFlag)(flags.platform);
|
|
96
|
+
if (!args.eventName && !flags['all-events']) {
|
|
97
|
+
const { names, isTruncated } = await ObserveQuery_1.ObserveQuery.customEventNamesAsync(graphqlClient, {
|
|
98
|
+
appId: projectId,
|
|
99
|
+
startTime,
|
|
100
|
+
endTime,
|
|
101
|
+
platform,
|
|
102
|
+
});
|
|
103
|
+
if (flags.json) {
|
|
104
|
+
(0, json_1.printJsonOnlyOutput)((0, formatCustomEvents_1.buildObserveCustomEventNamesJson)(names, isTruncated));
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
log_1.default.addNewLineIfNone();
|
|
108
|
+
log_1.default.log((0, formatCustomEvents_1.buildObserveCustomEventNamesTable)(names, {
|
|
109
|
+
daysBack,
|
|
110
|
+
startTime,
|
|
111
|
+
endTime,
|
|
112
|
+
isTruncated,
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const { events, pageInfo } = await (0, fetchCustomEvents_1.fetchObserveCustomEventsAsync)(graphqlClient, projectId, {
|
|
118
|
+
eventName: args.eventName,
|
|
119
|
+
limit: flags.limit ?? DEFAULT_EVENTS_LIMIT,
|
|
120
|
+
...(flags.after && { after: flags.after }),
|
|
121
|
+
startTime,
|
|
122
|
+
endTime,
|
|
123
|
+
platform,
|
|
124
|
+
appVersion: flags['app-version'],
|
|
125
|
+
updateId: flags['update-id'],
|
|
126
|
+
sessionId: flags['session-id'],
|
|
127
|
+
});
|
|
128
|
+
if (args.eventName && events.length === 0) {
|
|
129
|
+
const { names, isTruncated } = await ObserveQuery_1.ObserveQuery.customEventNamesAsync(graphqlClient, {
|
|
130
|
+
appId: projectId,
|
|
131
|
+
startTime,
|
|
132
|
+
endTime,
|
|
133
|
+
platform,
|
|
134
|
+
});
|
|
135
|
+
if (flags.json) {
|
|
136
|
+
(0, json_1.printJsonOnlyOutput)((0, formatCustomEvents_1.buildObserveCustomEventsEmptyWithSuggestionsJson)(args.eventName, names, isTruncated));
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
log_1.default.addNewLineIfNone();
|
|
140
|
+
log_1.default.log((0, formatCustomEvents_1.buildObserveCustomEventsEmptyWithSuggestionsTable)(args.eventName, names, {
|
|
141
|
+
daysBack,
|
|
142
|
+
startTime,
|
|
143
|
+
endTime,
|
|
144
|
+
isTruncated,
|
|
145
|
+
}));
|
|
146
|
+
}
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
if (flags.json) {
|
|
150
|
+
(0, json_1.printJsonOnlyOutput)((0, formatCustomEvents_1.buildObserveCustomEventsJson)(events, pageInfo));
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
log_1.default.addNewLineIfNone();
|
|
154
|
+
log_1.default.log((0, formatCustomEvents_1.buildObserveCustomEventsTable)(events, pageInfo, {
|
|
155
|
+
eventName: args.eventName,
|
|
156
|
+
daysBack,
|
|
157
|
+
startTime,
|
|
158
|
+
endTime,
|
|
159
|
+
}));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
exports.default = ObserveLogs;
|
|
@@ -4,11 +4,12 @@ const tslib_1 = require("tslib");
|
|
|
4
4
|
const core_1 = require("@oclif/core");
|
|
5
5
|
const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
|
|
6
6
|
const flags_1 = require("../../commandUtils/flags");
|
|
7
|
-
const generated_1 = require("../../graphql/generated");
|
|
8
7
|
const log_1 = tslib_1.__importDefault(require("../../log"));
|
|
9
8
|
const fetchMetrics_1 = require("../../observe/fetchMetrics");
|
|
10
9
|
const formatMetrics_1 = require("../../observe/formatMetrics");
|
|
11
10
|
const metricNames_1 = require("../../observe/metricNames");
|
|
11
|
+
const platforms_1 = require("../../observe/platforms");
|
|
12
|
+
const resolveProjectContext_1 = require("../../observe/resolveProjectContext");
|
|
12
13
|
const startAndEndTime_1 = require("../../observe/startAndEndTime");
|
|
13
14
|
const json_1 = require("../../utils/json");
|
|
14
15
|
const DEFAULT_METRICS = [
|
|
@@ -35,7 +36,7 @@ class ObserveMetrics extends EasCommand_1.default {
|
|
|
35
36
|
static flags = {
|
|
36
37
|
platform: core_1.Flags.option({
|
|
37
38
|
description: 'Filter by platform',
|
|
38
|
-
options:
|
|
39
|
+
options: platforms_1.allowedPlatformFlagValues,
|
|
39
40
|
})(),
|
|
40
41
|
metric: core_1.Flags.option({
|
|
41
42
|
description: 'Metric name to display (can be specified multiple times).',
|
|
@@ -74,20 +75,13 @@ class ObserveMetrics extends EasCommand_1.default {
|
|
|
74
75
|
};
|
|
75
76
|
async runAsync() {
|
|
76
77
|
const { flags } = await this.parse(ObserveMetrics);
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
else {
|
|
85
|
-
const ctx = await this.getContextAsync(ObserveMetrics, {
|
|
86
|
-
nonInteractive: flags['non-interactive'],
|
|
87
|
-
});
|
|
88
|
-
projectId = ctx.projectId;
|
|
89
|
-
graphqlClient = ctx.loggedIn.graphqlClient;
|
|
90
|
-
}
|
|
78
|
+
const { projectId, graphqlClient } = await (0, resolveProjectContext_1.resolveObserveCommandContextAsync)({
|
|
79
|
+
command: this,
|
|
80
|
+
commandClass: ObserveMetrics,
|
|
81
|
+
loggedInOnlyContextDefinition: ObserveMetrics.loggedInOnlyContextDefinition,
|
|
82
|
+
projectIdOverride: flags['project-id'],
|
|
83
|
+
nonInteractive: flags['non-interactive'],
|
|
84
|
+
});
|
|
91
85
|
if (flags.json) {
|
|
92
86
|
(0, json_1.enableJsonOutput)();
|
|
93
87
|
}
|
|
@@ -98,9 +92,7 @@ class ObserveMetrics extends EasCommand_1.default {
|
|
|
98
92
|
? flags.metric.map(metricNames_1.resolveMetricName)
|
|
99
93
|
: DEFAULT_METRICS;
|
|
100
94
|
const { daysBack, startTime, endTime } = (0, startAndEndTime_1.resolveTimeRange)(flags);
|
|
101
|
-
const platforms = flags.platform
|
|
102
|
-
? [flags.platform === 'android' ? generated_1.AppPlatform.Android : generated_1.AppPlatform.Ios]
|
|
103
|
-
: [generated_1.AppPlatform.Android, generated_1.AppPlatform.Ios];
|
|
95
|
+
const platforms = (0, platforms_1.appPlatformsFromFlag)(flags.platform);
|
|
104
96
|
const { metricsMap, buildNumbersMap, updateIdsMap, totalEventCounts } = await (0, fetchMetrics_1.fetchObserveMetricsAsync)(graphqlClient, projectId, metricNames, platforms, startTime, endTime);
|
|
105
97
|
const argumentsStat = flags.stat?.length
|
|
106
98
|
? Array.from(new Set(flags.stat.map(formatMetrics_1.resolveStatKey)))
|
|
@@ -4,10 +4,11 @@ const tslib_1 = require("tslib");
|
|
|
4
4
|
const core_1 = require("@oclif/core");
|
|
5
5
|
const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
|
|
6
6
|
const flags_1 = require("../../commandUtils/flags");
|
|
7
|
-
const generated_1 = require("../../graphql/generated");
|
|
8
7
|
const log_1 = tslib_1.__importDefault(require("../../log"));
|
|
9
8
|
const fetchVersions_1 = require("../../observe/fetchVersions");
|
|
10
9
|
const formatVersions_1 = require("../../observe/formatVersions");
|
|
10
|
+
const platforms_1 = require("../../observe/platforms");
|
|
11
|
+
const resolveProjectContext_1 = require("../../observe/resolveProjectContext");
|
|
11
12
|
const startAndEndTime_1 = require("../../observe/startAndEndTime");
|
|
12
13
|
const json_1 = require("../../utils/json");
|
|
13
14
|
class ObserveVersions extends EasCommand_1.default {
|
|
@@ -16,7 +17,7 @@ class ObserveVersions extends EasCommand_1.default {
|
|
|
16
17
|
static flags = {
|
|
17
18
|
platform: core_1.Flags.option({
|
|
18
19
|
description: 'Filter by platform',
|
|
19
|
-
options:
|
|
20
|
+
options: platforms_1.allowedPlatformFlagValues,
|
|
20
21
|
})(),
|
|
21
22
|
start: core_1.Flags.string({
|
|
22
23
|
description: 'Start of time range (ISO date)',
|
|
@@ -45,20 +46,13 @@ class ObserveVersions extends EasCommand_1.default {
|
|
|
45
46
|
};
|
|
46
47
|
async runAsync() {
|
|
47
48
|
const { flags } = await this.parse(ObserveVersions);
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
const ctx = await this.getContextAsync(ObserveVersions, {
|
|
57
|
-
nonInteractive: flags['non-interactive'],
|
|
58
|
-
});
|
|
59
|
-
projectId = ctx.projectId;
|
|
60
|
-
graphqlClient = ctx.loggedIn.graphqlClient;
|
|
61
|
-
}
|
|
49
|
+
const { projectId, graphqlClient } = await (0, resolveProjectContext_1.resolveObserveCommandContextAsync)({
|
|
50
|
+
command: this,
|
|
51
|
+
commandClass: ObserveVersions,
|
|
52
|
+
loggedInOnlyContextDefinition: ObserveVersions.loggedInOnlyContextDefinition,
|
|
53
|
+
projectIdOverride: flags['project-id'],
|
|
54
|
+
nonInteractive: flags['non-interactive'],
|
|
55
|
+
});
|
|
62
56
|
if (flags.json) {
|
|
63
57
|
(0, json_1.enableJsonOutput)();
|
|
64
58
|
}
|
|
@@ -66,9 +60,7 @@ class ObserveVersions extends EasCommand_1.default {
|
|
|
66
60
|
log_1.default.warn('EAS Observe is in preview and subject to breaking changes.');
|
|
67
61
|
}
|
|
68
62
|
const { startTime, endTime } = (0, startAndEndTime_1.resolveTimeRange)(flags);
|
|
69
|
-
const platforms = flags.platform
|
|
70
|
-
? [flags.platform === 'android' ? generated_1.AppPlatform.Android : generated_1.AppPlatform.Ios]
|
|
71
|
-
: [generated_1.AppPlatform.Android, generated_1.AppPlatform.Ios];
|
|
63
|
+
const platforms = (0, platforms_1.appPlatformsFromFlag)(flags.platform);
|
|
72
64
|
const results = await (0, fetchVersions_1.fetchObserveVersionsAsync)(graphqlClient, projectId, platforms, startTime, endTime);
|
|
73
65
|
if (flags.json) {
|
|
74
66
|
(0, json_1.printJsonOnlyOutput)((0, formatVersions_1.buildObserveVersionsJson)(results));
|
|
@@ -51,6 +51,7 @@ class SimulatorStart extends EasCommand_1.default {
|
|
|
51
51
|
const platform = flags.platform === 'android' ? generated_1.AppPlatform.Android : generated_1.AppPlatform.Ios;
|
|
52
52
|
const createSpinner = (0, ora_1.ora)('🚀 Creating device run session').start();
|
|
53
53
|
let deviceRunSessionId;
|
|
54
|
+
let jobRunUrl;
|
|
54
55
|
try {
|
|
55
56
|
const session = await DeviceRunSessionMutation_1.DeviceRunSessionMutation.createDeviceRunSessionAsync(graphqlClient, {
|
|
56
57
|
appId: projectId,
|
|
@@ -60,7 +61,7 @@ class SimulatorStart extends EasCommand_1.default {
|
|
|
60
61
|
});
|
|
61
62
|
deviceRunSessionId = session.id;
|
|
62
63
|
const jobRunId = (0, nullthrows_1.default)(session.turtleJobRun?.id, 'Expected device run session to start');
|
|
63
|
-
|
|
64
|
+
jobRunUrl = (0, url_1.getBareJobRunUrl)(session.app.ownerAccount.name, session.app.slug, jobRunId);
|
|
64
65
|
createSpinner.succeed(`Device run session created (id: ${deviceRunSessionId}) ${(0, log_1.link)(jobRunUrl)}`);
|
|
65
66
|
}
|
|
66
67
|
catch (err) {
|
|
@@ -76,13 +77,13 @@ class SimulatorStart extends EasCommand_1.default {
|
|
|
76
77
|
const session = await DeviceRunSessionQuery_1.DeviceRunSessionQuery.byIdAsync(graphqlClient, deviceRunSessionId);
|
|
77
78
|
if (session.status === generated_1.DeviceRunSessionStatus.Errored ||
|
|
78
79
|
session.status === generated_1.DeviceRunSessionStatus.Stopped) {
|
|
79
|
-
throw new Error(`Device run session ${deviceRunSessionId} ${session.status.toLowerCase()} before the ${flags.type} daemon was ready
|
|
80
|
+
throw new Error(`Device run session ${deviceRunSessionId} ${session.status.toLowerCase()} before the ${flags.type} daemon was ready. ${(0, log_1.link)(jobRunUrl)}`);
|
|
80
81
|
}
|
|
81
82
|
const jobRunStatus = session.turtleJobRun?.status;
|
|
82
83
|
if (jobRunStatus === generated_1.JobRunStatus.Errored ||
|
|
83
84
|
jobRunStatus === generated_1.JobRunStatus.Canceled ||
|
|
84
85
|
jobRunStatus === generated_1.JobRunStatus.Finished) {
|
|
85
|
-
throw new Error(`Turtle job run for device run session ${deviceRunSessionId} ${jobRunStatus.toLowerCase()} before the ${flags.type} daemon was ready
|
|
86
|
+
throw new Error(`Turtle job run for device run session ${deviceRunSessionId} ${jobRunStatus.toLowerCase()} before the ${flags.type} daemon was ready. ${(0, log_1.link)(jobRunUrl)}`);
|
|
86
87
|
}
|
|
87
88
|
const logMessages = await fetchLogMessagesAsync(session.turtleJobRun?.logFileUrls ?? []);
|
|
88
89
|
result = checkReadiness(logMessages);
|
|
@@ -95,21 +96,99 @@ class SimulatorStart extends EasCommand_1.default {
|
|
|
95
96
|
}
|
|
96
97
|
catch (err) {
|
|
97
98
|
pollSpinner.fail(`Failed while polling for ${flags.type} daemon logs`);
|
|
99
|
+
await ensureDeviceRunSessionStoppedSafelyAsync(graphqlClient, deviceRunSessionId);
|
|
98
100
|
throw err;
|
|
99
101
|
}
|
|
100
102
|
if (!result.ready) {
|
|
101
103
|
pollSpinner.fail(`Timed out waiting for ${flags.type} daemon to start`);
|
|
102
|
-
|
|
104
|
+
await ensureDeviceRunSessionStoppedSafelyAsync(graphqlClient, deviceRunSessionId);
|
|
105
|
+
throw new Error(`Timed out after ${Math.round(POLL_TIMEOUT_MS / 1000)}s waiting for ${flags.type} daemon to start. ${(0, log_1.link)(jobRunUrl)}`);
|
|
103
106
|
}
|
|
104
107
|
log_1.default.newLine();
|
|
105
108
|
log_1.default.log(`🔑 Run the following in your shell to attach to ${flags.type}:`);
|
|
106
109
|
log_1.default.newLine();
|
|
107
110
|
log_1.default.log(result.message);
|
|
108
111
|
log_1.default.newLine();
|
|
109
|
-
|
|
112
|
+
if (flags['non-interactive']) {
|
|
113
|
+
log_1.default.log(`When you are done, stop the session with: eas simulator:stop --id ${deviceRunSessionId}`);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
await waitForSessionEndOrInterruptAsync({
|
|
117
|
+
graphqlClient,
|
|
118
|
+
deviceRunSessionId,
|
|
119
|
+
jobRunUrl,
|
|
120
|
+
});
|
|
110
121
|
}
|
|
111
122
|
}
|
|
112
123
|
exports.default = SimulatorStart;
|
|
124
|
+
async function waitForSessionEndOrInterruptAsync({ graphqlClient, deviceRunSessionId, jobRunUrl, }) {
|
|
125
|
+
const spinner = (0, ora_1.ora)(`Device run session active — press Ctrl+C to stop, or run \`eas simulator:stop --id ${deviceRunSessionId}\` from another shell`).start();
|
|
126
|
+
const abortController = new AbortController();
|
|
127
|
+
const { signal } = abortController;
|
|
128
|
+
const abortPromise = new Promise(resolve => {
|
|
129
|
+
signal.addEventListener('abort', () => {
|
|
130
|
+
resolve();
|
|
131
|
+
}, { once: true });
|
|
132
|
+
});
|
|
133
|
+
const sigintHandler = () => {
|
|
134
|
+
if (signal.aborted) {
|
|
135
|
+
// Force exit on a second Ctrl+C in case cleanup is hanging. The session may still be
|
|
136
|
+
// running on EAS, so tell the user how to make sure it gets terminated.
|
|
137
|
+
spinner.fail(`Aborted before the device run session could be stopped. Run \`eas simulator:stop --id ${deviceRunSessionId}\` to terminate it and avoid unexpected charges.`);
|
|
138
|
+
process.exit(130);
|
|
139
|
+
}
|
|
140
|
+
abortController.abort();
|
|
141
|
+
};
|
|
142
|
+
process.on('SIGINT', sigintHandler);
|
|
143
|
+
try {
|
|
144
|
+
while (!signal.aborted) {
|
|
145
|
+
let session;
|
|
146
|
+
try {
|
|
147
|
+
session = await DeviceRunSessionQuery_1.DeviceRunSessionQuery.byIdAsync(graphqlClient, deviceRunSessionId);
|
|
148
|
+
}
|
|
149
|
+
catch (err) {
|
|
150
|
+
log_1.default.debug(`Failed to poll device run session: ${err instanceof Error ? err.message : String(err)}`);
|
|
151
|
+
await Promise.race([(0, promise_1.sleepAsync)(POLL_INTERVAL_MS), abortPromise]);
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
const jobRunStatus = session.turtleJobRun?.status;
|
|
155
|
+
if (session.status === generated_1.DeviceRunSessionStatus.Errored ||
|
|
156
|
+
jobRunStatus === generated_1.JobRunStatus.Errored) {
|
|
157
|
+
spinner.fail(`Device run session errored. ${(0, log_1.link)(jobRunUrl)}`);
|
|
158
|
+
throw new Error(`Device run session ${deviceRunSessionId} errored.`);
|
|
159
|
+
}
|
|
160
|
+
if (session.status === generated_1.DeviceRunSessionStatus.Stopped ||
|
|
161
|
+
jobRunStatus === generated_1.JobRunStatus.Canceled ||
|
|
162
|
+
jobRunStatus === generated_1.JobRunStatus.Finished) {
|
|
163
|
+
spinner.succeed(`Device run session ended. ${(0, log_1.link)(jobRunUrl)}`);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
await Promise.race([(0, promise_1.sleepAsync)(POLL_INTERVAL_MS), abortPromise]);
|
|
167
|
+
}
|
|
168
|
+
spinner.text = 'Stopping device run session...';
|
|
169
|
+
const stopped = await ensureDeviceRunSessionStoppedSafelyAsync(graphqlClient, deviceRunSessionId);
|
|
170
|
+
if (stopped) {
|
|
171
|
+
spinner.succeed('Device run session stopped');
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
spinner.fail(`Could not confirm the device run session was stopped. Run \`eas simulator:stop --id ${deviceRunSessionId}\` to terminate it and avoid unexpected charges.`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
finally {
|
|
178
|
+
process.removeListener('SIGINT', sigintHandler);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
async function ensureDeviceRunSessionStoppedSafelyAsync(graphqlClient, deviceRunSessionId) {
|
|
182
|
+
try {
|
|
183
|
+
await DeviceRunSessionMutation_1.DeviceRunSessionMutation.ensureDeviceRunSessionStoppedAsync(graphqlClient, deviceRunSessionId);
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
catch (err) {
|
|
187
|
+
// Cleanup is best-effort; surface the failure but don't mask the original error.
|
|
188
|
+
log_1.default.warn(`Failed to stop device run session ${deviceRunSessionId}: ${err instanceof Error ? err.message : String(err)}`);
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
113
192
|
function getReadinessCheckerForType(type) {
|
|
114
193
|
switch (type) {
|
|
115
194
|
case DEVICE_RUN_SESSION_TYPE_FLAG_VALUES[generated_1.DeviceRunSessionType.AgentDevice]:
|
|
@@ -26,7 +26,7 @@ class SimulatorStop extends EasCommand_1.default {
|
|
|
26
26
|
});
|
|
27
27
|
const stopSpinner = (0, ora_1.ora)(`🛑 Stopping device run session ${flags.id}`).start();
|
|
28
28
|
try {
|
|
29
|
-
const session = await DeviceRunSessionMutation_1.DeviceRunSessionMutation.
|
|
29
|
+
const session = await DeviceRunSessionMutation_1.DeviceRunSessionMutation.ensureDeviceRunSessionStoppedAsync(graphqlClient, flags.id);
|
|
30
30
|
stopSpinner.succeed(`🎉 Device run session ${session.id} is ${session.status.toLowerCase()}`);
|
|
31
31
|
}
|
|
32
32
|
catch (err) {
|