@quenty/nevermore-cli 4.43.4 → 4.44.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.
Files changed (143) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/build-scripts/{combine-test-places.luau → combine-test-places.lua} +3 -3
  3. package/build-scripts/{transform-inject-deploy-metadata.luau → transform-inject-deploy-metadata.lua} +3 -3
  4. package/dist/commands/batch-command/batch-deploy-command.js +4 -4
  5. package/dist/commands/batch-command/batch-deploy-command.js.map +1 -1
  6. package/dist/commands/batch-command/batch-test-command.d.ts.map +1 -1
  7. package/dist/commands/batch-command/batch-test-command.js +76 -19
  8. package/dist/commands/batch-command/batch-test-command.js.map +1 -1
  9. package/dist/commands/deploy-command/deploy-init-utils.d.ts.map +1 -1
  10. package/dist/commands/deploy-command/deploy-init-utils.js +7 -1
  11. package/dist/commands/deploy-command/deploy-init-utils.js.map +1 -1
  12. package/dist/commands/deploy-command/index.js +1 -1
  13. package/dist/commands/deploy-command/index.js.map +1 -1
  14. package/dist/utils/deploy/deploy-github-columns.d.ts +12 -2
  15. package/dist/utils/deploy/deploy-github-columns.d.ts.map +1 -1
  16. package/dist/utils/deploy/deploy-github-columns.js +11 -4
  17. package/dist/utils/deploy/deploy-github-columns.js.map +1 -1
  18. package/dist/utils/deploy/deploy-metadata.js +1 -1
  19. package/dist/utils/deploy/deploy-metadata.js.map +1 -1
  20. package/dist/utils/job-context/base-job-context.d.ts +2 -2
  21. package/dist/utils/job-context/base-job-context.d.ts.map +1 -1
  22. package/dist/utils/job-context/base-job-context.js +1 -1
  23. package/dist/utils/job-context/base-job-context.js.map +1 -1
  24. package/dist/utils/job-context/batch-script-job-context.d.ts +37 -2
  25. package/dist/utils/job-context/batch-script-job-context.d.ts.map +1 -1
  26. package/dist/utils/job-context/batch-script-job-context.js +59 -22
  27. package/dist/utils/job-context/batch-script-job-context.js.map +1 -1
  28. package/dist/utils/job-context/cloud-job-context.d.ts +2 -2
  29. package/dist/utils/job-context/cloud-job-context.d.ts.map +1 -1
  30. package/dist/utils/job-context/cloud-job-context.js +10 -5
  31. package/dist/utils/job-context/cloud-job-context.js.map +1 -1
  32. package/dist/utils/job-context/cloud-job-context.test.d.ts +7 -0
  33. package/dist/utils/job-context/cloud-job-context.test.d.ts.map +1 -0
  34. package/dist/utils/job-context/cloud-job-context.test.js +91 -0
  35. package/dist/utils/job-context/cloud-job-context.test.js.map +1 -0
  36. package/dist/utils/job-context/job-context.d.ts +70 -2
  37. package/dist/utils/job-context/job-context.d.ts.map +1 -1
  38. package/dist/utils/job-context/local-job-context.d.ts +2 -2
  39. package/dist/utils/job-context/local-job-context.d.ts.map +1 -1
  40. package/dist/utils/job-context/local-job-context.js +4 -2
  41. package/dist/utils/job-context/local-job-context.js.map +1 -1
  42. package/dist/utils/job-context/local-job-context.test.d.ts +7 -0
  43. package/dist/utils/job-context/local-job-context.test.d.ts.map +1 -0
  44. package/dist/utils/job-context/local-job-context.test.js +68 -0
  45. package/dist/utils/job-context/local-job-context.test.js.map +1 -0
  46. package/dist/utils/open-cloud/open-cloud-client.d.ts +50 -7
  47. package/dist/utils/open-cloud/open-cloud-client.d.ts.map +1 -1
  48. package/dist/utils/open-cloud/open-cloud-client.js +49 -13
  49. package/dist/utils/open-cloud/open-cloud-client.js.map +1 -1
  50. package/dist/utils/open-cloud/open-cloud-client.test.js +125 -1
  51. package/dist/utils/open-cloud/open-cloud-client.test.js.map +1 -1
  52. package/dist/utils/open-cloud/open-cloud-logs.characterization.test.d.ts +22 -0
  53. package/dist/utils/open-cloud/open-cloud-logs.characterization.test.d.ts.map +1 -0
  54. package/dist/utils/open-cloud/open-cloud-logs.characterization.test.js +202 -0
  55. package/dist/utils/open-cloud/open-cloud-logs.characterization.test.js.map +1 -0
  56. package/dist/utils/package-manager-utils.d.ts.map +1 -1
  57. package/dist/utils/package-manager-utils.js +32 -1
  58. package/dist/utils/package-manager-utils.js.map +1 -1
  59. package/dist/utils/package-manager-utils.test.js +25 -0
  60. package/dist/utils/package-manager-utils.test.js.map +1 -1
  61. package/dist/utils/testing/batch-run.e2e.test.d.ts +17 -0
  62. package/dist/utils/testing/batch-run.e2e.test.d.ts.map +1 -0
  63. package/dist/utils/testing/batch-run.e2e.test.js +343 -0
  64. package/dist/utils/testing/batch-run.e2e.test.js.map +1 -0
  65. package/dist/utils/testing/batch-test-runner-template.test.d.ts +11 -0
  66. package/dist/utils/testing/batch-test-runner-template.test.d.ts.map +1 -0
  67. package/dist/utils/testing/batch-test-runner-template.test.js +38 -0
  68. package/dist/utils/testing/batch-test-runner-template.test.js.map +1 -0
  69. package/dist/utils/testing/log-fetch-stats.d.ts +40 -0
  70. package/dist/utils/testing/log-fetch-stats.d.ts.map +1 -0
  71. package/dist/utils/testing/log-fetch-stats.js +18 -0
  72. package/dist/utils/testing/log-fetch-stats.js.map +1 -0
  73. package/dist/utils/testing/log-fetch-stats.test.d.ts +2 -0
  74. package/dist/utils/testing/log-fetch-stats.test.d.ts.map +1 -0
  75. package/dist/utils/testing/log-fetch-stats.test.js +41 -0
  76. package/dist/utils/testing/log-fetch-stats.test.js.map +1 -0
  77. package/dist/utils/testing/parsers/batch-log-parser.d.ts +126 -1
  78. package/dist/utils/testing/parsers/batch-log-parser.d.ts.map +1 -1
  79. package/dist/utils/testing/parsers/batch-log-parser.js +440 -103
  80. package/dist/utils/testing/parsers/batch-log-parser.js.map +1 -1
  81. package/dist/utils/testing/parsers/batch-log-parser.test.js +494 -1
  82. package/dist/utils/testing/parsers/batch-log-parser.test.js.map +1 -1
  83. package/dist/utils/testing/parsers/batch-log-renderer.d.ts +79 -0
  84. package/dist/utils/testing/parsers/batch-log-renderer.d.ts.map +1 -0
  85. package/dist/utils/testing/parsers/batch-log-renderer.js +241 -0
  86. package/dist/utils/testing/parsers/batch-log-renderer.js.map +1 -0
  87. package/dist/utils/testing/parsers/batch-log-renderer.test.d.ts +2 -0
  88. package/dist/utils/testing/parsers/batch-log-renderer.test.d.ts.map +1 -0
  89. package/dist/utils/testing/parsers/batch-log-renderer.test.js +202 -0
  90. package/dist/utils/testing/parsers/batch-log-renderer.test.js.map +1 -0
  91. package/dist/utils/testing/runner/combined-project-generator.js +1 -1
  92. package/dist/utils/testing/runner/combined-project-generator.js.map +1 -1
  93. package/dist/utils/testing/runner/test-runner.d.ts +24 -0
  94. package/dist/utils/testing/runner/test-runner.d.ts.map +1 -1
  95. package/dist/utils/testing/runner/test-runner.js +166 -6
  96. package/dist/utils/testing/runner/test-runner.js.map +1 -1
  97. package/dist/utils/testing/runner/test-runner.test.js +228 -2
  98. package/dist/utils/testing/runner/test-runner.test.js.map +1 -1
  99. package/dist/utils/testing/structured-test-results.d.ts +77 -0
  100. package/dist/utils/testing/structured-test-results.d.ts.map +1 -0
  101. package/dist/utils/testing/structured-test-results.js +140 -0
  102. package/dist/utils/testing/structured-test-results.js.map +1 -0
  103. package/dist/utils/testing/structured-test-results.test.d.ts +7 -0
  104. package/dist/utils/testing/structured-test-results.test.d.ts.map +1 -0
  105. package/dist/utils/testing/structured-test-results.test.js +179 -0
  106. package/dist/utils/testing/structured-test-results.test.js.map +1 -0
  107. package/package.json +6 -6
  108. package/src/commands/batch-command/batch-deploy-command.ts +4 -4
  109. package/src/commands/batch-command/batch-test-command.ts +94 -19
  110. package/src/commands/deploy-command/deploy-init-utils.ts +7 -1
  111. package/src/commands/deploy-command/index.ts +1 -1
  112. package/src/utils/deploy/deploy-github-columns.ts +14 -4
  113. package/src/utils/deploy/deploy-metadata.ts +1 -1
  114. package/src/utils/job-context/base-job-context.ts +3 -2
  115. package/src/utils/job-context/batch-script-job-context.ts +98 -17
  116. package/src/utils/job-context/cloud-job-context.test.ts +112 -0
  117. package/src/utils/job-context/cloud-job-context.ts +12 -6
  118. package/src/utils/job-context/job-context.ts +71 -2
  119. package/src/utils/job-context/local-job-context.test.ts +89 -0
  120. package/src/utils/job-context/local-job-context.ts +7 -3
  121. package/src/utils/open-cloud/open-cloud-client.test.ts +155 -1
  122. package/src/utils/open-cloud/open-cloud-client.ts +94 -18
  123. package/src/utils/open-cloud/open-cloud-logs.characterization.test.ts +277 -0
  124. package/src/utils/package-manager-utils.test.ts +27 -0
  125. package/src/utils/package-manager-utils.ts +34 -1
  126. package/src/utils/testing/batch-run.e2e.test.ts +425 -0
  127. package/src/utils/testing/batch-test-runner-template.test.ts +62 -0
  128. package/src/utils/testing/log-fetch-stats.test.ts +48 -0
  129. package/src/utils/testing/log-fetch-stats.ts +55 -0
  130. package/src/utils/testing/parsers/batch-log-parser.test.ts +660 -1
  131. package/src/utils/testing/parsers/batch-log-parser.ts +721 -116
  132. package/src/utils/testing/parsers/batch-log-renderer.test.ts +330 -0
  133. package/src/utils/testing/parsers/batch-log-renderer.ts +329 -0
  134. package/src/utils/testing/runner/combined-project-generator.ts +1 -1
  135. package/src/utils/testing/runner/test-runner.test.ts +332 -2
  136. package/src/utils/testing/runner/test-runner.ts +231 -9
  137. package/src/utils/testing/structured-test-results.test.ts +267 -0
  138. package/src/utils/testing/structured-test-results.ts +199 -0
  139. package/templates/batch-test-runner.lua +242 -0
  140. package/tsconfig.tsbuildinfo +1 -1
  141. package/templates/batch-test-runner.luau +0 -137
  142. /package/build-scripts/{smoke-test-server.luau → smoke-test-server.lua} +0 -0
  143. /package/build-scripts/{transform-rojo-merge-place.luau → transform-rojo-merge-place.lua} +0 -0
