eas-cli 20.0.0 → 20.1.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 +176 -106
- package/build/commands/simulator/exec.d.ts +12 -0
- package/build/commands/simulator/exec.js +42 -0
- package/build/commands/simulator/get.d.ts +2 -1
- package/build/commands/simulator/get.js +13 -7
- package/build/commands/simulator/start.d.ts +3 -0
- package/build/commands/simulator/start.js +65 -5
- package/build/commands/simulator/stop.d.ts +2 -1
- package/build/commands/simulator/stop.js +16 -9
- package/build/commands/update/embedded/delete.d.ts +15 -0
- package/build/commands/update/embedded/delete.js +55 -0
- package/build/commands/update/embedded/list.d.ts +19 -0
- package/build/commands/update/embedded/list.js +132 -0
- package/build/commands/update/embedded/view.d.ts +17 -0
- package/build/commands/update/embedded/view.js +75 -0
- package/build/graphql/generated.d.ts +365 -4
- package/build/graphql/generated.js +35 -1
- package/build/graphql/mutations/EmbeddedUpdateMutation.d.ts +5 -0
- package/build/graphql/mutations/EmbeddedUpdateMutation.js +14 -0
- package/build/graphql/queries/EmbeddedUpdateQuery.d.ts +18 -0
- package/build/graphql/queries/EmbeddedUpdateQuery.js +81 -0
- package/build/simulator/env.d.ts +7 -0
- package/build/simulator/env.js +44 -0
- package/build/simulator/utils.d.ts +3 -1
- package/build/simulator/utils.js +26 -7
- package/oclif.manifest.json +1092 -724
- package/package.json +5 -5
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import EasCommand from '../../commandUtils/EasCommand';
|
|
2
|
+
export default class SimulatorExec extends EasCommand {
|
|
3
|
+
static hidden: boolean;
|
|
4
|
+
static description: string;
|
|
5
|
+
static strict: boolean;
|
|
6
|
+
static contextDefinition: {
|
|
7
|
+
projectDir: import("../../commandUtils/context/ProjectDirContextField").default;
|
|
8
|
+
};
|
|
9
|
+
private isRunningSubprocess;
|
|
10
|
+
runAsync(): Promise<void>;
|
|
11
|
+
protected catch(err: Error): Promise<any>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const spawn_async_1 = tslib_1.__importDefault(require("@expo/spawn-async"));
|
|
5
|
+
const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
|
|
6
|
+
const env_1 = require("../../simulator/env");
|
|
7
|
+
class SimulatorExec extends EasCommand_1.default {
|
|
8
|
+
static hidden = true;
|
|
9
|
+
static description = `[EXPERIMENTAL] execute a simulator command with ${env_1.SIMULATOR_DOTENV_FILE_NAME} environment loaded`;
|
|
10
|
+
static strict = false;
|
|
11
|
+
static contextDefinition = {
|
|
12
|
+
...this.ContextOptions.ProjectDir,
|
|
13
|
+
};
|
|
14
|
+
isRunningSubprocess = false;
|
|
15
|
+
async runAsync() {
|
|
16
|
+
const rawArgv = [...this.argv];
|
|
17
|
+
// Required to avoid `Warning: Command exec did not parse its arguments. Did you forget to call 'this.parse'?`
|
|
18
|
+
await this.parse(SimulatorExec, []);
|
|
19
|
+
const [command, ...args] = rawArgv;
|
|
20
|
+
if (typeof command !== 'string' || command.length === 0) {
|
|
21
|
+
throw new Error('No command provided. Run `eas simulator:exec <command> [args...]`.');
|
|
22
|
+
}
|
|
23
|
+
const { projectDir } = await this.getContextAsync(SimulatorExec, {
|
|
24
|
+
nonInteractive: true,
|
|
25
|
+
});
|
|
26
|
+
await (0, env_1.loadSimulatorEnvAsync)(projectDir);
|
|
27
|
+
this.isRunningSubprocess = true;
|
|
28
|
+
await (0, spawn_async_1.default)(command, args, {
|
|
29
|
+
stdio: 'inherit',
|
|
30
|
+
env: process.env,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
catch(err) {
|
|
34
|
+
// Propagate wrapped command from spawnAsync rejection
|
|
35
|
+
if (this.isRunningSubprocess) {
|
|
36
|
+
process.exitCode = process.exitCode ?? err.status ?? 1;
|
|
37
|
+
return Promise.resolve();
|
|
38
|
+
}
|
|
39
|
+
return super.catch(err);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
exports.default = SimulatorExec;
|
|
@@ -5,9 +5,10 @@ export default class SimulatorGet extends EasCommand {
|
|
|
5
5
|
static flags: {
|
|
6
6
|
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
7
7
|
'non-interactive': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
8
|
-
id: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
8
|
+
id: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
9
9
|
};
|
|
10
10
|
static contextDefinition: {
|
|
11
|
+
projectDir: import("../../commandUtils/context/ProjectDirContextField").default;
|
|
11
12
|
loggedIn: import("../../commandUtils/context/LoggedInContextField").default;
|
|
12
13
|
};
|
|
13
14
|
runAsync(): Promise<void>;
|
|
@@ -9,6 +9,7 @@ const generated_1 = require("../../graphql/generated");
|
|
|
9
9
|
const DeviceRunSessionQuery_1 = require("../../graphql/queries/DeviceRunSessionQuery");
|
|
10
10
|
const log_1 = tslib_1.__importStar(require("../../log"));
|
|
11
11
|
const ora_1 = require("../../ora");
|
|
12
|
+
const env_1 = require("../../simulator/env");
|
|
12
13
|
const utils_1 = require("../../simulator/utils");
|
|
13
14
|
const json_1 = require("../../utils/json");
|
|
14
15
|
class SimulatorGet extends EasCommand_1.default {
|
|
@@ -16,13 +17,13 @@ class SimulatorGet extends EasCommand_1.default {
|
|
|
16
17
|
static description = '[EXPERIMENTAL] get info about a remote simulator session on EAS by its device run session ID';
|
|
17
18
|
static flags = {
|
|
18
19
|
id: core_1.Flags.string({
|
|
19
|
-
description:
|
|
20
|
-
required: true,
|
|
20
|
+
description: `Device run session ID. Defaults to ${env_1.SIMULATOR_DOTENV_FILE_NAME}.`,
|
|
21
21
|
}),
|
|
22
22
|
...flags_1.EasNonInteractiveAndJsonFlags,
|
|
23
23
|
};
|
|
24
24
|
static contextDefinition = {
|
|
25
25
|
...this.ContextOptions.LoggedIn,
|
|
26
|
+
...this.ContextOptions.ProjectDir,
|
|
26
27
|
};
|
|
27
28
|
async runAsync() {
|
|
28
29
|
const { flags } = await this.parse(SimulatorGet);
|
|
@@ -30,17 +31,22 @@ class SimulatorGet extends EasCommand_1.default {
|
|
|
30
31
|
if (jsonFlag) {
|
|
31
32
|
(0, json_1.enableJsonOutput)();
|
|
32
33
|
}
|
|
33
|
-
const { loggedIn: { graphqlClient }, } = await this.getContextAsync(SimulatorGet, {
|
|
34
|
+
const { projectDir, loggedIn: { graphqlClient }, } = await this.getContextAsync(SimulatorGet, {
|
|
34
35
|
nonInteractive,
|
|
35
36
|
});
|
|
36
|
-
|
|
37
|
+
await (0, env_1.loadSimulatorEnvAsync)(projectDir);
|
|
38
|
+
const flagId = flags.id || process.env[env_1.EAS_SIMULATOR_SESSION_ID];
|
|
39
|
+
if (!flagId) {
|
|
40
|
+
throw new Error(`No simulator session ID provided. Pass --id, or run \`eas simulator:start\` first to write ${env_1.SIMULATOR_DOTENV_FILE_NAME}.`);
|
|
41
|
+
}
|
|
42
|
+
const fetchSpinner = (0, ora_1.ora)(`Fetching device run session ${flagId}`).start();
|
|
37
43
|
let session;
|
|
38
44
|
try {
|
|
39
|
-
session = await DeviceRunSessionQuery_1.DeviceRunSessionQuery.byIdAsync(graphqlClient,
|
|
45
|
+
session = await DeviceRunSessionQuery_1.DeviceRunSessionQuery.byIdAsync(graphqlClient, flagId);
|
|
40
46
|
fetchSpinner.succeed(`Fetched device run session ${session.id}`);
|
|
41
47
|
}
|
|
42
48
|
catch (err) {
|
|
43
|
-
fetchSpinner.fail(`Failed to fetch device run session ${
|
|
49
|
+
fetchSpinner.fail(`Failed to fetch device run session ${flagId}`);
|
|
44
50
|
throw err;
|
|
45
51
|
}
|
|
46
52
|
const jobRunUrl = session.turtleJobRun
|
|
@@ -64,7 +70,7 @@ class SimulatorGet extends EasCommand_1.default {
|
|
|
64
70
|
if (session.status === generated_1.DeviceRunSessionStatus.InProgress) {
|
|
65
71
|
log_1.default.newLine();
|
|
66
72
|
if (session.remoteConfig) {
|
|
67
|
-
log_1.default.log((0, utils_1.formatRemoteSessionInstructions)(session.remoteConfig));
|
|
73
|
+
log_1.default.log((0, utils_1.formatRemoteSessionInstructions)(session.remoteConfig, 'env'));
|
|
68
74
|
}
|
|
69
75
|
else {
|
|
70
76
|
log_1.default.log('⏳ Session is starting up — remote config is not available yet. Re-run this command in a moment.');
|
|
@@ -8,9 +8,12 @@ export default class SimulatorStart extends EasCommand {
|
|
|
8
8
|
platform: import("@oclif/core/lib/interfaces").OptionFlag<"android" | "ios", import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
9
9
|
type: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
10
10
|
'package-version': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
11
|
+
force: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
12
|
+
'out-config-type': import("@oclif/core/lib/interfaces").OptionFlag<"env" | "dotenv", import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
11
13
|
};
|
|
12
14
|
static contextDefinition: {
|
|
13
15
|
loggedIn: import("../../commandUtils/context/LoggedInContextField").default;
|
|
16
|
+
projectDir: import("../../commandUtils/context/ProjectDirContextField").default;
|
|
14
17
|
projectId: import("../../commandUtils/context/ProjectIdContextField").ProjectIdContextField;
|
|
15
18
|
};
|
|
16
19
|
runAsync(): Promise<void>;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const core_1 = require("@oclif/core");
|
|
5
|
+
const nullthrows_1 = tslib_1.__importDefault(require("nullthrows"));
|
|
5
6
|
const url_1 = require("../../build/utils/url");
|
|
6
7
|
const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasCommand"));
|
|
7
8
|
const flags_1 = require("../../commandUtils/flags");
|
|
@@ -10,12 +11,16 @@ const DeviceRunSessionMutation_1 = require("../../graphql/mutations/DeviceRunSes
|
|
|
10
11
|
const DeviceRunSessionQuery_1 = require("../../graphql/queries/DeviceRunSessionQuery");
|
|
11
12
|
const log_1 = tslib_1.__importStar(require("../../log"));
|
|
12
13
|
const ora_1 = require("../../ora");
|
|
14
|
+
const env_1 = require("../../simulator/env");
|
|
13
15
|
const utils_1 = require("../../simulator/utils");
|
|
14
16
|
const json_1 = require("../../utils/json");
|
|
15
17
|
const promise_1 = require("../../utils/promise");
|
|
16
|
-
const nullthrows_1 = tslib_1.__importDefault(require("nullthrows"));
|
|
17
18
|
const POLL_INTERVAL_MS = 5_000; // 5 seconds
|
|
18
19
|
const POLL_TIMEOUT_MS = 15 * 60 * 1_000; // 15 minutes
|
|
20
|
+
const OUT_CONFIG_TYPE_VALUES = {
|
|
21
|
+
Env: 'env',
|
|
22
|
+
Dotenv: 'dotenv',
|
|
23
|
+
};
|
|
19
24
|
class SimulatorStart extends EasCommand_1.default {
|
|
20
25
|
static hidden = true;
|
|
21
26
|
static description = '[EXPERIMENTAL] start a remote simulator session on EAS and get instructions to connect to it';
|
|
@@ -33,10 +38,21 @@ class SimulatorStart extends EasCommand_1.default {
|
|
|
33
38
|
'package-version': core_1.Flags.string({
|
|
34
39
|
description: 'Version of the package backing the device run session (e.g. "0.1.3-alpha.3"). Defaults to "latest" when omitted.',
|
|
35
40
|
}),
|
|
41
|
+
force: core_1.Flags.boolean({
|
|
42
|
+
description: '[default: true] Create a new device session even when an existing simulator session is present in the environment.',
|
|
43
|
+
default: true,
|
|
44
|
+
allowNo: true,
|
|
45
|
+
}),
|
|
46
|
+
'out-config-type': core_1.Flags.option({
|
|
47
|
+
description: `How to output simulator connection configuration. Use "env" to print shell exports, or "dotenv" to write ${env_1.SIMULATOR_DOTENV_FILE_NAME}.`,
|
|
48
|
+
options: Object.values(OUT_CONFIG_TYPE_VALUES),
|
|
49
|
+
default: OUT_CONFIG_TYPE_VALUES.Dotenv,
|
|
50
|
+
})(),
|
|
36
51
|
...flags_1.EasNonInteractiveAndJsonFlags,
|
|
37
52
|
};
|
|
38
53
|
static contextDefinition = {
|
|
39
54
|
...this.ContextOptions.ProjectId,
|
|
55
|
+
...this.ContextOptions.ProjectDir,
|
|
40
56
|
...this.ContextOptions.LoggedIn,
|
|
41
57
|
};
|
|
42
58
|
async runAsync() {
|
|
@@ -45,9 +61,20 @@ class SimulatorStart extends EasCommand_1.default {
|
|
|
45
61
|
if (jsonFlag) {
|
|
46
62
|
(0, json_1.enableJsonOutput)();
|
|
47
63
|
}
|
|
48
|
-
const { projectId, loggedIn: { graphqlClient }, } = await this.getContextAsync(SimulatorStart, {
|
|
64
|
+
const { projectId, projectDir, loggedIn: { graphqlClient }, } = await this.getContextAsync(SimulatorStart, {
|
|
49
65
|
nonInteractive,
|
|
50
66
|
});
|
|
67
|
+
await (0, env_1.loadSimulatorEnvAsync)(projectDir);
|
|
68
|
+
const existingDeviceRunSessionId = process.env[env_1.EAS_SIMULATOR_SESSION_ID];
|
|
69
|
+
if (existingDeviceRunSessionId && !flags.force) {
|
|
70
|
+
throw new Error(`Existing simulator session in environment. Use --force to create a new device session.`);
|
|
71
|
+
}
|
|
72
|
+
if (existingDeviceRunSessionId) {
|
|
73
|
+
log_1.default.warn(` Overwriting previous simulator session (id: ${existingDeviceRunSessionId}). ` +
|
|
74
|
+
`The previous remote session will continue running until stopped. ` +
|
|
75
|
+
`To stop it, run: eas simulator:stop --id ${existingDeviceRunSessionId}`);
|
|
76
|
+
log_1.default.newLine();
|
|
77
|
+
}
|
|
51
78
|
const platform = flags.platform === 'android' ? generated_1.AppPlatform.Android : generated_1.AppPlatform.Ios;
|
|
52
79
|
const createSpinner = (0, ora_1.ora)('🚀 Creating device run session').start();
|
|
53
80
|
let deviceRunSessionId;
|
|
@@ -62,7 +89,12 @@ class SimulatorStart extends EasCommand_1.default {
|
|
|
62
89
|
deviceRunSessionId = session.id;
|
|
63
90
|
const jobRunId = (0, nullthrows_1.default)(session.turtleJobRun?.id, 'Expected device run session to start');
|
|
64
91
|
jobRunUrl = (0, url_1.getBareJobRunUrl)(session.app.ownerAccount.name, session.app.slug, jobRunId);
|
|
65
|
-
|
|
92
|
+
const simulatorEnvWritten = !jsonFlag && flags['out-config-type'] === OUT_CONFIG_TYPE_VALUES.Dotenv
|
|
93
|
+
? await writeSimulatorEnvSafelyAsync(projectDir, {
|
|
94
|
+
[env_1.EAS_SIMULATOR_SESSION_ID]: deviceRunSessionId,
|
|
95
|
+
})
|
|
96
|
+
: false;
|
|
97
|
+
createSpinner.succeed(`Device run session created (id: ${deviceRunSessionId}${simulatorEnvWritten ? `, saved to ${env_1.SIMULATOR_DOTENV_FILE_NAME}` : ''}) ${(0, log_1.link)(jobRunUrl)}`);
|
|
66
98
|
}
|
|
67
99
|
catch (err) {
|
|
68
100
|
createSpinner.fail('Failed to create device run session');
|
|
@@ -102,6 +134,12 @@ class SimulatorStart extends EasCommand_1.default {
|
|
|
102
134
|
await ensureDeviceRunSessionStoppedSafelyAsync(graphqlClient, deviceRunSessionId);
|
|
103
135
|
throw new Error(`Timed out after ${Math.round(POLL_TIMEOUT_MS / 1000)}s waiting for ${flags.type} session to be ready. ${(0, log_1.link)(jobRunUrl)}`);
|
|
104
136
|
}
|
|
137
|
+
if (flags['out-config-type'] === OUT_CONFIG_TYPE_VALUES.Dotenv) {
|
|
138
|
+
await writeSimulatorEnvSafelyAsync(projectDir, {
|
|
139
|
+
...(0, utils_1.getRemoteSessionEnvironmentVariables)(remoteConfig),
|
|
140
|
+
[env_1.EAS_SIMULATOR_SESSION_ID]: deviceRunSessionId,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
105
143
|
if (jsonFlag) {
|
|
106
144
|
(0, json_1.printJsonOnlyOutput)({
|
|
107
145
|
id: deviceRunSessionId,
|
|
@@ -112,7 +150,7 @@ class SimulatorStart extends EasCommand_1.default {
|
|
|
112
150
|
return;
|
|
113
151
|
}
|
|
114
152
|
log_1.default.newLine();
|
|
115
|
-
log_1.default.log((0, utils_1.formatRemoteSessionInstructions)(remoteConfig));
|
|
153
|
+
log_1.default.log((0, utils_1.formatRemoteSessionInstructions)(remoteConfig, flags['out-config-type']));
|
|
116
154
|
log_1.default.newLine();
|
|
117
155
|
if (nonInteractive) {
|
|
118
156
|
log_1.default.log(`When you are done, stop the session with: eas simulator:stop --id ${deviceRunSessionId}`);
|
|
@@ -122,11 +160,22 @@ class SimulatorStart extends EasCommand_1.default {
|
|
|
122
160
|
graphqlClient,
|
|
123
161
|
deviceRunSessionId,
|
|
124
162
|
jobRunUrl,
|
|
163
|
+
projectDir,
|
|
125
164
|
});
|
|
126
165
|
}
|
|
127
166
|
}
|
|
128
167
|
exports.default = SimulatorStart;
|
|
129
|
-
async function
|
|
168
|
+
async function writeSimulatorEnvSafelyAsync(projectDir, environmentVariables) {
|
|
169
|
+
try {
|
|
170
|
+
await (0, env_1.writeSimulatorEnvAsync)(projectDir, environmentVariables);
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
catch (err) {
|
|
174
|
+
log_1.default.warn(`Failed to write simulator environment variables to ${env_1.SIMULATOR_DOTENV_FILE_NAME}: ${err instanceof Error ? err.message : String(err)}`);
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
async function waitForSessionEndOrInterruptAsync({ graphqlClient, deviceRunSessionId, jobRunUrl, projectDir, }) {
|
|
130
179
|
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();
|
|
131
180
|
const abortController = new AbortController();
|
|
132
181
|
const { signal } = abortController;
|
|
@@ -166,6 +215,7 @@ async function waitForSessionEndOrInterruptAsync({ graphqlClient, deviceRunSessi
|
|
|
166
215
|
jobRunStatus === generated_1.JobRunStatus.Canceled ||
|
|
167
216
|
jobRunStatus === generated_1.JobRunStatus.Finished) {
|
|
168
217
|
spinner.succeed(`Device run session ended. ${(0, log_1.link)(jobRunUrl)}`);
|
|
218
|
+
await resetSimulatorEnvVerboseAsync(projectDir);
|
|
169
219
|
return;
|
|
170
220
|
}
|
|
171
221
|
await Promise.race([(0, promise_1.sleepAsync)(POLL_INTERVAL_MS), abortPromise]);
|
|
@@ -174,6 +224,7 @@ async function waitForSessionEndOrInterruptAsync({ graphqlClient, deviceRunSessi
|
|
|
174
224
|
const stopped = await ensureDeviceRunSessionStoppedSafelyAsync(graphqlClient, deviceRunSessionId);
|
|
175
225
|
if (stopped) {
|
|
176
226
|
spinner.succeed('Device run session stopped');
|
|
227
|
+
await resetSimulatorEnvVerboseAsync(projectDir);
|
|
177
228
|
}
|
|
178
229
|
else {
|
|
179
230
|
spinner.fail(`Could not confirm the device run session was stopped. Run \`eas simulator:stop --id ${deviceRunSessionId}\` to terminate it and avoid unexpected charges.`);
|
|
@@ -183,6 +234,15 @@ async function waitForSessionEndOrInterruptAsync({ graphqlClient, deviceRunSessi
|
|
|
183
234
|
process.removeListener('SIGINT', sigintHandler);
|
|
184
235
|
}
|
|
185
236
|
}
|
|
237
|
+
async function resetSimulatorEnvVerboseAsync(projectDir) {
|
|
238
|
+
try {
|
|
239
|
+
await (0, env_1.resetSimulatorEnvAsync)(projectDir);
|
|
240
|
+
}
|
|
241
|
+
catch (err) {
|
|
242
|
+
log_1.default.error(`Failed to clean up ${env_1.SIMULATOR_DOTENV_FILE_NAME}`);
|
|
243
|
+
throw err;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
186
246
|
async function ensureDeviceRunSessionStoppedSafelyAsync(graphqlClient, deviceRunSessionId) {
|
|
187
247
|
try {
|
|
188
248
|
await DeviceRunSessionMutation_1.DeviceRunSessionMutation.ensureDeviceRunSessionStoppedAsync(graphqlClient, deviceRunSessionId);
|
|
@@ -5,9 +5,10 @@ export default class SimulatorStop extends EasCommand {
|
|
|
5
5
|
static flags: {
|
|
6
6
|
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
7
7
|
'non-interactive': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
8
|
-
id: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
8
|
+
id: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
9
9
|
};
|
|
10
10
|
static contextDefinition: {
|
|
11
|
+
projectDir: import("../../commandUtils/context/ProjectDirContextField").default;
|
|
11
12
|
loggedIn: import("../../commandUtils/context/LoggedInContextField").default;
|
|
12
13
|
};
|
|
13
14
|
runAsync(): Promise<void>;
|
|
@@ -6,19 +6,20 @@ const EasCommand_1 = tslib_1.__importDefault(require("../../commandUtils/EasComm
|
|
|
6
6
|
const flags_1 = require("../../commandUtils/flags");
|
|
7
7
|
const DeviceRunSessionMutation_1 = require("../../graphql/mutations/DeviceRunSessionMutation");
|
|
8
8
|
const ora_1 = require("../../ora");
|
|
9
|
+
const env_1 = require("../../simulator/env");
|
|
9
10
|
const json_1 = require("../../utils/json");
|
|
10
11
|
class SimulatorStop extends EasCommand_1.default {
|
|
11
12
|
static hidden = true;
|
|
12
13
|
static description = '[EXPERIMENTAL] stop a remote simulator session on EAS by its device run session ID';
|
|
13
14
|
static flags = {
|
|
14
15
|
id: core_1.Flags.string({
|
|
15
|
-
description:
|
|
16
|
-
required: true,
|
|
16
|
+
description: `Device run session ID. Defaults to ${env_1.SIMULATOR_DOTENV_FILE_NAME}.`,
|
|
17
17
|
}),
|
|
18
18
|
...flags_1.EasNonInteractiveAndJsonFlags,
|
|
19
19
|
};
|
|
20
20
|
static contextDefinition = {
|
|
21
21
|
...this.ContextOptions.LoggedIn,
|
|
22
|
+
...this.ContextOptions.ProjectDir,
|
|
22
23
|
};
|
|
23
24
|
async runAsync() {
|
|
24
25
|
const { flags } = await this.parse(SimulatorStop);
|
|
@@ -26,21 +27,27 @@ class SimulatorStop extends EasCommand_1.default {
|
|
|
26
27
|
if (jsonFlag) {
|
|
27
28
|
(0, json_1.enableJsonOutput)();
|
|
28
29
|
}
|
|
29
|
-
const { loggedIn: { graphqlClient }, } = await this.getContextAsync(SimulatorStop, {
|
|
30
|
+
const { projectDir, loggedIn: { graphqlClient }, } = await this.getContextAsync(SimulatorStop, {
|
|
30
31
|
nonInteractive,
|
|
31
32
|
});
|
|
32
|
-
|
|
33
|
+
await (0, env_1.loadSimulatorEnvAsync)(projectDir);
|
|
34
|
+
const flagId = flags.id || process.env[env_1.EAS_SIMULATOR_SESSION_ID];
|
|
35
|
+
if (!flagId) {
|
|
36
|
+
throw new Error(`No simulator session ID provided. Pass --id, or run \`eas simulator:start\` first to write ${env_1.SIMULATOR_DOTENV_FILE_NAME}.`);
|
|
37
|
+
}
|
|
38
|
+
const stopSpinner = (0, ora_1.ora)(`🛑 Stopping device run session ${flagId}`).start();
|
|
39
|
+
let session;
|
|
33
40
|
try {
|
|
34
|
-
|
|
41
|
+
session = await DeviceRunSessionMutation_1.DeviceRunSessionMutation.ensureDeviceRunSessionStoppedAsync(graphqlClient, flagId);
|
|
35
42
|
stopSpinner.succeed(`🎉 Device run session ${session.id} is ${session.status.toLowerCase()}`);
|
|
36
|
-
if (jsonFlag) {
|
|
37
|
-
(0, json_1.printJsonOnlyOutput)({ id: session.id, status: session.status });
|
|
38
|
-
}
|
|
39
43
|
}
|
|
40
44
|
catch (err) {
|
|
41
|
-
stopSpinner.fail(`Failed to stop device run session ${
|
|
45
|
+
stopSpinner.fail(`Failed to stop device run session ${flagId}`);
|
|
42
46
|
throw err;
|
|
43
47
|
}
|
|
48
|
+
if (jsonFlag) {
|
|
49
|
+
(0, json_1.printJsonOnlyOutput)({ id: session.id, status: session.status });
|
|
50
|
+
}
|
|
44
51
|
}
|
|
45
52
|
}
|
|
46
53
|
exports.default = SimulatorStop;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import EasCommand from '../../../commandUtils/EasCommand';
|
|
2
|
+
export default class UpdateEmbeddedDelete extends EasCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static args: {
|
|
5
|
+
id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
6
|
+
};
|
|
7
|
+
static flags: {
|
|
8
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
9
|
+
'non-interactive': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
};
|
|
11
|
+
static contextDefinition: {
|
|
12
|
+
loggedIn: import("../../../commandUtils/context/LoggedInContextField").default;
|
|
13
|
+
};
|
|
14
|
+
runAsync(): Promise<void>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
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 EmbeddedUpdateMutation_1 = require("../../../graphql/mutations/EmbeddedUpdateMutation");
|
|
8
|
+
const log_1 = tslib_1.__importDefault(require("../../../log"));
|
|
9
|
+
const prompts_1 = require("../../../prompts");
|
|
10
|
+
const json_1 = require("../../../utils/json");
|
|
11
|
+
class UpdateEmbeddedDelete extends EasCommand_1.default {
|
|
12
|
+
static description = 'delete an embedded update registered with EAS Update';
|
|
13
|
+
static args = {
|
|
14
|
+
id: core_1.Args.string({
|
|
15
|
+
required: true,
|
|
16
|
+
description: 'The ID of the embedded update (manifest UUID from app.manifest).',
|
|
17
|
+
}),
|
|
18
|
+
};
|
|
19
|
+
static flags = {
|
|
20
|
+
...flags_1.EasNonInteractiveAndJsonFlags,
|
|
21
|
+
};
|
|
22
|
+
static contextDefinition = {
|
|
23
|
+
...this.ContextOptions.LoggedIn,
|
|
24
|
+
};
|
|
25
|
+
async runAsync() {
|
|
26
|
+
const { args: { id: embeddedUpdateId }, flags, } = await this.parse(UpdateEmbeddedDelete);
|
|
27
|
+
const { json: jsonFlag, nonInteractive } = (0, flags_1.resolveNonInteractiveAndJsonFlags)(flags);
|
|
28
|
+
const { loggedIn: { graphqlClient }, } = await this.getContextAsync(UpdateEmbeddedDelete, { nonInteractive });
|
|
29
|
+
if (jsonFlag) {
|
|
30
|
+
(0, json_1.enableJsonOutput)();
|
|
31
|
+
}
|
|
32
|
+
if (!nonInteractive) {
|
|
33
|
+
log_1.default.log(`You are about to permanently delete embedded update: "${embeddedUpdateId}". ` +
|
|
34
|
+
`Diff patches already generated against this bundle keep serving, but new diffs ` +
|
|
35
|
+
`can't be generated until you re-upload it.`);
|
|
36
|
+
log_1.default.newLine();
|
|
37
|
+
const confirmed = await (0, prompts_1.toggleConfirmAsync)({ message: 'Are you sure you wish to proceed?' });
|
|
38
|
+
if (!confirmed) {
|
|
39
|
+
log_1.default.error(`Canceled deletion of embedded update: "${embeddedUpdateId}".`);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Best-effort delete on the server: deleting an unknown id succeeds (idempotent),
|
|
44
|
+
// so we don't need a not-found branch here.
|
|
45
|
+
await EmbeddedUpdateMutation_1.EmbeddedUpdateMutation.deleteEmbeddedUpdateAsync(graphqlClient, {
|
|
46
|
+
id: embeddedUpdateId,
|
|
47
|
+
});
|
|
48
|
+
if (jsonFlag) {
|
|
49
|
+
(0, json_1.printJsonOnlyOutput)({ id: embeddedUpdateId });
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
log_1.default.withTick(`Deleted embedded update ${embeddedUpdateId}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
exports.default = UpdateEmbeddedDelete;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Platform } from '@expo/eas-build-job';
|
|
2
|
+
import EasCommand from '../../../commandUtils/EasCommand';
|
|
3
|
+
export default class UpdateEmbeddedList extends EasCommand {
|
|
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<Platform | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
9
|
+
'runtime-version': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
10
|
+
channel: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
11
|
+
limit: import("@oclif/core/lib/interfaces").OptionFlag<number | undefined>;
|
|
12
|
+
'after-cursor': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
13
|
+
};
|
|
14
|
+
static contextDefinition: {
|
|
15
|
+
loggedIn: import("../../../commandUtils/context/LoggedInContextField").default;
|
|
16
|
+
projectId: import("../../../commandUtils/context/ProjectIdContextField").ProjectIdContextField;
|
|
17
|
+
};
|
|
18
|
+
runAsync(): Promise<void>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const eas_build_job_1 = require("@expo/eas-build-job");
|
|
5
|
+
const core_1 = require("@oclif/core");
|
|
6
|
+
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
7
|
+
const EasCommand_1 = tslib_1.__importDefault(require("../../../commandUtils/EasCommand"));
|
|
8
|
+
const flags_1 = require("../../../commandUtils/flags");
|
|
9
|
+
const pagination_1 = require("../../../commandUtils/pagination");
|
|
10
|
+
const ChannelQuery_1 = require("../../../graphql/queries/ChannelQuery");
|
|
11
|
+
const EmbeddedUpdateQuery_1 = require("../../../graphql/queries/EmbeddedUpdateQuery");
|
|
12
|
+
const AppPlatform_1 = require("../../../graphql/types/AppPlatform");
|
|
13
|
+
const log_1 = tslib_1.__importDefault(require("../../../log"));
|
|
14
|
+
const prompts_1 = require("../../../prompts");
|
|
15
|
+
const date_1 = require("../../../utils/date");
|
|
16
|
+
const formatFields_1 = tslib_1.__importDefault(require("../../../utils/formatFields"));
|
|
17
|
+
const json_1 = require("../../../utils/json");
|
|
18
|
+
const DEFAULT_LIMIT = 25;
|
|
19
|
+
const MAX_LIMIT = 50;
|
|
20
|
+
const CHANNELS_LIMIT = 50;
|
|
21
|
+
class UpdateEmbeddedList extends EasCommand_1.default {
|
|
22
|
+
static description = 'list embedded updates registered with EAS Update for this project';
|
|
23
|
+
static flags = {
|
|
24
|
+
platform: core_1.Flags.option({
|
|
25
|
+
char: 'p',
|
|
26
|
+
description: 'Filter by platform',
|
|
27
|
+
options: [eas_build_job_1.Platform.IOS, eas_build_job_1.Platform.ANDROID],
|
|
28
|
+
})(),
|
|
29
|
+
'runtime-version': core_1.Flags.string({
|
|
30
|
+
description: 'Filter by runtime version',
|
|
31
|
+
}),
|
|
32
|
+
channel: core_1.Flags.string({
|
|
33
|
+
description: 'Filter by channel name (pass "all" to skip the channel prompt)',
|
|
34
|
+
}),
|
|
35
|
+
limit: (0, pagination_1.getLimitFlagWithCustomValues)({ defaultTo: DEFAULT_LIMIT, limit: MAX_LIMIT }),
|
|
36
|
+
'after-cursor': core_1.Flags.string({
|
|
37
|
+
description: 'Return items after this cursor (for pagination)',
|
|
38
|
+
}),
|
|
39
|
+
...flags_1.EasNonInteractiveAndJsonFlags,
|
|
40
|
+
};
|
|
41
|
+
static contextDefinition = {
|
|
42
|
+
...this.ContextOptions.ProjectId,
|
|
43
|
+
...this.ContextOptions.LoggedIn,
|
|
44
|
+
};
|
|
45
|
+
async runAsync() {
|
|
46
|
+
const { flags } = await this.parse(UpdateEmbeddedList);
|
|
47
|
+
const { json: jsonFlag, nonInteractive } = (0, flags_1.resolveNonInteractiveAndJsonFlags)(flags);
|
|
48
|
+
const { projectId, loggedIn: { graphqlClient }, } = await this.getContextAsync(UpdateEmbeddedList, { nonInteractive });
|
|
49
|
+
if (jsonFlag) {
|
|
50
|
+
(0, json_1.enableJsonOutput)();
|
|
51
|
+
}
|
|
52
|
+
const platform = flags.platform
|
|
53
|
+
? (0, AppPlatform_1.toAppPlatform)(flags.platform)
|
|
54
|
+
: undefined;
|
|
55
|
+
// Resolve channel filter:
|
|
56
|
+
// - `--channel <name>`: use it
|
|
57
|
+
// - `--channel all` (or no flag in non-interactive / json): no channel filter
|
|
58
|
+
// - no flag in interactive: prompt with the project's channels + "All channels"
|
|
59
|
+
let channel;
|
|
60
|
+
if (flags.channel) {
|
|
61
|
+
channel = flags.channel.toLowerCase() === 'all' ? undefined : flags.channel;
|
|
62
|
+
}
|
|
63
|
+
else if (!nonInteractive && !jsonFlag) {
|
|
64
|
+
channel = await promptForChannelAsync(graphqlClient, projectId);
|
|
65
|
+
}
|
|
66
|
+
const filter = platform || flags['runtime-version'] || channel
|
|
67
|
+
? {
|
|
68
|
+
platform,
|
|
69
|
+
runtimeVersion: flags['runtime-version'],
|
|
70
|
+
channel,
|
|
71
|
+
}
|
|
72
|
+
: undefined;
|
|
73
|
+
const limit = flags.limit ?? DEFAULT_LIMIT;
|
|
74
|
+
const connection = await EmbeddedUpdateQuery_1.EmbeddedUpdateQuery.viewPaginatedAsync(graphqlClient, {
|
|
75
|
+
appId: projectId,
|
|
76
|
+
filter,
|
|
77
|
+
first: limit,
|
|
78
|
+
after: flags['after-cursor'],
|
|
79
|
+
});
|
|
80
|
+
const embeddedUpdates = connection.edges.map(e => e.node);
|
|
81
|
+
if (jsonFlag) {
|
|
82
|
+
(0, json_1.printJsonOnlyOutput)({
|
|
83
|
+
embeddedUpdates,
|
|
84
|
+
pageInfo: connection.pageInfo,
|
|
85
|
+
});
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
if (embeddedUpdates.length === 0) {
|
|
89
|
+
log_1.default.log('No embedded updates found.');
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
log_1.default.addNewLineIfNone();
|
|
93
|
+
log_1.default.log(chalk_1.default.bold(`Embedded updates (${embeddedUpdates.length}${connection.pageInfo.hasNextPage ? '+' : ''}):`));
|
|
94
|
+
log_1.default.newLine();
|
|
95
|
+
log_1.default.log(embeddedUpdates.map(formatEmbeddedUpdateRow).join(`\n\n${chalk_1.default.dim('———')}\n\n`));
|
|
96
|
+
if (connection.pageInfo.hasNextPage && connection.pageInfo.endCursor) {
|
|
97
|
+
log_1.default.newLine();
|
|
98
|
+
log_1.default.log(chalk_1.default.dim(`Showing ${embeddedUpdates.length}. For the next page, run with --after-cursor ${connection.pageInfo.endCursor}`));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
exports.default = UpdateEmbeddedList;
|
|
103
|
+
// Sentinel for the "All channels" option. We can't use `undefined` here because
|
|
104
|
+
// the underlying `prompts` library substitutes a choice's index when its value
|
|
105
|
+
// is undefined, which then leaks into the GraphQL filter.
|
|
106
|
+
const ALL_CHANNELS = '__embedded_update_list__all_channels__';
|
|
107
|
+
async function promptForChannelAsync(graphqlClient, projectId) {
|
|
108
|
+
const channels = await ChannelQuery_1.ChannelQuery.viewUpdateChannelsOnAppAsync(graphqlClient, {
|
|
109
|
+
appId: projectId,
|
|
110
|
+
offset: 0,
|
|
111
|
+
limit: CHANNELS_LIMIT,
|
|
112
|
+
});
|
|
113
|
+
if (channels.length === 0) {
|
|
114
|
+
// Nothing to choose from — fall back to listing everything.
|
|
115
|
+
return undefined;
|
|
116
|
+
}
|
|
117
|
+
const selected = await (0, prompts_1.selectAsync)('Filter embedded updates by which channel?', [
|
|
118
|
+
{ title: 'All channels', value: ALL_CHANNELS },
|
|
119
|
+
...channels.map(c => ({ title: c.name, value: c.name })),
|
|
120
|
+
]);
|
|
121
|
+
return selected === ALL_CHANNELS ? undefined : selected;
|
|
122
|
+
}
|
|
123
|
+
function formatEmbeddedUpdateRow(embeddedUpdate) {
|
|
124
|
+
const createdAt = new Date(embeddedUpdate.createdAt);
|
|
125
|
+
return (0, formatFields_1.default)([
|
|
126
|
+
{ label: 'ID', value: embeddedUpdate.id },
|
|
127
|
+
{ label: 'Platform', value: embeddedUpdate.platform.toLowerCase() },
|
|
128
|
+
{ label: 'Runtime version', value: embeddedUpdate.runtimeVersion },
|
|
129
|
+
{ label: 'Channel', value: embeddedUpdate.channel },
|
|
130
|
+
{ label: 'Created', value: `${(0, date_1.fromNow)(createdAt)} ago` },
|
|
131
|
+
]);
|
|
132
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import EasCommand from '../../../commandUtils/EasCommand';
|
|
2
|
+
import { EmbeddedUpdateFragment } from '../../../graphql/queries/EmbeddedUpdateQuery';
|
|
3
|
+
export default class UpdateEmbeddedView extends EasCommand {
|
|
4
|
+
static description: string;
|
|
5
|
+
static args: {
|
|
6
|
+
id: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
|
+
};
|
|
8
|
+
static flags: {
|
|
9
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
};
|
|
11
|
+
static contextDefinition: {
|
|
12
|
+
loggedIn: import("../../../commandUtils/context/LoggedInContextField").default;
|
|
13
|
+
projectId: import("../../../commandUtils/context/ProjectIdContextField").ProjectIdContextField;
|
|
14
|
+
};
|
|
15
|
+
runAsync(): Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
export declare function formatEmbeddedUpdate(embeddedUpdate: EmbeddedUpdateFragment): string;
|