@opice/cli 0.4.1 → 0.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opice/cli",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "CLI for opice — scaffolds projects and wraps `bun test` to stream E2E results to the reporting platform",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli.ts CHANGED
@@ -14,10 +14,14 @@ Commands:
14
14
  Scaffold opice.config.json in the current project. Pass
15
15
  --with-workflow to also drop a .github/workflows/opice.yml.
16
16
 
17
- test [bun test args...]
17
+ test [--retries=N] [bun test args...]
18
18
  Wrapper around 'bun test' that exports OPICE_* env vars from
19
19
  opice.config.json + git so the harness reporter streams results
20
20
  to the platform. All trailing args pass through to bun test.
21
+ --retries=N sets a default retry budget for every scenario (a
22
+ flaky scenario that fails then passes is reported as flaky, not
23
+ failed). Falls back to "retries" in opice.config.json; a
24
+ per-scenario walkthrough/meta retries overrides both.
21
25
 
22
26
  failures <run-url|run-id> [--json]
23
27
  Pull a failed run's details (failed scenarios, the failing step,
@@ -43,8 +43,18 @@ export async function testCommand(args: string[]): Promise<number> {
43
43
  ...(git.commit ? { OPICE_COMMIT: git.commit } : {}),
44
44
  }
45
45
 
46
- // Always invoke `bun test`; any user-passed args go after.
47
- const child = spawn('bun', ['test', ...args], { stdio: 'inherit', env })
46
+ // `--retries=N` (opice's spelling) bun's `--retry=N`, the global default
47
+ // retry budget for every scenario. CLI flag wins over opice.config.json's
48
+ // `retries`. A per-scenario `walkthrough`/meta `retries` overrides both.
49
+ const { retries, rest } = extractRetries(args)
50
+ const resolvedRetries = retries ?? config?.retries
51
+ const bunArgs = ['test', ...rest]
52
+ // Don't clobber an explicit `--retry` the caller passed through to bun.
53
+ if (resolvedRetries !== undefined && !rest.some((a) => a === '--retry' || a.startsWith('--retry='))) {
54
+ bunArgs.push(`--retry=${resolvedRetries}`)
55
+ }
56
+
57
+ const child = spawn('bun', bunArgs, { stdio: 'inherit', env })
48
58
 
49
59
  const exitCode = await new Promise<number>((resolve) => {
50
60
  child.on('exit', (code) => resolve(code ?? 1))
@@ -57,6 +67,33 @@ export async function testCommand(args: string[]): Promise<number> {
57
67
  return exitCode
58
68
  }
59
69
 
70
+ /**
71
+ * Pull opice's `--retries=N` / `--retries N` out of the arg list (so it isn't
72
+ * forwarded to bun, which only knows `--retry`). Returns the parsed budget and
73
+ * the remaining args. An invalid value is ignored (falls through to config).
74
+ */
75
+ function extractRetries(args: string[]): { retries: number | undefined; rest: string[] } {
76
+ const rest: string[] = []
77
+ let retries: number | undefined
78
+ for (let i = 0; i < args.length; i++) {
79
+ const arg = args[i]
80
+ if (arg === undefined) continue
81
+ if (arg.startsWith('--retries=')) {
82
+ const n = Number(arg.slice('--retries='.length))
83
+ if (Number.isInteger(n) && n >= 0) retries = n
84
+ } else if (arg === '--retries') {
85
+ const n = Number(args[i + 1])
86
+ if (Number.isInteger(n) && n >= 0) {
87
+ retries = n
88
+ i++ // consume the value
89
+ }
90
+ } else {
91
+ rest.push(arg)
92
+ }
93
+ }
94
+ return { retries, rest }
95
+ }
96
+
60
97
  async function finalizeHandoffs(childPid: number | undefined, slug: string | undefined): Promise<void> {
61
98
  let files: string[]
62
99
  try {
package/src/config.ts CHANGED
@@ -4,6 +4,13 @@ import path from 'node:path'
4
4
  export interface OpiceConfig {
5
5
  project: string
6
6
  endpoint: string
7
+ /**
8
+ * Default retry budget applied to every scenario (passed to `bun test
9
+ * --retry`). A flaky scenario that fails then passes within the budget is
10
+ * reported as passed-but-flaky. Overridden by `opice test --retries=N` on
11
+ * the command line, and by a per-scenario `walkthrough`/meta `retries`.
12
+ */
13
+ retries?: number
7
14
  }
8
15
 
9
16
  const CONFIG_NAME = 'opice.config.json'