@@ -0,0 +1,79 @@
1
+ import { type BatchPackageResult } from './batch-log-parser.js';
2
+ /**
3
+ * One line of a batch run's output, carrying the severity Open Cloud reported
4
+ * for the message it came from.
5
+ *
6
+ * Severity is per *message*, and a message can be several lines — an error
7
+ * arrives with its whole traceback attached — so every line of a message
8
+ * inherits it. That is why this is not derived from the text: guessing at
9
+ * severity from patterns misreads a traceback's continuation lines, while the
10
+ * API already says which of OUTPUT, WARNING and ERROR each message was.
11
+ */
12
+ export interface RenderableLogLine {
13
+ line: string;
14
+ severity: 'output' | 'warning' | 'error';
15
+ }
16
+ export interface BatchLogRenderOptions {
17
+ /** Section slug to the package name a reader recognizes, for group titles. */
18
+ slugToPackage: Map<string, string>;
19
+ /**
20
+ * Per-package verdicts, printed as each section closes so a package's result
21
+ * sits with the output that produced it rather than in a later block.
22
+ *
23
+ * Keyed by package name, as `parseBatchTestLogs` returns it — sections are
24
+ * named by slug, so a lookup here goes through `slugToPackage` first.
25
+ */
26
+ results?: Map<string, BatchPackageResult>;
27
+ /** Emit GitHub `::group::` markers. Off outside CI, where they are noise. */
28
+ useGroups: boolean;
29
+ /** Colorize by severity. Off when NO_COLOR is set. */
30
+ color: boolean;
31
+ }
32
+ /**
33
+ * Split typed messages into the lines the parser tokenizes, keeping severity.
34
+ *
35
+ * The join is the same one `getRawTaskLogsAsync` performs, so the resulting
36
+ * lines are positionally identical to the parser's — which is what lets the
37
+ * token at index i describe the line at index i.
38
+ */
39
+ export declare function toRenderableLines(messages: Array<{
40
+ message: string;
41
+ messageType?: string;
42
+ }>): RenderableLogLine[];
43
+ /**
44
+ * Render a whole batch run's output in arrival order, with each package's
45
+ * section wrapped in a collapsible group.
46
+ *
47
+ * Every line the run produced is emitted, including the ones that belong to no
48
+ * package: output between two sections, or before the first BEGIN, used to be
49
+ * discarded by the parser and so never reached anyone. Those lines are exactly
50
+ * the ones worth seeing when a batch misbehaves — a crash between packages, or
51
+ * a harness message printed before the first test — so they are rendered at the
52
+ * top level, outside any group, rather than dropped.
53
+ *
54
+ * Groups are injected around the parser's own BEGIN/END tokens rather than
55
+ * opened as each package starts. An aggregated batch starts every package at
56
+ * once, before the cloud task exists, so grouping by start time produced one
57
+ * empty group per package and put every line under the last of them.
58
+ */
59
+ export declare function renderBatchLog(lines: RenderableLogLine[], options: BatchLogRenderOptions): string[];
60
+ /**
61
+ * Render everything one batch execution produced, ready to print.
62
+ *
63
+ * The binding between what a run reports and what the renderer is told about it
64
+ * lives here rather than at the call site, so a field the outcome carries and
65
+ * the render forgets — the results that put a verdict in every group title, say
66
+ * — is a mistake one test can catch.
67
+ *
68
+ * Structural rather than typed against `BatchExecutionOutcome`: the job context
69
+ * that defines it already imports this module.
70
+ */
71
+ export declare function renderBatchOutcome(outcome: {
72
+ lines: RenderableLogLine[];
73
+ results: Map<string, BatchPackageResult>;
74
+ slugToPackage: Map<string, string>;
75
+ }, presentation: {
76
+ useGroups: boolean;
77
+ color: boolean;
78
+ }): string[];
79
+ //# sourceMappingURL=batch-log-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch-log-renderer.d.ts","sourceRoot":"","sources":["../../../../src/utils/testing/parsers/batch-log-renderer.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,KAAK,kBAAkB,EAExB,MAAM,uBAAuB,CAAC;AAE/B;;;;;;;;;GASG;AACH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC;CAC1C;AAED,MAAM,WAAW,qBAAqB;IACpC,8EAA8E;IAC9E,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC1C,6EAA6E;IAC7E,SAAS,EAAE,OAAO,CAAC;IACnB,sDAAsD;IACtD,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,KAAK,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GACzD,iBAAiB,EAAE,CAiBrB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,iBAAiB,EAAE,EAC1B,OAAO,EAAE,qBAAqB,GAC7B,MAAM,EAAE,CAoEV;AA6CD;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE;IACP,KAAK,EAAE,iBAAiB,EAAE,CAAC;IAC3B,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IACzC,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC,EACD,YAAY,EAAE;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GACnD,MAAM,EAAE,CAOV"}
@@ -0,0 +1,241 @@
1
+ import { OutputHelper } from '@quenty/cli-output-helpers';
2
+ import { formatDurationMs } from '@quenty/cli-output-helpers/cli-utils';
3
+ import { formatStatusText, resolveResultStatus, statusIcon, } from '@quenty/cli-output-helpers/reporting';
4
+ import { tokenizeBatchLog, } from './batch-log-parser.js';
5
+ /**
6
+ * Split typed messages into the lines the parser tokenizes, keeping severity.
7
+ *
8
+ * The join is the same one `getRawTaskLogsAsync` performs, so the resulting
9
+ * lines are positionally identical to the parser's — which is what lets the
10
+ * token at index i describe the line at index i.
11
+ */
12
+ export function toRenderableLines(messages) {
13
+ const lines = [];
14
+ for (const entry of messages) {
15
+ const severity = entry.messageType === 'ERROR'
16
+ ? 'error'
17
+ : entry.messageType === 'WARNING'
18
+ ? 'warning'
19
+ : 'output';
20
+ for (const line of entry.message.split('\n')) {
21
+ lines.push({ line, severity });
22
+ }
23
+ }
24
+ return lines;
25
+ }
26
+ /**
27
+ * Render a whole batch run's output in arrival order, with each package's
28
+ * section wrapped in a collapsible group.
29
+ *
30
+ * Every line the run produced is emitted, including the ones that belong to no
31
+ * package: output between two sections, or before the first BEGIN, used to be
32
+ * discarded by the parser and so never reached anyone. Those lines are exactly
33
+ * the ones worth seeing when a batch misbehaves — a crash between packages, or
34
+ * a harness message printed before the first test — so they are rendered at the
35
+ * top level, outside any group, rather than dropped.
36
+ *
37
+ * Groups are injected around the parser's own BEGIN/END tokens rather than
38
+ * opened as each package starts. An aggregated batch starts every package at
39
+ * once, before the cloud task exists, so grouping by start time produced one
40
+ * empty group per package and put every line under the last of them.
41
+ */
42
+ export function renderBatchLog(lines, options) {
43
+ const tokens = tokenizeBatchLog(lines.map((entry) => entry.line));
44
+ const out = [];
45
+ /** Slugs that reached the output, so the rest can be listed after it. */
46
+ const rendered = new Set();
47
+ let openSlug;
48
+ /**
49
+ * Where the run of lines belonging to no open section began.
50
+ *
51
+ * A section whose BEGIN the log window dropped only announces itself at its
52
+ * END, by which point its output has already been emitted. Knowing where that
53
+ * run started lets the header be spliced in above it, so the output lands
54
+ * inside its own group rather than the group holding only a verdict.
55
+ */
56
+ let orphanStart = 0;
57
+ const closeGroup = () => {
58
+ if (openSlug === undefined) {
59
+ return;
60
+ }
61
+ if (options.useGroups) {
62
+ out.push('::endgroup::');
63
+ }
64
+ openSlug = undefined;
65
+ orphanStart = out.length;
66
+ };
67
+ for (let i = 0; i < tokens.length; i++) {
68
+ const token = tokens[i];
69
+ if (token.kind === 'begin') {
70
+ // A second BEGIN with a section still open means the first never closed;
71
+ // close it here so the groups stay balanced whatever the log did.
72
+ closeGroup();
73
+ openSlug = token.slug;
74
+ rendered.add(token.slug);
75
+ out.push(...openGroup(token.slug, options));
76
+ continue;
77
+ }
78
+ if (token.kind === 'end') {
79
+ if (openSlug === undefined) {
80
+ // An END whose BEGIN the log window dropped. Its output is already in
81
+ // `out`, so the header goes in above it rather than here — otherwise
82
+ // the group holds nothing but the verdict while the output it belongs
83
+ // to sits loose above it.
84
+ out.splice(orphanStart, 0, ...openGroup(token.slug, options));
85
+ openSlug = token.slug;
86
+ }
87
+ rendered.add(token.slug);
88
+ out.push(...verdictLines(token.slug, options));
89
+ closeGroup();
90
+ continue;
91
+ }
92
+ // The summary marker and its JSON payload are framing for the parser, not
93
+ // output anyone reads.
94
+ if (token.kind === 'summary' || token.kind === 'summaryPayload') {
95
+ continue;
96
+ }
97
+ out.push(colorize(lines[i], options.color));
98
+ }
99
+ closeGroup();
100
+ out.push(...sectionlessGroups(rendered, options));
101
+ return out;
102
+ }
103
+ /**
104
+ * Groups for packages that never appeared in the log at all.
105
+ *
106
+ * A dropped log window takes whole sections with it, markers included, and such
107
+ * a package used to render nothing: no group, no verdict, no reason — only a
108
+ * row in the summary table saying FAILED with nothing behind it. The result is
109
+ * known regardless, because it came back in the run's return value, so it is
110
+ * shown in the same shape every other package is.
111
+ */
112
+ function sectionlessGroups(rendered, options) {
113
+ const out = [];
114
+ for (const [slug, name] of options.slugToPackage) {
115
+ if (rendered.has(slug)) {
116
+ continue;
117
+ }
118
+ const result = options.results?.get(name);
119
+ if (!result) {
120
+ continue;
121
+ }
122
+ out.push(...openGroup(slug, options));
123
+ out.push(...verdictLines(slug, options));
124
+ // The group is otherwise empty, so it says why rather than leaving a reader
125
+ // to work out that a package showing no output is one whose output is gone.
126
+ out.push(options.color ? OutputHelper.formatDim(NO_SECTION_NOTE) : NO_SECTION_NOTE);
127
+ if (options.useGroups) {
128
+ out.push('::endgroup::');
129
+ }
130
+ }
131
+ return out;
132
+ }
133
+ const NO_SECTION_NOTE = "This package printed nothing that survived the run's log window. " +
134
+ 'Its verdict and counts came back in the batch summary instead.';
135
+ /**
136
+ * Render everything one batch execution produced, ready to print.
137
+ *
138
+ * The binding between what a run reports and what the renderer is told about it
139
+ * lives here rather than at the call site, so a field the outcome carries and
140
+ * the render forgets — the results that put a verdict in every group title, say
141
+ * — is a mistake one test can catch.
142
+ *
143
+ * Structural rather than typed against `BatchExecutionOutcome`: the job context
144
+ * that defines it already imports this module.
145
+ */
146
+ export function renderBatchOutcome(outcome, presentation) {
147
+ return renderBatchLog(outcome.lines, {
148
+ slugToPackage: outcome.slugToPackage,
149
+ results: outcome.results,
150
+ useGroups: presentation.useGroups,
151
+ color: presentation.color,
152
+ });
153
+ }
154
+ /**
155
+ * Header for one package's section, carrying its verdict.
156
+ *
157
+ * The status is in the title because a group is read collapsed: a reader
158
+ * scanning 78 of them wants to know which to open, and a title that is only a
159
+ * package name makes them all look alike. The counts and duration are formatted
160
+ * with the same helpers the PR comment table uses, so the two cannot drift into
161
+ * describing the same run differently.
162
+ */
163
+ function openGroup(slug, options) {
164
+ const name = options.slugToPackage.get(slug) ?? slug;
165
+ const result = options.results?.get(name);
166
+ const title = result ? `${name} - ${describeResult(result)}` : name;
167
+ if (options.useGroups) {
168
+ return [`::group::${title}`];
169
+ }
170
+ return [OutputHelper.formatDim(`──────── ${title} ────────`)];
171
+ }
172
+ /**
173
+ * "⚠️ Passed (35/35) - logs lost (1.2s)", the shape every other reporter uses.
174
+ *
175
+ * Resolved by the shared status resolver rather than worked out here, so a
176
+ * group title, a summary-table row and a PR comment row describing the same run
177
+ * cannot disagree about what state it is in or what that state is called. This
178
+ * only picks the icon style and puts the duration on the end.
179
+ */
180
+ function describeResult(result) {
181
+ const status = resolveResultStatus(toStatusInput(result));
182
+ const duration = result.durationMs === undefined
183
+ ? ''
184
+ : `(${formatDurationMs(result.durationMs)})`;
185
+ return [
186
+ statusIcon(status.severity, 'emoji'),
187
+ formatStatusText(status),
188
+ duration,
189
+ ]
190
+ .filter(Boolean)
191
+ .join(' ');
192
+ }
193
+ /**
194
+ * A batch result in the shape the status resolver reads.
195
+ *
196
+ * The parser's result is not a `PackageResult` — it is per-section, and one
197
+ * section is not a package's whole run — so the two fields the resolver needs
198
+ * are handed over rather than the type being widened to fit.
199
+ */
200
+ function toStatusInput(result) {
201
+ return {
202
+ success: result.success,
203
+ progressSummary: result.testCounts
204
+ ? {
205
+ kind: 'test-counts',
206
+ passed: result.testCounts.passed,
207
+ failed: result.testCounts.failed,
208
+ total: result.testCounts.total,
209
+ }
210
+ : undefined,
211
+ caveats: result.logsLost ? ['logs-lost'] : undefined,
212
+ };
213
+ }
214
+ /**
215
+ * Why a package failed, printed where its output ends.
216
+ *
217
+ * Only the reason: the verdict itself is in the group's title now, and saying
218
+ * it twice in six lines of output reads as two separate findings. A reason is
219
+ * a sentence and belongs in the body.
220
+ */
221
+ function verdictLines(slug, options) {
222
+ const name = options.slugToPackage.get(slug);
223
+ const result = name ? options.results?.get(name) : undefined;
224
+ if (!result?.error) {
225
+ return [];
226
+ }
227
+ return [
228
+ options.color ? OutputHelper.formatError(result.error) : result.error,
229
+ ];
230
+ }
231
+ function colorize(entry, color) {
232
+ if (!color || entry.severity === 'output') {
233
+ // Left exactly as it arrived: jest-lua colors its own output, and
234
+ // re-wrapping it would fight those escapes.
235
+ return entry.line;
236
+ }
237
+ return entry.severity === 'error'
238
+ ? OutputHelper.formatError(entry.line)
239
+ : OutputHelper.formatWarning(entry.line);
240
+ }
241
+ //# sourceMappingURL=batch-log-renderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch-log-renderer.js","sourceRoot":"","sources":["../../../../src/utils/testing/parsers/batch-log-renderer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=batch-log-renderer.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch-log-renderer.test.d.ts","sourceRoot":"","sources":["../../../../src/utils/testing/parsers/batch-log-renderer.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,202 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { OutputHelper } from '@quenty/cli-output-helpers';
3
+ import { renderBatchLog, toRenderableLines, } from './batch-log-renderer.js';
4
+ const SLUGS = new Map([
5
+ ['alpha', '@quenty/alpha'],
6
+ ['beta', '@quenty/beta'],
7
+ ]);
8
+ /** Plain OUTPUT lines, which is what most of a run is. */
9
+ function plain(...lines) {
10
+ return lines.map((line) => ({ line, severity: 'output' }));
11
+ }
12
+ function render(lines, results) {
13
+ return renderBatchLog(lines, {
14
+ slugToPackage: SLUGS,
15
+ results,
16
+ useGroups: true,
17
+ color: false,
18
+ });
19
+ }
20
+ function result(over) {
21
+ return {
22
+ slug: 'alpha',
23
+ success: true,
24
+ logs: '',
25
+ tracebackCount: 0,
26
+ ...over,
27
+ };
28
+ }
29
+ describe('renderBatchLog', () => {
30
+ it('wraps each package section in a group of its own', () => {
31
+ const out = render(plain('===BATCH_TEST_BEGIN alpha===', 'alpha ran', '===BATCH_TEST_END alpha PASS 10==='));
32
+ expect(out).toEqual([
33
+ '::group::@quenty/alpha',
34
+ 'alpha ran',
35
+ '::endgroup::',
36
+ ]);
37
+ });
38
+ it('keeps output that belongs to no package, outside any group', () => {
39
+ // The whole point. Output between two sections used to be discarded by the
40
+ // parser, so a crash landing between packages reached nobody.
41
+ const out = render(plain('harness starting up', '===BATCH_TEST_BEGIN alpha===', 'alpha ran', '===BATCH_TEST_END alpha PASS 10===', 'something exploded between packages', '===BATCH_TEST_BEGIN beta===', 'beta ran', '===BATCH_TEST_END beta PASS 20===', 'trailing note after the last package'));
42
+ expect(out).toEqual([
43
+ 'harness starting up',
44
+ '::group::@quenty/alpha',
45
+ 'alpha ran',
46
+ '::endgroup::',
47
+ 'something exploded between packages',
48
+ '::group::@quenty/beta',
49
+ 'beta ran',
50
+ '::endgroup::',
51
+ 'trailing note after the last package',
52
+ ]);
53
+ });
54
+ it('emits one group per package rather than one per start', () => {
55
+ // The bug this replaces: every package was grouped when it started, which
56
+ // in an aggregated batch is all of them at once, before the task existed.
57
+ const out = render(plain('===BATCH_TEST_BEGIN alpha===', '===BATCH_TEST_END alpha PASS 10===', '===BATCH_TEST_BEGIN beta===', '===BATCH_TEST_END beta PASS 20==='));
58
+ expect(out.filter((line) => line === '::endgroup::')).toHaveLength(2);
59
+ expect(out.indexOf('::group::@quenty/beta')).toBeGreaterThan(out.indexOf('::endgroup::'));
60
+ });
61
+ it('closes a section left open by a missing END', () => {
62
+ // Groups must balance whatever the log did, or every later line renders
63
+ // inside a package it has nothing to do with.
64
+ const out = render(plain('===BATCH_TEST_BEGIN alpha===', 'alpha ran', '===BATCH_TEST_BEGIN beta===', 'beta ran', '===BATCH_TEST_END beta PASS 20==='));
65
+ expect(out.filter((line) => line.startsWith('::group::'))).toHaveLength(2);
66
+ expect(out.filter((line) => line === '::endgroup::')).toHaveLength(2);
67
+ });
68
+ it('puts a dropped BEGIN section inside its group, output and all', () => {
69
+ // Truncation eats the head of the window, so the first surviving section
70
+ // announces itself only at its END — after its output has been emitted.
71
+ // Heading it there would leave a group holding nothing but the verdict
72
+ // while hundreds of its lines sat loose above it.
73
+ const out = render(plain('alpha line one', 'alpha line two', '===BATCH_TEST_END alpha PASS 10==='));
74
+ expect(out).toEqual([
75
+ '::group::@quenty/alpha',
76
+ 'alpha line one',
77
+ 'alpha line two',
78
+ '::endgroup::',
79
+ ]);
80
+ });
81
+ it('leaves earlier top-level output above a dropped BEGIN section', () => {
82
+ // Only the run since the last section closed belongs to the orphan; output
83
+ // from before that is not retroactively swept into it.
84
+ const out = render(plain('===BATCH_TEST_BEGIN alpha===', 'alpha ran', '===BATCH_TEST_END alpha PASS 10===', 'loose line between packages', 'beta output with no begin', '===BATCH_TEST_END beta PASS 20==='));
85
+ expect(out).toEqual([
86
+ '::group::@quenty/alpha',
87
+ 'alpha ran',
88
+ '::endgroup::',
89
+ '::group::@quenty/beta',
90
+ 'loose line between packages',
91
+ 'beta output with no begin',
92
+ '::endgroup::',
93
+ ]);
94
+ });
95
+ it('carries the verdict in the group title, and the reason in its body', () => {
96
+ // A group is read collapsed first, so the title has to say which ones are
97
+ // worth opening. The reason is a sentence and stays in the body.
98
+ const results = new Map([
99
+ [
100
+ '@quenty/alpha',
101
+ result({
102
+ success: false,
103
+ error: 'no jest report in output',
104
+ testCounts: { passed: 3, failed: 1, total: 4 },
105
+ durationMs: 1500,
106
+ }),
107
+ ],
108
+ ]);
109
+ const out = render(plain('===BATCH_TEST_BEGIN alpha===', 'alpha ran', '===BATCH_TEST_END alpha FAIL 10==='), results);
110
+ expect(out).toEqual([
111
+ '::group::@quenty/alpha - ❌ FAILED (3/4) (1.5s)',
112
+ 'alpha ran',
113
+ 'no jest report in output',
114
+ '::endgroup::',
115
+ ]);
116
+ });
117
+ it('titles a passing package with its counts and duration', () => {
118
+ const results = new Map([
119
+ [
120
+ '@quenty/alpha',
121
+ result({
122
+ success: true,
123
+ testCounts: { passed: 68, failed: 0, total: 68 },
124
+ durationMs: 1500,
125
+ }),
126
+ ],
127
+ ]);
128
+ const out = render(plain('===BATCH_TEST_BEGIN alpha===', '===BATCH_TEST_END alpha PASS 1==='), results);
129
+ expect(out[0]).toBe('::group::@quenty/alpha - ✅ Passed (68/68) (1.5s)');
130
+ });
131
+ it('titles a package with only its name when nothing is known about it', () => {
132
+ const out = render(plain('===BATCH_TEST_BEGIN alpha===', '===BATCH_TEST_END alpha PASS 1==='));
133
+ expect(out[0]).toBe('::group::@quenty/alpha');
134
+ });
135
+ it('drops the summary marker and its payload', () => {
136
+ // Framing for the parser, not output a person reads.
137
+ const out = render(plain('real output', '===BATCH_TEST_SUMMARY===', '[{"slug":"alpha","success":true}]'));
138
+ expect(out).toEqual(['real output']);
139
+ });
140
+ it('leaves plain output untouched so jest keeps its own color', () => {
141
+ const out = renderBatchLog(plain('✓ passed'), {
142
+ slugToPackage: SLUGS,
143
+ useGroups: true,
144
+ color: true,
145
+ });
146
+ expect(out).toEqual(['✓ passed']);
147
+ });
148
+ it('colors warnings and errors by the severity the API reported', () => {
149
+ const out = renderBatchLog([
150
+ { line: 'plain', severity: 'output' },
151
+ { line: 'careful', severity: 'warning' },
152
+ { line: 'broken', severity: 'error' },
153
+ ], { slugToPackage: SLUGS, useGroups: true, color: true });
154
+ // Compared against the formatters themselves rather than asserting the text
155
+ // changed: chalk emits no escapes on a non-TTY, so "it differs" would pass
156
+ // or fail on where the suite runs rather than on what the renderer did.
157
+ expect(out[0]).toBe('plain');
158
+ expect(out[1]).toBe(OutputHelper.formatWarning('careful'));
159
+ expect(out[2]).toBe(OutputHelper.formatError('broken'));
160
+ });
161
+ it('uses a plain header instead of group markers outside CI', () => {
162
+ const out = renderBatchLog(plain('===BATCH_TEST_BEGIN alpha===', 'ran', '===BATCH_TEST_END alpha PASS 1==='), { slugToPackage: SLUGS, useGroups: false, color: false });
163
+ expect(out.some((line) => line.includes('@quenty/alpha'))).toBe(true);
164
+ expect(out).not.toContain('::group::@quenty/alpha');
165
+ expect(out).not.toContain('::endgroup::');
166
+ });
167
+ });
168
+ describe('toRenderableLines', () => {
169
+ it('gives every line of a message the severity of that message', () => {
170
+ // An error arrives with its traceback attached as one message. Classifying
171
+ // by line would leave the continuation lines looking like ordinary output.
172
+ const lines = toRenderableLines([
173
+ { message: 'fine', messageType: 'OUTPUT' },
174
+ {
175
+ message: "TaskScript:1: boom\nStack Begin\nScript 'X', Line 1\nStack End",
176
+ messageType: 'ERROR',
177
+ },
178
+ ]);
179
+ expect(lines).toHaveLength(5);
180
+ expect(lines[0]).toEqual({ line: 'fine', severity: 'output' });
181
+ expect(lines.slice(1).every((l) => l.severity === 'error')).toBe(true);
182
+ expect(lines[2].line).toBe('Stack Begin');
183
+ });
184
+ it('treats an untyped message as ordinary output', () => {
185
+ // The flat log view carries no type, and a missing type must not read as
186
+ // a failure.
187
+ expect(toRenderableLines([{ message: 'hi' }])).toEqual([
188
+ { line: 'hi', severity: 'output' },
189
+ ]);
190
+ });
191
+ it('produces exactly the lines the parser tokenizes', () => {
192
+ // The renderer maps token i onto line i, which only holds if this split is
193
+ // the same one the fetch's joined text would produce.
194
+ const messages = [
195
+ { message: 'one', messageType: 'OUTPUT' },
196
+ { message: 'two\nthree', messageType: 'WARNING' },
197
+ ];
198
+ const joined = messages.map((m) => m.message).join('\n');
199
+ expect(toRenderableLines(messages).map((l) => l.line)).toEqual(joined.split('\n'));
200
+ });
201
+ });
202
+ //# sourceMappingURL=batch-log-renderer.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch-log-renderer.test.js","sourceRoot":"","sources":["../../../../src/utils/testing/parsers/batch-log-renderer.test.ts"],"names":[],"mappings":"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"}
@@ -61,7 +61,7 @@ export async function generateCombinedProjectAsync(options) {
61
61
  }
