@stim-cli/ci 1.36.0 → 1.38.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
CHANGED
|
@@ -36,6 +36,22 @@ device with `STIM_NO_RECORDED_BUILD`, and the failure's `remedy` names the comma
|
|
|
36
36
|
to run first, such as `stim-ci build --platform ios --scheme App`. `build` and
|
|
37
37
|
`run` must use the same Stim home: pass the same `--home`, or keep the default.
|
|
38
38
|
|
|
39
|
+
Every iOS and Android `run` on this machine starts the app from clean state on
|
|
40
|
+
the workspace's own simulator or emulator, including when the device already
|
|
41
|
+
has this build.
|
|
42
|
+
Before it installs, `run` uninstalls every other user app except XCUITest
|
|
43
|
+
runner apps, such as the ones agent-device installs. On iOS it also clears the
|
|
44
|
+
app's defaults and data container and resets the simulator keychain; on Android
|
|
45
|
+
it runs `pm clear` on the app. Simulator-wide settings such as privacy grants
|
|
46
|
+
are kept. A local simulator or emulator Stim does not own refuses with
|
|
47
|
+
`STIM_BAD_ARG` instead of skipping the cleanup. A run that `ios.remote` or
|
|
48
|
+
`android.remote` places on another machine or on EAS is not cleaned, and a
|
|
49
|
+
physical device is refused. `build` always compiles on this machine and ignores
|
|
50
|
+
`remote.build`. By default it compiles an iOS app, and an Android Debug app,
|
|
51
|
+
for this machine's architecture only, so when `run` can land on another
|
|
52
|
+
machine or on EAS, build
|
|
53
|
+
for that device too with `--arch all` (iOS) or `--abi all` (Android).
|
|
54
|
+
|
|
39
55
|
`--eas-profile <name>` (iOS and Android, build only) downloads a completed EAS
|
|
40
56
|
development build instead of compiling, as `stim ios --eas-profile` does; `run`
|
|
41
57
|
then installs it. Stim never starts an EAS build.
|
|
@@ -93,6 +109,13 @@ run options other than those that build.
|
|
|
93
109
|
Everything after `--` is an argument vector. No shell is inferred. To use shell
|
|
94
110
|
syntax, pass a shell explicitly: `-- bash -e -o pipefail -c 'pnpm test:e2e'`.
|
|
95
111
|
|
|
112
|
+
Without `--`, `run` installs and launches the app, writes `run.json`, then stops the
|
|
113
|
+
workspace as after a passing test, with `test: null` and exit code 0. Use it when a
|
|
114
|
+
later step drives a Release app on the device `run.json` names; boot a simulator again
|
|
115
|
+
by its UDID, since cleanup shuts it down. Cleanup also stops Metro, so a Debug app has
|
|
116
|
+
no bundler in that later step. An explicit `--` with no command after it is
|
|
117
|
+
refused. The library's `runCI` behaves the same when `command` is omitted.
|
|
118
|
+
|
|
96
119
|
The test process runs in the project directory. It receives the caller's
|
|
97
120
|
environment plus these values:
|
|
98
121
|
|
|
@@ -126,7 +149,7 @@ the `test` result, optional `failure`, `diagnostics`, and `cleanup`.
|
|
|
126
149
|
If a progress callback or writing `result.json` fails, the result includes
|
|
127
150
|
`reportingError`. Reporter failures cannot interrupt cleanup or replace an earlier
|
|
128
151
|
test failure; after a passing test, they return 1.
|
|
129
|
-
Setup failure leaves `run` and `test` null. Diagnostics include the last 1000
|
|
152
|
+
Setup failure leaves `run` and `test` null; a run without a command leaves `test` null. Diagnostics include the last 1000
|
|
130
153
|
structured records and their original directory. After cleanup, regular `.log`
|
|
131
154
|
and `.ndjson` files (including `.1` rotated copies) directly inside that directory
|
|
132
155
|
are copied into `logs/` and listed in `diagnostics.files`. This retains raw
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { n as buildCI, t as runCI } from "./src-
|
|
1
|
+
import { n as buildCI, t as runCI } from "./src-DJH6gv01.mjs";
|
|
2
2
|
import { parseArgs } from "node:util";
|
|
3
3
|
//#region src/cli.ts
|
|
4
4
|
const HELP = `Usage: stim-ci build --platform <ios|android|macos> [options]
|
|
5
|
-
stim-ci run --platform <ios|android|macos|web> [options] -- <command> [args...]
|
|
5
|
+
stim-ci run --platform <ios|android|macos|web> [options] [-- <command> [args...]]
|
|
6
6
|
|
|
7
7
|
Build is the only step that compiles. It records the app for this checkout, platform and
|
|
8
8
|
selectors, and exports it only with --export.
|
|
9
|
-
Run installs and launches the app the last matching build recorded, runs
|
|
10
|
-
stops the app. It never builds; with no recorded build it refuses
|
|
9
|
+
Run installs and launches the app the last matching build recorded, runs the test command
|
|
10
|
+
given after --, if any, and stops the app. It never builds; with no recorded build it refuses
|
|
11
|
+
and names the build to run.
|
|
11
12
|
The final result is JSON on stdout; progress and test output go to stderr. No result, test or
|
|
12
13
|
diagnostic file is written unless --artifacts is given.
|
|
13
14
|
|
|
@@ -110,8 +111,7 @@ function parse(argv) {
|
|
|
110
111
|
}
|
|
111
112
|
};
|
|
112
113
|
}
|
|
113
|
-
if (separator
|
|
114
|
-
if (!command[0]) throw new Error("A test command is required after --.");
|
|
114
|
+
if (separator >= 0 && !command[0]) throw new Error("A test command is required after --.");
|
|
115
115
|
const run = platform === "ios" ? {
|
|
116
116
|
platform,
|
|
117
117
|
scheme: values.scheme,
|
|
@@ -125,13 +125,13 @@ function parse(argv) {
|
|
|
125
125
|
options: {
|
|
126
126
|
...common,
|
|
127
127
|
run,
|
|
128
|
-
command
|
|
128
|
+
...separator >= 0 ? { command } : {}
|
|
129
129
|
}
|
|
130
130
|
};
|
|
131
131
|
}
|
|
132
132
|
async function main(argv = process.argv.slice(2)) {
|
|
133
133
|
if (argv.length === 1 && argv[0] === "--version") {
|
|
134
|
-
process.stdout.write(`1.
|
|
134
|
+
process.stdout.write(`1.38.0\n`);
|
|
135
135
|
return;
|
|
136
136
|
}
|
|
137
137
|
if (argv.length === 0 || argv[0] === "--help" || (argv[0] === "run" || argv[0] === "build") && argv[1] === "--help") {
|
package/dist/index.d.mts
CHANGED
|
@@ -22,9 +22,10 @@ interface CommandResult {
|
|
|
22
22
|
}
|
|
23
23
|
//#endregion
|
|
24
24
|
//#region src/build.d.ts
|
|
25
|
-
type
|
|
25
|
+
type WithoutKeys$1<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;
|
|
26
26
|
interface CIBuildOptions extends CIContextOptions {
|
|
27
|
-
|
|
27
|
+
/** Always compiles on this machine; `remoteBuild` is not accepted. */
|
|
28
|
+
build: WithoutKeys$1<StimBuildOptions, "signal" | "remoteBuild">;
|
|
28
29
|
/** Also writes the app here as a portable APK (Android) or tar.gz (iOS, macOS); without it the build is only recorded for `run`. */
|
|
29
30
|
exportPath?: string;
|
|
30
31
|
}
|
|
@@ -56,8 +57,9 @@ declare function buildCI(input: CIBuildOptions): Promise<CIBuildResult>;
|
|
|
56
57
|
type WithoutKeys<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;
|
|
57
58
|
interface CIOptions extends CIContextOptions {
|
|
58
59
|
/** Selectors of the recorded build to run. `run` never builds, so build-time options such as `easProfile` belong to `buildCI`. */
|
|
59
|
-
run: WithoutKeys<StimRunOptions, "signal" | "recordedBuild" | "easProfile">;
|
|
60
|
-
command
|
|
60
|
+
run: WithoutKeys<StimRunOptions, "signal" | "recordedBuild" | "cleanAppState" | "easProfile">;
|
|
61
|
+
/** Test command argv. Without it, `runCI` installs and launches the app, then stops it as after a passing test. */
|
|
62
|
+
command?: readonly [string, ...string[]];
|
|
61
63
|
}
|
|
62
64
|
interface CIFailure {
|
|
63
65
|
code: string;
|
|
@@ -88,7 +90,7 @@ interface CIResult {
|
|
|
88
90
|
error?: CIFailure;
|
|
89
91
|
};
|
|
90
92
|
}
|
|
91
|
-
/** Runs an app and argv-based test command, stops its workspace or explicit slot, and retains diagnostics. */
|
|
93
|
+
/** Runs an app and an optional argv-based test command, stops its workspace or explicit slot, and retains diagnostics. */
|
|
92
94
|
declare function runCI(options: CIOptions): Promise<CIResult>;
|
|
93
95
|
//#endregion
|
|
94
96
|
export { type CIBuildOptions, type CIBuildResult, CIFailure, CIOptions, CIResult, type CommandResult, buildCI, runCI };
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as buildCI, t as runCI } from "./src-
|
|
1
|
+
import { n as buildCI, t as runCI } from "./src-DJH6gv01.mjs";
|
|
2
2
|
export { buildCI, runCI };
|
|
@@ -201,6 +201,7 @@ async function buildCI(input) {
|
|
|
201
201
|
attempted = true;
|
|
202
202
|
result.build = await stim.build({
|
|
203
203
|
...options.build,
|
|
204
|
+
remoteBuild: "local",
|
|
204
205
|
signal
|
|
205
206
|
});
|
|
206
207
|
signal?.throwIfAborted();
|
|
@@ -296,10 +297,10 @@ function commandEnvironment(result, options) {
|
|
|
296
297
|
STIM_CI_RUN_RESULT: result.runPath ?? ""
|
|
297
298
|
};
|
|
298
299
|
}
|
|
299
|
-
/** Runs an app and argv-based test command, stops its workspace or explicit slot, and retains diagnostics. */
|
|
300
|
+
/** Runs an app and an optional argv-based test command, stops its workspace or explicit slot, and retains diagnostics. */
|
|
300
301
|
async function runCI(options) {
|
|
301
|
-
if (!options.command[0]) throw new Error("A non-empty test command is required.");
|
|
302
|
-
for (const argument of options.command) if (typeof argument !== "string" || argument.includes("\0")) throw new Error("Test command arguments must be strings without null bytes.");
|
|
302
|
+
if (options.command && !options.command[0]) throw new Error("A non-empty test command is required.");
|
|
303
|
+
for (const argument of options.command ?? []) if (typeof argument !== "string" || argument.includes("\0")) throw new Error("Test command arguments must be strings without null bytes.");
|
|
303
304
|
const prepared = prepareCI(options);
|
|
304
305
|
options = prepared.options;
|
|
305
306
|
const { projectRoot, artifactsDir, timeout, signal } = prepared;
|
|
@@ -341,26 +342,30 @@ async function runCI(options) {
|
|
|
341
342
|
result.run = await stim.run({
|
|
342
343
|
...options.run,
|
|
343
344
|
recordedBuild: true,
|
|
345
|
+
cleanAppState: true,
|
|
344
346
|
signal
|
|
345
347
|
});
|
|
346
348
|
signal?.throwIfAborted();
|
|
347
349
|
if (result.runPath) writeJson(result.runPath, result.run);
|
|
348
|
-
result.
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
350
|
+
if (!options.command) result.exitCode = 0;
|
|
351
|
+
else {
|
|
352
|
+
result.test = await runCommand({
|
|
353
|
+
command: options.command,
|
|
354
|
+
cwd: projectRoot,
|
|
355
|
+
env: commandEnvironment(result, options),
|
|
356
|
+
artifactsDir,
|
|
357
|
+
signal,
|
|
358
|
+
onOutput: onProgress
|
|
359
|
+
});
|
|
360
|
+
result.exitCode = result.test.exitCode ?? 1;
|
|
361
|
+
if (result.exitCode < 0 || result.exitCode === 0 && result.test.error) result.exitCode = 1;
|
|
362
|
+
if (result.exitCode !== 0) result.failure = {
|
|
363
|
+
code: "STIM_CI_TEST_FAILED",
|
|
364
|
+
message: result.test.error ?? `Test command ${result.test.signal ? `was terminated by ${result.test.signal}` : `exited with ${result.exitCode}`}.`
|
|
365
|
+
};
|
|
366
|
+
}
|
|
362
367
|
} catch (error) {
|
|
363
|
-
result.failure = failure(error, result.run ? "STIM_CI_TEST_FAILED" : "STIM_CI_SETUP_FAILED");
|
|
368
|
+
result.failure = failure(error, result.run && options.command ? "STIM_CI_TEST_FAILED" : "STIM_CI_SETUP_FAILED");
|
|
364
369
|
if (result.failure.code === "STIM_NO_RECORDED_BUILD") result.failure.remedy = `Run ${buildCommand(options, projectRoot)} first.`;
|
|
365
370
|
} finally {
|
|
366
371
|
cleaningUp = true;
|
package/dist/stim-ci.mjs
CHANGED
|
@@ -6,6 +6,6 @@ const minor = parts[1] ?? 0;
|
|
|
6
6
|
if (major < 22 || major === 22 && minor < 12) {
|
|
7
7
|
process.stderr.write(`stim-ci requires Node.js 22.12.0 or later; this is ${process.versions.node}.\n`);
|
|
8
8
|
process.exitCode = 1;
|
|
9
|
-
} else import("./cli-
|
|
9
|
+
} else import("./cli-BKK3T47P.mjs").then(({ main }) => main());
|
|
10
10
|
//#endregion
|
|
11
11
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stim-cli/ci",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.38.0",
|
|
4
4
|
"description": "Build Stim app artifacts or run Stim apps and test commands in CI with diagnostics and scoped cleanup.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"cross-spawn": "^7.0.6",
|
|
36
|
-
"stim": "1.
|
|
36
|
+
"stim": "1.38.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/cross-spawn": "^6.0.6"
|