@stim-cli/ci 1.37.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
@@ -109,6 +109,13 @@ run options other than those that build.
109
109
  Everything after `--` is an argument vector. No shell is inferred. To use shell
110
110
  syntax, pass a shell explicitly: `-- bash -e -o pipefail -c 'pnpm test:e2e'`.
111
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
+
112
119
  The test process runs in the project directory. It receives the caller's
113
120
  environment plus these values:
114
121
 
@@ -142,7 +149,7 @@ the `test` result, optional `failure`, `diagnostics`, and `cleanup`.
142
149
  If a progress callback or writing `result.json` fails, the result includes
143
150
  `reportingError`. Reporter failures cannot interrupt cleanup or replace an earlier
144
151
  test failure; after a passing test, they return 1.
145
- 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
146
153
  structured records and their original directory. After cleanup, regular `.log`
147
154
  and `.ndjson` files (including `.1` rotated copies) directly inside that directory
148
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-CFd6F73i.mjs";
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 a test command, and
10
- stops the app. It never builds; with no recorded build it refuses and names the build to run.
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 < 0) throw new Error("Separate the test command with --.");
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.37.0\n`);
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
@@ -58,7 +58,8 @@ type WithoutKeys<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : ne
58
58
  interface CIOptions extends CIContextOptions {
59
59
  /** Selectors of the recorded build to run. `run` never builds, so build-time options such as `easProfile` belong to `buildCI`. */
60
60
  run: WithoutKeys<StimRunOptions, "signal" | "recordedBuild" | "cleanAppState" | "easProfile">;
61
- command: readonly [string, ...string[]];
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[]];
62
63
  }
63
64
  interface CIFailure {
64
65
  code: string;
@@ -89,7 +90,7 @@ interface CIResult {
89
90
  error?: CIFailure;
90
91
  };
91
92
  }
92
- /** 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. */
93
94
  declare function runCI(options: CIOptions): Promise<CIResult>;
94
95
  //#endregion
95
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-CFd6F73i.mjs";
1
+ import { n as buildCI, t as runCI } from "./src-DJH6gv01.mjs";
2
2
  export { buildCI, runCI };
@@ -297,10 +297,10 @@ function commandEnvironment(result, options) {
297
297
  STIM_CI_RUN_RESULT: result.runPath ?? ""
298
298
  };
299
299
  }
300
- /** 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. */
301
301
  async function runCI(options) {
302
- if (!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.");
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.");
304
304
  const prepared = prepareCI(options);
305
305
  options = prepared.options;
306
306
  const { projectRoot, artifactsDir, timeout, signal } = prepared;
@@ -347,22 +347,25 @@ async function runCI(options) {
347
347
  });
348
348
  signal?.throwIfAborted();
349
349
  if (result.runPath) writeJson(result.runPath, result.run);
350
- result.test = await runCommand({
351
- command: options.command,
352
- cwd: projectRoot,
353
- env: commandEnvironment(result, options),
354
- artifactsDir,
355
- signal,
356
- onOutput: onProgress
357
- });
358
- result.exitCode = result.test.exitCode ?? 1;
359
- if (result.exitCode < 0 || result.exitCode === 0 && result.test.error) result.exitCode = 1;
360
- if (result.exitCode !== 0) result.failure = {
361
- code: "STIM_CI_TEST_FAILED",
362
- message: result.test.error ?? `Test command ${result.test.signal ? `was terminated by ${result.test.signal}` : `exited with ${result.exitCode}`}.`
363
- };
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
+ }
364
367
  } catch (error) {
365
- 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");
366
369
  if (result.failure.code === "STIM_NO_RECORDED_BUILD") result.failure.remedy = `Run ${buildCommand(options, projectRoot)} first.`;
367
370
  } finally {
368
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-BCFk6LoD.mjs").then(({ main }) => main());
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.37.0",
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.37.0"
36
+ "stim": "1.38.0"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/cross-spawn": "^6.0.6"