@quenty/nevermore-cli 4.43.3 → 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 (154) hide show
  1. package/CHANGELOG.md +10 -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/commands/init-command/init-game-command.js +2 -2
  15. package/dist/commands/init-command/init-game-command.js.map +1 -1
  16. package/dist/commands/install-package-command.d.ts +14 -0
  17. package/dist/commands/install-package-command.d.ts.map +1 -1
  18. package/dist/commands/install-package-command.js +65 -12
  19. package/dist/commands/install-package-command.js.map +1 -1
  20. package/dist/utils/deploy/deploy-github-columns.d.ts +12 -2
  21. package/dist/utils/deploy/deploy-github-columns.d.ts.map +1 -1
  22. package/dist/utils/deploy/deploy-github-columns.js +11 -4
  23. package/dist/utils/deploy/deploy-github-columns.js.map +1 -1
  24. package/dist/utils/deploy/deploy-metadata.js +1 -1
  25. package/dist/utils/deploy/deploy-metadata.js.map +1 -1
  26. package/dist/utils/job-context/base-job-context.d.ts +2 -2
  27. package/dist/utils/job-context/base-job-context.d.ts.map +1 -1
  28. package/dist/utils/job-context/base-job-context.js +1 -1
  29. package/dist/utils/job-context/base-job-context.js.map +1 -1
  30. package/dist/utils/job-context/batch-script-job-context.d.ts +37 -2
  31. package/dist/utils/job-context/batch-script-job-context.d.ts.map +1 -1
  32. package/dist/utils/job-context/batch-script-job-context.js +59 -22
  33. package/dist/utils/job-context/batch-script-job-context.js.map +1 -1
  34. package/dist/utils/job-context/cloud-job-context.d.ts +2 -2
  35. package/dist/utils/job-context/cloud-job-context.d.ts.map +1 -1
  36. package/dist/utils/job-context/cloud-job-context.js +10 -5
  37. package/dist/utils/job-context/cloud-job-context.js.map +1 -1
  38. package/dist/utils/job-context/cloud-job-context.test.d.ts +7 -0
  39. package/dist/utils/job-context/cloud-job-context.test.d.ts.map +1 -0
  40. package/dist/utils/job-context/cloud-job-context.test.js +91 -0
  41. package/dist/utils/job-context/cloud-job-context.test.js.map +1 -0
  42. package/dist/utils/job-context/job-context.d.ts +70 -2
  43. package/dist/utils/job-context/job-context.d.ts.map +1 -1
  44. package/dist/utils/job-context/local-job-context.d.ts +2 -2
  45. package/dist/utils/job-context/local-job-context.d.ts.map +1 -1
  46. package/dist/utils/job-context/local-job-context.js +4 -2
  47. package/dist/utils/job-context/local-job-context.js.map +1 -1
  48. package/dist/utils/job-context/local-job-context.test.d.ts +7 -0
  49. package/dist/utils/job-context/local-job-context.test.d.ts.map +1 -0
  50. package/dist/utils/job-context/local-job-context.test.js +68 -0
  51. package/dist/utils/job-context/local-job-context.test.js.map +1 -0
  52. package/dist/utils/open-cloud/open-cloud-client.d.ts +50 -7
  53. package/dist/utils/open-cloud/open-cloud-client.d.ts.map +1 -1
  54. package/dist/utils/open-cloud/open-cloud-client.js +49 -13
  55. package/dist/utils/open-cloud/open-cloud-client.js.map +1 -1
  56. package/dist/utils/open-cloud/open-cloud-client.test.js +125 -1
  57. package/dist/utils/open-cloud/open-cloud-client.test.js.map +1 -1
  58. package/dist/utils/open-cloud/open-cloud-logs.characterization.test.d.ts +22 -0
  59. package/dist/utils/open-cloud/open-cloud-logs.characterization.test.d.ts.map +1 -0
  60. package/dist/utils/open-cloud/open-cloud-logs.characterization.test.js +202 -0
  61. package/dist/utils/open-cloud/open-cloud-logs.characterization.test.js.map +1 -0
  62. package/dist/utils/package-manager-utils.d.ts +29 -0
  63. package/dist/utils/package-manager-utils.d.ts.map +1 -0
  64. package/dist/utils/package-manager-utils.js +120 -0
  65. package/dist/utils/package-manager-utils.js.map +1 -0
  66. package/dist/utils/package-manager-utils.test.d.ts +2 -0
  67. package/dist/utils/package-manager-utils.test.d.ts.map +1 -0
  68. package/dist/utils/package-manager-utils.test.js +121 -0
  69. package/dist/utils/package-manager-utils.test.js.map +1 -0
  70. package/dist/utils/testing/batch-run.e2e.test.d.ts +17 -0
  71. package/dist/utils/testing/batch-run.e2e.test.d.ts.map +1 -0
  72. package/dist/utils/testing/batch-run.e2e.test.js +343 -0
  73. package/dist/utils/testing/batch-run.e2e.test.js.map +1 -0
  74. package/dist/utils/testing/batch-test-runner-template.test.d.ts +11 -0
  75. package/dist/utils/testing/batch-test-runner-template.test.d.ts.map +1 -0
  76. package/dist/utils/testing/batch-test-runner-template.test.js +38 -0
  77. package/dist/utils/testing/batch-test-runner-template.test.js.map +1 -0
  78. package/dist/utils/testing/log-fetch-stats.d.ts +40 -0
  79. package/dist/utils/testing/log-fetch-stats.d.ts.map +1 -0
  80. package/dist/utils/testing/log-fetch-stats.js +18 -0
  81. package/dist/utils/testing/log-fetch-stats.js.map +1 -0
  82. package/dist/utils/testing/log-fetch-stats.test.d.ts +2 -0
  83. package/dist/utils/testing/log-fetch-stats.test.d.ts.map +1 -0
  84. package/dist/utils/testing/log-fetch-stats.test.js +41 -0
  85. package/dist/utils/testing/log-fetch-stats.test.js.map +1 -0
  86. package/dist/utils/testing/parsers/batch-log-parser.d.ts +126 -1
  87. package/dist/utils/testing/parsers/batch-log-parser.d.ts.map +1 -1
  88. package/dist/utils/testing/parsers/batch-log-parser.js +440 -103
  89. package/dist/utils/testing/parsers/batch-log-parser.js.map +1 -1
  90. package/dist/utils/testing/parsers/batch-log-parser.test.js +494 -1
  91. package/dist/utils/testing/parsers/batch-log-parser.test.js.map +1 -1
  92. package/dist/utils/testing/parsers/batch-log-renderer.d.ts +79 -0
  93. package/dist/utils/testing/parsers/batch-log-renderer.d.ts.map +1 -0
  94. package/dist/utils/testing/parsers/batch-log-renderer.js +241 -0
  95. package/dist/utils/testing/parsers/batch-log-renderer.js.map +1 -0
  96. package/dist/utils/testing/parsers/batch-log-renderer.test.d.ts +2 -0
  97. package/dist/utils/testing/parsers/batch-log-renderer.test.d.ts.map +1 -0
  98. package/dist/utils/testing/parsers/batch-log-renderer.test.js +202 -0
  99. package/dist/utils/testing/parsers/batch-log-renderer.test.js.map +1 -0
  100. package/dist/utils/testing/runner/combined-project-generator.js +1 -1
  101. package/dist/utils/testing/runner/combined-project-generator.js.map +1 -1
  102. package/dist/utils/testing/runner/test-runner.d.ts +24 -0
  103. package/dist/utils/testing/runner/test-runner.d.ts.map +1 -1
  104. package/dist/utils/testing/runner/test-runner.js +166 -6
  105. package/dist/utils/testing/runner/test-runner.js.map +1 -1
  106. package/dist/utils/testing/runner/test-runner.test.js +228 -2
  107. package/dist/utils/testing/runner/test-runner.test.js.map +1 -1
  108. package/dist/utils/testing/structured-test-results.d.ts +77 -0
  109. package/dist/utils/testing/structured-test-results.d.ts.map +1 -0
  110. package/dist/utils/testing/structured-test-results.js +140 -0
  111. package/dist/utils/testing/structured-test-results.js.map +1 -0
  112. package/dist/utils/testing/structured-test-results.test.d.ts +7 -0
  113. package/dist/utils/testing/structured-test-results.test.d.ts.map +1 -0
  114. package/dist/utils/testing/structured-test-results.test.js +179 -0
  115. package/dist/utils/testing/structured-test-results.test.js.map +1 -0
  116. package/package.json +6 -6
  117. package/src/commands/batch-command/batch-deploy-command.ts +4 -4
  118. package/src/commands/batch-command/batch-test-command.ts +94 -19
  119. package/src/commands/deploy-command/deploy-init-utils.ts +7 -1
  120. package/src/commands/deploy-command/index.ts +1 -1
  121. package/src/commands/init-command/init-game-command.ts +2 -2
  122. package/src/commands/install-package-command.ts +107 -14
  123. package/src/utils/deploy/deploy-github-columns.ts +14 -4
  124. package/src/utils/deploy/deploy-metadata.ts +1 -1
  125. package/src/utils/job-context/base-job-context.ts +3 -2
  126. package/src/utils/job-context/batch-script-job-context.ts +98 -17
  127. package/src/utils/job-context/cloud-job-context.test.ts +112 -0
  128. package/src/utils/job-context/cloud-job-context.ts +12 -6
  129. package/src/utils/job-context/job-context.ts +71 -2
  130. package/src/utils/job-context/local-job-context.test.ts +89 -0
  131. package/src/utils/job-context/local-job-context.ts +7 -3
  132. package/src/utils/open-cloud/open-cloud-client.test.ts +155 -1
  133. package/src/utils/open-cloud/open-cloud-client.ts +94 -18
  134. package/src/utils/open-cloud/open-cloud-logs.characterization.test.ts +277 -0
  135. package/src/utils/package-manager-utils.test.ts +174 -0
  136. package/src/utils/package-manager-utils.ts +148 -0
  137. package/src/utils/testing/batch-run.e2e.test.ts +425 -0
  138. package/src/utils/testing/batch-test-runner-template.test.ts +62 -0
  139. package/src/utils/testing/log-fetch-stats.test.ts +48 -0
  140. package/src/utils/testing/log-fetch-stats.ts +55 -0
  141. package/src/utils/testing/parsers/batch-log-parser.test.ts +660 -1
  142. package/src/utils/testing/parsers/batch-log-parser.ts +721 -116
  143. package/src/utils/testing/parsers/batch-log-renderer.test.ts +330 -0
  144. package/src/utils/testing/parsers/batch-log-renderer.ts +329 -0
  145. package/src/utils/testing/runner/combined-project-generator.ts +1 -1
  146. package/src/utils/testing/runner/test-runner.test.ts +332 -2
  147. package/src/utils/testing/runner/test-runner.ts +231 -9
  148. package/src/utils/testing/structured-test-results.test.ts +267 -0
  149. package/src/utils/testing/structured-test-results.ts +199 -0
  150. package/templates/batch-test-runner.lua +242 -0
  151. package/tsconfig.tsbuildinfo +1 -1
  152. package/templates/batch-test-runner.luau +0 -137
  153. /package/build-scripts/{smoke-test-server.luau → smoke-test-server.lua} +0 -0
  154. /package/build-scripts/{transform-rojo-merge-place.luau → transform-rojo-merge-place.lua} +0 -0
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Detects which package manager owns a project so commands install with the
3
+ * same tool the project was set up with.
4
+ */
5
+ import * as fs from 'fs/promises';
6
+ import * as os from 'os';
7
+ import * as path from 'path';
8
+ export const PACKAGE_MANAGERS = ['pnpm', 'npm', 'yarn', 'bun'];
9
+ export const DEFAULT_PACKAGE_MANAGER = 'pnpm';
10
+ const LOCKFILES = [
11
+ ['pnpm-lock.yaml', 'pnpm'],
12
+ ['pnpm-workspace.yaml', 'pnpm'],
13
+ ['bun.lock', 'bun'],
14
+ ['bun.lockb', 'bun'],
15
+ ['yarn.lock', 'yarn'],
16
+ ['package-lock.json', 'npm'],
17
+ ];
18
+ export function isPackageManager(value) {
19
+ return PACKAGE_MANAGERS.includes(value);
20
+ }
21
+ function parsePackageManagerField(value) {
22
+ if (typeof value !== 'string') {
23
+ return undefined;
24
+ }
25
+ const name = value.split('@')[0]?.trim();
26
+ if (name && isPackageManager(name)) {
27
+ return name;
28
+ }
29
+ return undefined;
30
+ }
31
+ async function detectInDirectoryAsync(directory) {
32
+ try {
33
+ const contents = await fs.readFile(path.join(directory, 'package.json'), 'utf-8');
34
+ const parsed = JSON.parse(contents);
35
+ const declared = parsePackageManagerField(parsed.packageManager);
36
+ if (declared) {
37
+ return declared;
38
+ }
39
+ }
40
+ catch {
41
+ // No readable package.json here, fall through to lockfiles
42
+ }
43
+ for (const [fileName, packageManager] of LOCKFILES) {
44
+ try {
45
+ await fs.access(path.join(directory, fileName));
46
+ return packageManager;
47
+ }
48
+ catch {
49
+ continue;
50
+ }
51
+ }
52
+ return undefined;
53
+ }
54
+ /**
55
+ * Detects the package manager for a project, walking up from the given
56
+ * directory so this works from a subfolder of the project.
57
+ *
58
+ * A `packageManager` field wins over a lockfile in the same directory, and the
59
+ * nearest directory with either wins over anything further up. Falls back to
60
+ * pnpm: Nevermore projects are pnpm projects — the templates pin it and gate it
61
+ * behind `only-allow pnpm` — so pnpm is the right guess for a directory that
62
+ * hasn't declared anything yet.
63
+ */
64
+ export async function detectPackageManagerAsync(startDirectory) {
65
+ let directory = await resolveRealPathAsync(path.resolve(startDirectory));
66
+ // Walking to the filesystem root adopts lockfiles that belong to nobody. A
67
+ // stray package-lock.json in a home directory — npm leaves one behind after a
68
+ // single `npm install` run there — made every project below it detect as npm,
69
+ // and in this monorepo that means installing with the one tool that rejects
70
+ // `workspace:` ranges outright. Nothing above the home directory can be part
71
+ // of the project, so the search stops there.
72
+ const boundary = await resolveRealPathAsync(os.homedir());
73
+ for (;;) {
74
+ if (boundary !== undefined && isSamePath(directory, boundary)) {
75
+ break;
76
+ }
77
+ const detected = await detectInDirectoryAsync(directory);
78
+ if (detected) {
79
+ return detected;
80
+ }
81
+ const parent = path.dirname(directory);
82
+ if (parent === directory) {
83
+ break;
84
+ }
85
+ directory = parent;
86
+ }
87
+ return DEFAULT_PACKAGE_MANAGER;
88
+ }
89
+ /**
90
+ * Resolve symlinks and, on Windows, 8.3 short names — `C:\Users\JAMESO~1` and
91
+ * `C:\Users\James Onnen` are the same directory and must compare equal.
92
+ * Returns the input unchanged when the path does not exist.
93
+ */
94
+ async function resolveRealPathAsync(target) {
95
+ try {
96
+ return await fs.realpath(target);
97
+ }
98
+ catch {
99
+ return target;
100
+ }
101
+ }
102
+ /** Windows paths are case-insensitive; POSIX ones are not. */
103
+ function isSamePath(left, right) {
104
+ if (process.platform === 'win32') {
105
+ return left.toLowerCase() === right.toLowerCase();
106
+ }
107
+ return left === right;
108
+ }
109
+ /**
110
+ * Builds the command that adds dependencies to a project. Only npm spells this
111
+ * `install`; the rest treat a bare `install` as "install the lockfile" and need
112
+ * `add` to record new dependencies.
113
+ */
114
+ export function buildAddPackagesCommand(packageManager, packages) {
115
+ if (packageManager === 'npm') {
116
+ return { command: 'npm', args: ['install', ...packages] };
117
+ }
118
+ return { command: packageManager, args: ['add', ...packages] };
119
+ }
120
+ //# sourceMappingURL=package-manager-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-manager-utils.js","sourceRoot":"","sources":["../../src/utils/package-manager-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=package-manager-utils.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-manager-utils.test.d.ts","sourceRoot":"","sources":["../../src/utils/package-manager-utils.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,121 @@
1
+ import { describe, expect, it, beforeEach, afterEach } from 'vitest';
2
+ import * as fs from 'fs/promises';
3
+ import * as os from 'os';
4
+ import * as path from 'path';
5
+ import { buildAddPackagesCommand, detectPackageManagerAsync, isPackageManager, } from './package-manager-utils.js';
6
+ describe('package-manager-utils', () => {
7
+ let root;
8
+ beforeEach(async () => {
9
+ root = await fs.mkdtemp(path.join(os.tmpdir(), 'nevermore-pm-'));
10
+ });
11
+ afterEach(async () => {
12
+ await fs.rm(root, { recursive: true, force: true });
13
+ });
14
+ async function writeFileAsync(relativePath, contents) {
15
+ const filePath = path.join(root, relativePath);
16
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
17
+ await fs.writeFile(filePath, contents);
18
+ }
19
+ describe('detectPackageManagerAsync', () => {
20
+ it('reads the packageManager field', async () => {
21
+ await writeFileAsync('package.json', JSON.stringify({ packageManager: 'pnpm@10.27.0' }));
22
+ expect(await detectPackageManagerAsync(root)).toBe('pnpm');
23
+ });
24
+ it('prefers the packageManager field over a lockfile', async () => {
25
+ await writeFileAsync('package.json', JSON.stringify({ packageManager: 'yarn@4.0.0' }));
26
+ await writeFileAsync('package-lock.json', '{}');
27
+ expect(await detectPackageManagerAsync(root)).toBe('yarn');
28
+ });
29
+ it('falls back to lockfiles', async () => {
30
+ await writeFileAsync('package.json', JSON.stringify({ name: 'game' }));
31
+ await writeFileAsync('pnpm-lock.yaml', '');
32
+ expect(await detectPackageManagerAsync(root)).toBe('pnpm');
33
+ });
34
+ it('treats a pnpm workspace file as pnpm', async () => {
35
+ await writeFileAsync('pnpm-workspace.yaml', 'packages:\n');
36
+ expect(await detectPackageManagerAsync(root)).toBe('pnpm');
37
+ });
38
+ it('walks up from a subdirectory', async () => {
39
+ await writeFileAsync('package.json', JSON.stringify({ packageManager: 'pnpm@10.27.0' }));
40
+ await fs.mkdir(path.join(root, 'src', 'shared'), { recursive: true });
41
+ expect(await detectPackageManagerAsync(path.join(root, 'src', 'shared'))).toBe('pnpm');
42
+ });
43
+ it('lets the nearest project win', async () => {
44
+ await writeFileAsync('package.json', JSON.stringify({ packageManager: 'pnpm@10.27.0' }));
45
+ await writeFileAsync('nested/package.json', JSON.stringify({ packageManager: 'yarn@4.0.0' }));
46
+ expect(await detectPackageManagerAsync(path.join(root, 'nested'))).toBe('yarn');
47
+ });
48
+ it('ignores an unknown packageManager field', async () => {
49
+ await writeFileAsync('package.json', JSON.stringify({ packageManager: 'cnpm@1.0.0' }));
50
+ await writeFileAsync('yarn.lock', '');
51
+ expect(await detectPackageManagerAsync(root)).toBe('yarn');
52
+ });
53
+ it('survives malformed package.json', async () => {
54
+ await writeFileAsync('package.json', '{ not json');
55
+ await writeFileAsync('pnpm-lock.yaml', '');
56
+ expect(await detectPackageManagerAsync(root)).toBe('pnpm');
57
+ });
58
+ it('defaults to pnpm', async () => {
59
+ expect(await detectPackageManagerAsync(root)).toBe('pnpm');
60
+ });
61
+ it('ignores a lockfile sitting in the home directory', async () => {
62
+ // npm leaves a package-lock.json behind after one `npm install` run in a
63
+ // home directory, and walking to the filesystem root adopted it — every
64
+ // project below it then installed with the one tool that rejects this
65
+ // repo's `workspace:` ranges. This test was the symptom: the temp dir
66
+ // lives under the home directory on Windows, so "defaults to pnpm" here
67
+ // failed on a machine that had one and passed everywhere else.
68
+ const home = await fs.realpath(os.homedir());
69
+ const marker = path.join(home, 'package-lock.json');
70
+ const alreadyThere = await fs
71
+ .access(marker)
72
+ .then(() => true)
73
+ .catch(() => false);
74
+ if (!alreadyThere) {
75
+ await fs.writeFile(marker, '{}');
76
+ }
77
+ try {
78
+ expect(await detectPackageManagerAsync(root)).toBe('pnpm');
79
+ }
80
+ finally {
81
+ if (!alreadyThere) {
82
+ await fs.rm(marker, { force: true });
83
+ }
84
+ }
85
+ });
86
+ it('still honors an npm project', async () => {
87
+ await writeFileAsync('package.json', JSON.stringify({ name: 'game' }));
88
+ await writeFileAsync('package-lock.json', '{}');
89
+ expect(await detectPackageManagerAsync(root)).toBe('npm');
90
+ });
91
+ });
92
+ describe('buildAddPackagesCommand', () => {
93
+ it('uses install for npm', () => {
94
+ expect(buildAddPackagesCommand('npm', ['@quenty/blend'])).toEqual({
95
+ command: 'npm',
96
+ args: ['install', '@quenty/blend'],
97
+ });
98
+ });
99
+ it('uses add for everything else', () => {
100
+ expect(buildAddPackagesCommand('pnpm', ['@quenty/blend'])).toEqual({
101
+ command: 'pnpm',
102
+ args: ['add', '@quenty/blend'],
103
+ });
104
+ expect(buildAddPackagesCommand('yarn', ['@quenty/maid'])).toEqual({
105
+ command: 'yarn',
106
+ args: ['add', '@quenty/maid'],
107
+ });
108
+ expect(buildAddPackagesCommand('bun', ['@quenty/maid'])).toEqual({
109
+ command: 'bun',
110
+ args: ['add', '@quenty/maid'],
111
+ });
112
+ });
113
+ });
114
+ describe('isPackageManager', () => {
115
+ it('accepts known managers and rejects others', () => {
116
+ expect(isPackageManager('pnpm')).toBe(true);
117
+ expect(isPackageManager('deno')).toBe(false);
118
+ });
119
+ });
120
+ });
121
+ //# sourceMappingURL=package-manager-utils.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-manager-utils.test.js","sourceRoot":"","sources":["../../src/utils/package-manager-utils.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * End-to-end test for one aggregated batch run.
3
+ *
4
+ * Every piece of this path has unit tests — the parser, the renderer, the job
5
+ * context — and none of them cover the thing that actually goes wrong, which is
6
+ * the seams between them. What a reader sees is produced by a log travelling
7
+ * through all three, and until the execution returned data rather than printing
8
+ * it, that could not be asserted on without spying on `console.log`.
9
+ *
10
+ * So this drives the whole path from the one end that is not ours: a transport
11
+ * handing back the messages a real Open Cloud task produces, complete with the
12
+ * message types, the multi-line error and the trailing JSON summary. Everything
13
+ * downstream is the real code, and the assertions are on what a person would
14
+ * read and on what each package's result came out as.
15
+ */
16
+ export {};
17
+ //# sourceMappingURL=batch-run.e2e.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch-run.e2e.test.d.ts","sourceRoot":"","sources":["../../../src/utils/testing/batch-run.e2e.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG"}
@@ -0,0 +1,343 @@
1
+ /**
2
+ * End-to-end test for one aggregated batch run.
3
+ *
4
+ * Every piece of this path has unit tests — the parser, the renderer, the job
5
+ * context — and none of them cover the thing that actually goes wrong, which is
6
+ * the seams between them. What a reader sees is produced by a log travelling
7
+ * through all three, and until the execution returned data rather than printing
8
+ * it, that could not be asserted on without spying on `console.log`.
9
+ *
10
+ * So this drives the whole path from the one end that is not ours: a transport
11
+ * handing back the messages a real Open Cloud task produces, complete with the
12
+ * message types, the multi-line error and the trailing JSON summary. Everything
13
+ * downstream is the real code, and the assertions are on what a person would
14
+ * read and on what each package's result came out as.
15
+ */
16
+ import { describe, it, expect, vi } from 'vitest';
17
+ import { OutputHelper } from '@quenty/cli-output-helpers';
18
+ import { BatchScriptJobContext } from '../job-context/batch-script-job-context.js';
19
+ import { renderBatchOutcome } from './parsers/batch-log-renderer.js';
20
+ const { SLUG_MAP } = vi.hoisted(() => ({
21
+ SLUG_MAP: new Map([
22
+ ['@quenty/alpha', 'alpha'],
23
+ ['@quenty/beta', 'beta'],
24
+ ]),
25
+ }));
26
+ // The only mocked collaborator: building the combined place shells out to rojo
27
+ // and lune, which is a different subject from what this test is about. What it
28
+ // produces that matters downstream is the slug map.
29
+ vi.mock('./runner/combined-project-generator.js', () => ({
30
+ generateCombinedProjectAsync: vi.fn(async () => ({
31
+ rbxlPath: '/tmp/batch.rbxl',
32
+ slugMap: SLUG_MAP,
33
+ primaryTarget: { placeId: 1, universeId: 2 },
34
+ buildContext: { cleanupAsync: async () => { } },
35
+ })),
36
+ }));
37
+ /**
38
+ * The summary the Luau runner prints last and also returns.
39
+ *
40
+ * `counts` are present for both packages: the runner reads them off what the
41
+ * test script returned, or off what NevermoreTestRunnerUtils left in its state
42
+ * module when the script returned nothing.
43
+ */
44
+ const SUMMARY_ENTRIES = [
45
+ {
46
+ slug: 'alpha',
47
+ success: true,
48
+ durationMs: 1500,
49
+ counts: {
50
+ passed: 68,
51
+ failed: 0,
52
+ skipped: 0,
53
+ total: 68,
54
+ suitesPassed: 4,
55
+ suitesFailed: 0,
56
+ suitesTotal: 4,
57
+ },
58
+ ranJest: true,
59
+ },
60
+ {
61
+ slug: 'beta',
62
+ success: false,
63
+ durationMs: 900,
64
+ error: 'beta had a failing suite',
65
+ counts: {
66
+ passed: 3,
67
+ failed: 1,
68
+ skipped: 0,
69
+ total: 4,
70
+ suitesPassed: 0,
71
+ suitesFailed: 1,
72
+ suitesTotal: 1,
73
+ },
74
+ ranJest: true,
75
+ },
76
+ ];
77
+ const SUMMARY_JSON = JSON.stringify(SUMMARY_ENTRIES);
78
+ /**
79
+ * What the task printed, in the shape Open Cloud delivers it: typed messages,
80
+ * one of which carries a whole traceback, and none of which are guaranteed to
81
+ * fall inside a package's section.
82
+ */
83
+ const TASK_MESSAGES = [
84
+ { message: '[BatchTest] running 2 packages', messageType: 'OUTPUT' },
85
+ { message: '===BATCH_TEST_BEGIN alpha===', messageType: 'OUTPUT' },
86
+ {
87
+ message: 'PASS ServerScriptService.alpha.Thing.spec',
88
+ messageType: 'OUTPUT',
89
+ },
90
+ { message: '===BATCH_TEST_END alpha PASS 1500===', messageType: 'OUTPUT' },
91
+ {
92
+ message: "TaskScript:12: a leaked task exploded\nStack Begin\nScript 'Foo', Line 3\nStack End",
93
+ messageType: 'ERROR',
94
+ },
95
+ { message: '===BATCH_TEST_BEGIN beta===', messageType: 'OUTPUT' },
96
+ {
97
+ message: '[BatchTest] beta: beta had a failing suite',
98
+ messageType: 'WARNING',
99
+ },
100
+ { message: '===BATCH_TEST_END beta FAIL 900===', messageType: 'OUTPUT' },
101
+ { message: '===BATCH_TEST_SUMMARY===', messageType: 'OUTPUT' },
102
+ { message: SUMMARY_JSON, messageType: 'OUTPUT' },
103
+ ];
104
+ /** A transport that runs nothing and reports the messages it was handed. */
105
+ class FakeTransport {
106
+ _messages;
107
+ _returnValues;
108
+ scriptContent;
109
+ deployCount = 0;
110
+ runCount = 0;
111
+ constructor(_messages, _returnValues) {
112
+ this._messages = _messages;
113
+ this._returnValues = _returnValues;
114
+ }
115
+ async buildPlaceAsync() {
116
+ throw new Error('the batch context builds the combined place itself');
117
+ }
118
+ async deployBuiltPlaceAsync() {
119
+ this.deployCount++;
120
+ return {};
121
+ }
122
+ async runScriptAsync(_deployment, options) {
123
+ this.runCount++;
124
+ this.scriptContent = options.scriptContent;
125
+ return {
126
+ success: true,
127
+ taskState: 'COMPLETE',
128
+ returnValues: this._returnValues,
129
+ };
130
+ }
131
+ async getLogsAsync() {
132
+ const text = this._messages.map((m) => m.message).join('\n');
133
+ return {
134
+ text,
135
+ messages: this._messages,
136
+ stats: {
137
+ requests: 1,
138
+ pages: 1,
139
+ entries: 1,
140
+ messages: this._messages.length,
141
+ chars: text.length,
142
+ },
143
+ };
144
+ }
145
+ async releaseAsync() { }
146
+ async releaseBuiltPlaceAsync() { }
147
+ async disposeAsync() { }
148
+ }
149
+ function createBatch(messages = TASK_MESSAGES, returnValues) {
150
+ const targets = [...SLUG_MAP.keys()].map((name) => ({
151
+ name,
152
+ packageName: name,
153
+ path: `/repo/src/${name.split('/')[1]}`,
154
+ target: { placeId: 1, universeId: 2 },
155
+ places: [],
156
+ }));
157
+ const transport = new FakeTransport(messages, returnValues);
158
+ const batch = new BatchScriptJobContext(transport, targets, {
159
+ repoRoot: '/repo',
160
+ });
161
+ return { batch, transport, targets };
162
+ }
163
+ /** What the per-package loop asks the context for, for one package. */
164
+ async function runPackageAsync(batch, packageName) {
165
+ const deployment = await batch.deployBuiltPlaceAsync({
166
+ builtPlace: { rbxlPath: '/tmp/batch.rbxl', target: {} },
167
+ packageName,
168
+ packagePath: '/repo',
169
+ });
170
+ return batch.runScriptAsync(deployment, {
171
+ scriptContent: '',
172
+ packageName,
173
+ });
174
+ }
175
+ describe('an aggregated batch run, end to end', () => {
176
+ it('renders the whole run: every line, in order, grouped and titled', async () => {
177
+ const { batch } = createBatch();
178
+ const outcome = await batch.getExecutionOutcomeAsync();
179
+ const rendered = renderBatchOutcome(outcome, {
180
+ useGroups: true,
181
+ color: false,
182
+ });
183
+ expect(rendered).toEqual([
184
+ // Before any package began, so it belongs to none of them.
185
+ '[BatchTest] running 2 packages',
186
+ '::group::@quenty/alpha - ✅ Passed (68/68) (1.5s)',
187
+ 'PASS ServerScriptService.alpha.Thing.spec',
188
+ '::endgroup::',
189
+ // Between two packages. This is the output the parser used to discard,
190
+ // and the only trace of a crash that belongs to no section.
191
+ 'TaskScript:12: a leaked task exploded',
192
+ 'Stack Begin',
193
+ "Script 'Foo', Line 3",
194
+ 'Stack End',
195
+ '::group::@quenty/beta - ❌ FAILED (3/4) (900ms)',
196
+ '[BatchTest] beta: beta had a failing suite',
197
+ 'beta had a failing suite',
198
+ '::endgroup::',
199
+ // The summary marker and its payload are framing, not output.
200
+ ]);
201
+ });
202
+ it('colors by the severity the transport reported, jest output untouched', async () => {
203
+ const { batch } = createBatch();
204
+ const outcome = await batch.getExecutionOutcomeAsync();
205
+ const rendered = renderBatchOutcome(outcome, {
206
+ useGroups: false,
207
+ color: true,
208
+ });
209
+ expect(rendered).toContain(OutputHelper.formatError('TaskScript:12: a leaked task exploded'));
210
+ expect(rendered).toContain(OutputHelper.formatWarning('[BatchTest] beta: beta had a failing suite'));
211
+ expect(rendered).toContain('PASS ServerScriptService.alpha.Thing.spec');
212
+ });
213
+ it('gives each package its own verdict, counts and duration', async () => {
214
+ const { batch } = createBatch();
215
+ const alpha = await runPackageAsync(batch, '@quenty/alpha');
216
+ const beta = await runPackageAsync(batch, '@quenty/beta');
217
+ expect(alpha.success).toBe(true);
218
+ expect(alpha.durationMs).toBe(1500);
219
+ expect(alpha.testResults).toMatchObject({
220
+ passed: 68,
221
+ failed: 0,
222
+ total: 68,
223
+ });
224
+ expect(beta.success).toBe(false);
225
+ expect(beta.durationMs).toBe(900);
226
+ expect(beta.errorMessage).toContain('beta had a failing suite');
227
+ expect(beta.testResults).toMatchObject({ passed: 3, failed: 1, total: 4 });
228
+ });
229
+ it('builds, uploads and executes once for the whole batch', async () => {
230
+ const { batch, transport } = createBatch();
231
+ await batch.getExecutionOutcomeAsync();
232
+ await runPackageAsync(batch, '@quenty/alpha');
233
+ await runPackageAsync(batch, '@quenty/beta');
234
+ expect(transport.deployCount).toBe(1);
235
+ expect(transport.runCount).toBe(1);
236
+ // The script the packages ran is the template with this batch's slugs in
237
+ // it — the one substitution the context makes, and nothing runs if it is
238
+ // wrong.
239
+ expect(transport.scriptContent).toContain('["alpha","beta"]');
240
+ expect(transport.scriptContent).not.toContain('{{ PACKAGE_SLUGS_JSON }}');
241
+ });
242
+ it('judges a package whose whole section the log window dropped', async () => {
243
+ // The case this path exists for. beta printed nothing that survived — no
244
+ // BEGIN, no END, no jest report — so before the summary came back as a
245
+ // return value it was failed for having no attributable output, and
246
+ // rendered nothing at all: no group, no verdict, no reason.
247
+ const { batch } = createBatch([
248
+ { message: '===BATCH_TEST_BEGIN alpha===', messageType: 'OUTPUT' },
249
+ {
250
+ message: 'PASS ServerScriptService.alpha.Thing.spec',
251
+ messageType: 'OUTPUT',
252
+ },
253
+ {
254
+ message: '===BATCH_TEST_END alpha PASS 1500===',
255
+ messageType: 'OUTPUT',
256
+ },
257
+ ], [SUMMARY_ENTRIES]);
258
+ const outcome = await batch.getExecutionOutcomeAsync();
259
+ const beta = outcome.results.get('@quenty/beta');
260
+ expect(beta?.testCounts).toEqual({ passed: 3, failed: 1, total: 4 });
261
+ expect(beta?.countsSource).toBe('returned');
262
+ expect(beta?.logsLost).toBe(true);
263
+ // Not failed for the absence of a section, which is what used to happen.
264
+ expect(beta?.error).not.toContain('no output could be attributed');
265
+ const rendered = renderBatchOutcome(outcome, {
266
+ useGroups: true,
267
+ color: false,
268
+ });
269
+ expect(rendered).toContain('::group::@quenty/beta - ❌ FAILED (3/4) - logs lost (900ms)');
270
+ expect(rendered.join('\n')).toContain('survived the run');
271
+ });
272
+ it('marks a pass judged on counts alone as one, rather than an ordinary pass', async () => {
273
+ // Trustworthy counts, but nothing to check for tracebacks against and
274
+ // nothing to read if someone goes looking, so it does not get to look like
275
+ // every other green package in the list.
276
+ const { batch } = createBatch([{ message: 'nothing survived', messageType: 'OUTPUT' }], [
277
+ [
278
+ {
279
+ slug: 'alpha',
280
+ success: true,
281
+ durationMs: 1200,
282
+ counts: {
283
+ passed: 35,
284
+ failed: 0,
285
+ skipped: 0,
286
+ total: 35,
287
+ suitesPassed: 2,
288
+ suitesFailed: 0,
289
+ suitesTotal: 2,
290
+ },
291
+ ranJest: true,
292
+ },
293
+ ],
294
+ ]);
295
+ const outcome = await batch.getExecutionOutcomeAsync();
296
+ expect(outcome.results.get('@quenty/alpha')?.success).toBe(true);
297
+ expect(renderBatchOutcome(outcome, { useGroups: true, color: false })).toContain('::group::@quenty/alpha - ⚠️ Passed (35/35) - logs lost (1.2s)');
298
+ });
299
+ it('prefers the returned summary over the printed one', async () => {
300
+ // Both channels carry the same summary. The returned one is read because it
301
+ // is the copy the engine's log buffer cannot truncate — so when they
302
+ // disagree, which only happens if the printed one arrived damaged, the
303
+ // returned one wins.
304
+ const { batch } = createBatch(TASK_MESSAGES, [
305
+ [
306
+ {
307
+ slug: 'alpha',
308
+ success: true,
309
+ durationMs: 4200,
310
+ counts: {
311
+ passed: 99,
312
+ failed: 0,
313
+ skipped: 0,
314
+ total: 99,
315
+ suitesPassed: 1,
316
+ suitesFailed: 0,
317
+ suitesTotal: 1,
318
+ },
319
+ ranJest: true,
320
+ },
321
+ ],
322
+ ]);
323
+ const alpha = (await batch.getExecutionOutcomeAsync()).results.get('@quenty/alpha');
324
+ expect(alpha?.testCounts?.total).toBe(99);
325
+ expect(alpha?.durationMs).toBe(4200);
326
+ });
327
+ it('reports what reading the log turned up without printing it', async () => {
328
+ // A log window that dropped everything but the summary: the run is still
329
+ // judged, and the shortfall is handed back as a diagnostic for the command
330
+ // to place after the output rather than printed from inside the transport.
331
+ const { batch } = createBatch([
332
+ { message: '===BATCH_TEST_SUMMARY===', messageType: 'OUTPUT' },
333
+ { message: SUMMARY_JSON, messageType: 'OUTPUT' },
334
+ ]);
335
+ const outcome = await batch.getExecutionOutcomeAsync();
336
+ expect(outcome.diagnostics.length).toBeGreaterThan(0);
337
+ expect(outcome.diagnostics.map((d) => d.message).join('\n')).toContain('could not attribute any of it to a package section');
338
+ // Still counted, because the counts came back in the summary rather than
339
+ // being scraped out of the section that went missing.
340
+ expect(outcome.results.get('@quenty/alpha')?.testCounts?.total).toBe(68);
341
+ });
342
+ });
343
+ //# sourceMappingURL=batch-run.e2e.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch-run.e2e.test.js","sourceRoot":"","sources":["../../../src/utils/testing/batch-run.e2e.test.ts"],"names":[],"mappings":"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"}