62
62
  // ── Phase 2: Merge via Lune ──
63
63
  const combinedRbxlPath = buildContext.resolvePath('batch-test.rbxl');
64
- const luneScriptPath = resolvePackagePath(import.meta.url, 'build-scripts', 'combine-test-places.luau');
64
+ const luneScriptPath = resolvePackagePath(import.meta.url, 'build-scripts', 'combine-test-places.lua');
65
65
  // Build args: <outputPath> <slug1> <rbxl1> <script1> <slug2> <rbxl2> <script2> ...
66
66
  const luneArgs = [combinedRbxlPath];
67
67
  for (const build of builds) {
@@ -1 +1 @@
1
- {"version":3,"file":"combined-project-generator.js","sourceRoot":"","sources":["../../../../src/utils/testing/runner/combined-project-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EACL,YAAY,EACZ,kBAAkB,GACnB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAoC1D;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,4BAA4B,CAAC,OAMlD;IACC,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;IAE1E,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CACb,2DAA2D,CAC5D,CAAC;IACJ,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,YAAY,CAAC,WAAW,CAAC;QAClD,MAAM,EAAE,gBAAgB;KACzB,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC1C,MAAM,WAAW,GAAG,YAAY,CAAC,CAAC,CAAE,CAAC,MAAM,CAAC;IAC5C,MAAM,aAAa,GAAiB,EAAE,GAAG,WAAW,EAAE,CAAC;IACvD,IAAI,YAAY;QAAE,aAAa,CAAC,OAAO,GAAG,YAAY,CAAC;IACvD,IAAI,eAAe;QAAE,aAAa,CAAC,UAAU,GAAG,eAAe,CAAC;IAEhE,MAAM,MAAM,GAAuB,EAAE,CAAC;IAEtC,sDAAsD;IAEtD,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;QACvC,MAAM,EAAE,MAAM,EAAE,GAAG,WAAW,CAAC;QAE/B,iEAAiE;QACjE,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;QACnE,MAAM,IAAI,GAAG,MAAM,iBAAiB,CAAC,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QAEpE,2BAA2B;QAC3B,KAAK,MAAM,CAAC,YAAY,EAAE,YAAY,CAAC,IAAI,OAAO,EAAE,CAAC;YACnD,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;gBAC1B,MAAM,IAAI,KAAK,CACb,mBAAmB,WAAW,CAAC,IAAI,QAAQ,YAAY,mBAAmB,IAAI,GAAG,CAClF,CAAC;YACJ,CAAC;QACH,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAEpC,4BAA4B;QAC5B,MAAM,QAAQ,GAAG,YAAY,CAAC,WAAW,CAAC,GAAG,IAAI,OAAO,CAAC,CAAC;QAC1D,YAAY,CAAC,OAAO,CAAC,YAAY,WAAW,CAAC,IAAI,KAAK,IAAI,MAAM,CAAC,CAAC;QAClE,QAAQ,EAAE,mBAAmB,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAClD,MAAM,YAAY,CAAC,cAAc,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;QACrE,UAAU,EAAE,CAAC;QACb,QAAQ,EAAE,sBAAsB,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QACrD,QAAQ,EAAE,cAAc,EAAE,CAAC;YACzB,IAAI,EAAE,OAAO;YACb,SAAS,EAAE,UAAU;YACrB,KAAK,EAAE,YAAY,CAAC,MAAM;YAC1B,KAAK,EAAE,WAAW,CAAC,IAAI;SACxB,CAAC,CAAC;QAEH,8BAA8B;QAC9B,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CACb,yBAAyB,WAAW,CAAC,IAAI,+BAA+B,CACzE,CAAC;QACJ,CAAC;QACD,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,cAAc,CAAC,CAAC;QAEzE,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,gCAAgC;IAEhC,MAAM,gBAAgB,GAAG,YAAY,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC;IACrE,MAAM,cAAc,GAAG,kBAAkB,CACvC,MAAM,CAAC,IAAI,CAAC,GAAG,EACf,eAAe,EACf,0BAA0B,CAC3B,CAAC;IAEF,mFAAmF;IACnF,MAAM,QAAQ,GAAa,CAAC,gBAAgB,CAAC,CAAC;IAC9C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IAC9D,CAAC;IAED,YAAY,CAAC,OAAO,CAClB,WAAW,MAAM,CAAC,MAAM,iCAAiC,CAC1D,CAAC;IACF,QAAQ,EAAE,cAAc,EAAE,EAAE,CAAC;IAC7B,QAAQ,EAAE,cAAc,EAAE,CAAC;QACzB,IAAI,EAAE,OAAO;QACb,SAAS,EAAE,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC,MAAM;KACrB,CAAC,CAAC;IACH,MAAM,YAAY,CAAC,+BAA+B,CAChD,cAAc,EACd,GAAG,QAAQ,CACZ,CAAC;IAEF,YAAY,CAAC,OAAO,CAClB,YAAY,OAAO,CAAC,IAAI,eAAe,gBAAgB,EAAE,CAC1D,CAAC;IAEF,OAAO;QACL,QAAQ,EAAE,gBAAgB;QAC1B,OAAO;QACP,aAAa;QACb,YAAY;KACb,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,iBAAiB,CAC9B,eAAuB,EACvB,WAAmB;IAEnB,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,gCAAgC,eAAe,KAAK,WAAW,EAAE,CAClE,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAEjC,CAAC;IACF,MAAM,mBAAmB,GAAG,OAAO,CAAC,IAAI,EAAE,mBAAmB,CAAC;IAC9D,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CACb,oBAAoB,eAAe,yCAAyC,CAC7E,CAAC;IACJ,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,EAAE,CAAC;QACnD,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,KAAK,QAAQ,EAAE,CAAC;YAC7C,OAAO,GAAG,CAAC;QACb,CAAC;IACH,CAAC;IAED,MAAM,IAAI,KAAK,CACb,oBAAoB,eAAe,yCAAyC,CAC7E,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"combined-project-generator.js","sourceRoot":"","sources":["../../../../src/utils/testing/runner/combined-project-generator.ts"],"names":[],"mappings":"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"}
@@ -13,6 +13,14 @@ export interface SingleTestResult {
13
13
  durationMs?: number;
14
14
  /** Why the run failed, when the runner can say more than "it failed". */
15
15
  error?: string;
16
+ /**
17
+ * Where `testCounts` came from. `returned` means the run handed them over as a
18
+ * value; `scraped` means they were read out of log text, which is the channel
19
+ * truncation destroys. Absent when there are no counts at all.
20
+ */
21
+ countsSource?: 'returned' | 'scraped';
22
+ /** True when the verdict rests on returned results with no log to read. */
23
+ logsLost?: boolean;
16
24
  }
17
25
  /**
18
26
  * Combine failure reasons from the job context with those read from the logs.
@@ -33,6 +41,12 @@ export interface SingleTestOptions {
33
41
  timeoutMs?: number;
34
42
  /** Luau code to execute directly, bypassing the configured scriptTemplate. */
35
43
  scriptText?: string;
44
+ /**
45
+ * Skip this run's counts-provenance line, because the caller reports it for
46
+ * every package at once. Set by an aggregated batch, where one fetch serves
47
+ * the whole run and the per-package line says the same thing each time.
48
+ */
49
+ suppressCountsProvenance?: boolean;
36
50
  }
37
51
  /**
38
52
  * Build, deploy, and run a test for a single package using the provided
@@ -41,6 +55,16 @@ export interface SingleTestOptions {
41
55
  * Creates and releases its own deployment handle — the caller owns the context lifetime.
42
56
  */
43
57
  export declare function runSingleTestAsync(context: JobContext, options: SingleTestOptions): Promise<SingleTestResult>;
58
+ /**
59
+ * Whether this package ships a jest.config, i.e. whether it has specs to run.
60
+ *
61
+ * Deliberately a bounded walk, not a recursive glob: every package under `src/`
62
+ * has a symlinked, self-referential `node_modules`, so recursive search here
63
+ * hangs. Two levels covers the layouts in use (`src/jest.config.lua` for a
64
+ * package, `src/modules/jest.config.lua` for a game) without needing a list of
65
+ * them.
66
+ */
67
+ export declare function packageHasJestConfigAsync(packagePath: string): Promise<boolean>;
44
68
  /**
45
69
  * Read a test script from the deploy target's configured script path.
46
70
  */
@@ -1 +1 @@
1
- {"version":3,"file":"test-runner.d.ts","sourceRoot":"","sources":["../../../../src/utils/testing/runner/test-runner.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EACL,KAAK,gBAAgB,EAGtB,MAAM,uBAAuB,CAAC;AAS/B,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,UAAU,EAAE,MAAM,EAAE,GACnB,MAAM,EAAE,CAOV;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,UAAU,EACnB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,gBAAgB,CAAC,CA6E3B;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,OAAO,CAAC,MAAM,CAAC,CAajB"}
1
+ {"version":3,"file":"test-runner.d.ts","sourceRoot":"","sources":["../../../../src/utils/testing/runner/test-runner.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EACL,KAAK,gBAAgB,EAGtB,MAAM,uBAAuB,CAAC;AAkB/B,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,YAAY,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IACtC,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,UAAU,EAAE,MAAM,EAAE,GACnB,MAAM,EAAE,CAOV;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,UAAU,EACnB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,gBAAgB,CAAC,CAyJ3B;AA6ED;;;;;;;;GAQG;AACH,wBAAsB,yBAAyB,CAC7C,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,OAAO,CAAC,CAmClB;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GAAG,SAAS,GAC7B,OAAO,CAAC,MAAM,CAAC,CAajB"}