@quenty/nevermore-cli 4.50.1 → 4.51.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/CHANGELOG.md +6 -0
- package/dist/commands/batch-command/batch-bundle-command.d.ts +12 -0
- package/dist/commands/batch-command/batch-bundle-command.d.ts.map +1 -0
- package/dist/commands/batch-command/batch-bundle-command.js +96 -0
- package/dist/commands/batch-command/batch-bundle-command.js.map +1 -0
- package/dist/commands/batch-command/batch-test-command.d.ts +1 -0
- package/dist/commands/batch-command/batch-test-command.d.ts.map +1 -1
- package/dist/commands/batch-command/batch-test-command.js +103 -15
- package/dist/commands/batch-command/batch-test-command.js.map +1 -1
- package/dist/commands/batch-command/index.d.ts.map +1 -1
- package/dist/commands/batch-command/index.js +2 -0
- package/dist/commands/batch-command/index.js.map +1 -1
- package/dist/commands/tools-command/ci-post-test-results.d.ts +1 -0
- package/dist/commands/tools-command/ci-post-test-results.d.ts.map +1 -1
- package/dist/commands/tools-command/ci-post-test-results.js +6 -1
- package/dist/commands/tools-command/ci-post-test-results.js.map +1 -1
- package/dist/utils/job-context/batch-script-job-context.d.ts +12 -0
- package/dist/utils/job-context/batch-script-job-context.d.ts.map +1 -1
- package/dist/utils/job-context/batch-script-job-context.js +19 -0
- package/dist/utils/job-context/batch-script-job-context.js.map +1 -1
- package/dist/utils/sourcemap/sourcemap-loader.d.ts +3 -3
- package/dist/utils/sourcemap/sourcemap-loader.d.ts.map +1 -1
- package/dist/utils/sourcemap/sourcemap-loader.js +6 -7
- package/dist/utils/sourcemap/sourcemap-loader.js.map +1 -1
- package/dist/utils/testing/batch-run.e2e.test.js +36 -0
- package/dist/utils/testing/batch-run.e2e.test.js.map +1 -1
- package/dist/utils/testing/runner/prebuilt-batch-bundle.d.ts +26 -0
- package/dist/utils/testing/runner/prebuilt-batch-bundle.d.ts.map +1 -0
- package/dist/utils/testing/runner/prebuilt-batch-bundle.js +200 -0
- package/dist/utils/testing/runner/prebuilt-batch-bundle.js.map +1 -0
- package/dist/utils/testing/runner/prebuilt-batch-bundle.test.d.ts +2 -0
- package/dist/utils/testing/runner/prebuilt-batch-bundle.test.d.ts.map +1 -0
- package/dist/utils/testing/runner/prebuilt-batch-bundle.test.js +181 -0
- package/dist/utils/testing/runner/prebuilt-batch-bundle.test.js.map +1 -0
- package/dist/utils/testing/runner/test-runner.d.ts +8 -1
- package/dist/utils/testing/runner/test-runner.d.ts.map +1 -1
- package/dist/utils/testing/runner/test-runner.js +19 -6
- package/dist/utils/testing/runner/test-runner.js.map +1 -1
- package/package.json +7 -6
- package/src/commands/batch-command/batch-bundle-command.ts +140 -0
- package/src/commands/batch-command/batch-test-command.ts +156 -16
- package/src/commands/batch-command/index.ts +2 -0
- package/src/commands/tools-command/ci-post-test-results.ts +11 -1
- package/src/utils/job-context/batch-script-job-context.ts +34 -3
- package/src/utils/sourcemap/sourcemap-loader.ts +7 -9
- package/src/utils/testing/batch-run.e2e.test.ts +42 -0
- package/src/utils/testing/runner/prebuilt-batch-bundle.test.ts +252 -0
- package/src/utils/testing/runner/prebuilt-batch-bundle.ts +267 -0
- package/src/utils/testing/runner/test-runner.ts +43 -13
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type DeployTarget } from '@quenty/nevermore-deploy';
|
|
2
|
-
import { type JobContext } from '../../job-context/job-context.js';
|
|
2
|
+
import { type BuiltPlace, type JobContext } from '../../job-context/job-context.js';
|
|
3
3
|
import { type DeployOverrides } from '../../build/build.js';
|
|
4
4
|
import { type ParsedTestCounts } from '../test-log-parser.js';
|
|
5
5
|
export interface SingleTestResult {
|
|
@@ -51,6 +51,11 @@ export interface SingleTestOptions {
|
|
|
51
51
|
*/
|
|
52
52
|
suppressCountsProvenance?: boolean;
|
|
53
53
|
}
|
|
54
|
+
export interface PreparedTest {
|
|
55
|
+
builtPlace: BuiltPlace;
|
|
56
|
+
scriptContent: string;
|
|
57
|
+
hasJestConfig: boolean;
|
|
58
|
+
}
|
|
54
59
|
/**
|
|
55
60
|
* Build, deploy, and run a test for a single package using the provided
|
|
56
61
|
* JobContext. The context determines the execution environment (cloud or local).
|
|
@@ -58,6 +63,8 @@ export interface SingleTestOptions {
|
|
|
58
63
|
* Creates and releases its own deployment handle — the caller owns the context lifetime.
|
|
59
64
|
*/
|
|
60
65
|
export declare function runSingleTestAsync(context: JobContext, options: SingleTestOptions): Promise<SingleTestResult>;
|
|
66
|
+
export declare function prepareTestAsync(context: JobContext, options: SingleTestOptions): Promise<PreparedTest>;
|
|
67
|
+
export declare function executePreparedTestAsync(context: JobContext, prepared: PreparedTest, options: SingleTestOptions): Promise<SingleTestResult>;
|
|
61
68
|
/**
|
|
62
69
|
* Whether this package ships a jest.config, i.e. whether it has specs to run.
|
|
63
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,
|
|
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,EACL,KAAK,UAAU,EACf,KAAK,UAAU,EAChB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,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,kFAAkF;IAClF,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,UAAU,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,UAAU,EACnB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,gBAAgB,CAAC,CAG3B;AAED,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,UAAU,EACnB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,YAAY,CAAC,CAsCvB;AAED,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,UAAU,EACnB,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,gBAAgB,CAAC,CA4H3B;AA4ED;;;;;;;;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"}
|
|
@@ -29,11 +29,11 @@ export function mergeFailureReasons(contextError, logReasons) {
|
|
|
29
29
|
* Creates and releases its own deployment handle — the caller owns the context lifetime.
|
|
30
30
|
*/
|
|
31
31
|
export async function runSingleTestAsync(context, options) {
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
const prepared = await prepareTestAsync(context, options);
|
|
33
|
+
return executePreparedTestAsync(context, prepared, options);
|
|
34
|
+
}
|
|
35
|
+
export async function prepareTestAsync(context, options) {
|
|
36
|
+
const { packagePath, packageName, scriptText, target, overrides } = options;
|
|
37
37
|
const sessionId = randomUUID();
|
|
38
38
|
const builtPlace = await context.buildPlaceAsync({
|
|
39
39
|
target,
|
|
@@ -57,6 +57,19 @@ export async function runSingleTestAsync(context, options) {
|
|
|
57
57
|
}
|
|
58
58
|
const scriptContent = scriptText ??
|
|
59
59
|
(await readTestScriptAsync(packagePath, builtPlace.target.scriptTemplate));
|
|
60
|
+
return {
|
|
61
|
+
builtPlace,
|
|
62
|
+
scriptContent,
|
|
63
|
+
hasJestConfig: await packageHasJestConfigAsync(packagePath),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
export async function executePreparedTestAsync(context, prepared, options) {
|
|
67
|
+
const { packagePath, packageName,
|
|
68
|
+
// 300s is the Open Cloud maximum. The old 120s default failed real suites
|
|
69
|
+
// with no jest summary at all, so "--timeout 300" had become folklore
|
|
70
|
+
// everyone had to know before their first useful run.
|
|
71
|
+
timeoutMs = 300_000, scriptText, } = options;
|
|
72
|
+
const { builtPlace, scriptContent, hasJestConfig } = prepared;
|
|
60
73
|
const deployment = await context.deployBuiltPlaceAsync({
|
|
61
74
|
builtPlace,
|
|
62
75
|
packageName,
|
|
@@ -95,7 +108,7 @@ export async function runSingleTestAsync(context, options) {
|
|
|
95
108
|
const smokeTestedWithSpecs = structured !== undefined &&
|
|
96
109
|
!structured.ranJest &&
|
|
97
110
|
scriptText === undefined &&
|
|
98
|
-
|
|
111
|
+
hasJestConfig;
|
|
99
112
|
const reasons = mergeFailureReasons(result.errorMessage, [
|
|
100
113
|
...(smokeTestedWithSpecs
|
|
101
114
|
? [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-runner.js","sourceRoot":"","sources":["../../../../src/utils/testing/runner/test-runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"test-runner.js","sourceRoot":"","sources":["../../../../src/utils/testing/runner/test-runner.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/nevermore-cli",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.51.0",
|
|
4
4
|
"description": "CLI interface for Nevermore",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -25,15 +25,16 @@
|
|
|
25
25
|
"Quenty"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@quenty/cli-output-helpers": "1.
|
|
29
|
-
"@quenty/nevermore-cli-helpers": "1.
|
|
28
|
+
"@quenty/cli-output-helpers": "1.20.0",
|
|
29
|
+
"@quenty/nevermore-cli-helpers": "1.21.0",
|
|
30
30
|
"@quenty/nevermore-deploy": "1.1.1",
|
|
31
|
-
"@quenty/nevermore-template-helpers": "1.
|
|
32
|
-
"@quenty/studio-bridge": "0.
|
|
31
|
+
"@quenty/nevermore-template-helpers": "1.22.0",
|
|
32
|
+
"@quenty/studio-bridge": "0.23.0",
|
|
33
33
|
"execa": "^9.6.1",
|
|
34
34
|
"find-git-root": "^1.0.4",
|
|
35
35
|
"inquirer": "^13.2.0",
|
|
36
36
|
"node-fetch": "^3.3.2",
|
|
37
|
+
"tar": "^7.5.11",
|
|
37
38
|
"typescript-memoize": "^1.1.1",
|
|
38
39
|
"ws": "^8.18.0",
|
|
39
40
|
"yargs": "^18.0.0"
|
|
@@ -60,5 +61,5 @@
|
|
|
60
61
|
"engines": {
|
|
61
62
|
"node": ">=16"
|
|
62
63
|
},
|
|
63
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "2cc8ce7136d877fc883c13bc5b174693fd7059be"
|
|
64
65
|
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { CommandModule } from 'yargs';
|
|
2
|
+
import { OutputHelper } from '@quenty/cli-output-helpers';
|
|
3
|
+
import { BaseReporter } from '@quenty/cli-output-helpers/reporting';
|
|
4
|
+
import { NevermoreGlobalArgs } from '../../args/global-args.js';
|
|
5
|
+
import {
|
|
6
|
+
BatchScriptJobContext,
|
|
7
|
+
LocalJobContext,
|
|
8
|
+
} from '../../utils/job-context/index.js';
|
|
9
|
+
import {
|
|
10
|
+
discoverAllTestableBatchTargetsAsync,
|
|
11
|
+
discoverChangedTestableBatchTargetsAsync,
|
|
12
|
+
type BatchTarget,
|
|
13
|
+
} from '../../utils/batch/changed-packages-utils.js';
|
|
14
|
+
import { prepareTestAsync } from '../../utils/testing/runner/test-runner.js';
|
|
15
|
+
import {
|
|
16
|
+
BUNDLE_FILE_SUFFIX,
|
|
17
|
+
writePrebuiltBatchBundleAsync,
|
|
18
|
+
} from '../../utils/testing/runner/prebuilt-batch-bundle.js';
|
|
19
|
+
|
|
20
|
+
interface BatchBundleArgs extends NevermoreGlobalArgs {
|
|
21
|
+
file: string;
|
|
22
|
+
base?: string;
|
|
23
|
+
all?: boolean;
|
|
24
|
+
limit?: number;
|
|
25
|
+
maxPlaceMb?: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const batchBundleCommand: CommandModule<
|
|
29
|
+
NevermoreGlobalArgs,
|
|
30
|
+
BatchBundleArgs
|
|
31
|
+
> = {
|
|
32
|
+
command: 'bundle <file>',
|
|
33
|
+
describe:
|
|
34
|
+
'Build the test places for changed packages into one bundle file, without an API key. ' +
|
|
35
|
+
'Run it with "batch test --bundle <file>".',
|
|
36
|
+
builder: (yargs) => {
|
|
37
|
+
return yargs
|
|
38
|
+
.positional('file', {
|
|
39
|
+
describe: `File to write, conventionally <name>${BUNDLE_FILE_SUFFIX}`,
|
|
40
|
+
type: 'string',
|
|
41
|
+
demandOption: true,
|
|
42
|
+
})
|
|
43
|
+
.option('all', {
|
|
44
|
+
describe: 'Bundle all packages with test targets, not just changed',
|
|
45
|
+
type: 'boolean',
|
|
46
|
+
default: false,
|
|
47
|
+
})
|
|
48
|
+
.option('base', {
|
|
49
|
+
describe: 'Git ref to diff against for change detection',
|
|
50
|
+
type: 'string',
|
|
51
|
+
default: 'origin/main',
|
|
52
|
+
})
|
|
53
|
+
.option('limit', {
|
|
54
|
+
describe: 'Max number of packages to bundle (for local debugging)',
|
|
55
|
+
type: 'number',
|
|
56
|
+
})
|
|
57
|
+
.option('max-place-mb', {
|
|
58
|
+
describe:
|
|
59
|
+
'Size budget in MB for one combined place. Larger batches are split into several places. (default: 90, under the Open Cloud upload limit)',
|
|
60
|
+
type: 'number',
|
|
61
|
+
}) as any;
|
|
62
|
+
},
|
|
63
|
+
handler: async (args) => {
|
|
64
|
+
try {
|
|
65
|
+
await _runAsync(args);
|
|
66
|
+
} catch (err) {
|
|
67
|
+
OutputHelper.error(err instanceof Error ? err.message : String(err));
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
async function _runAsync(args: BatchBundleArgs): Promise<void> {
|
|
74
|
+
let packages = args.all
|
|
75
|
+
? await discoverAllTestableBatchTargetsAsync()
|
|
76
|
+
: await discoverChangedTestableBatchTargetsAsync(args.base!);
|
|
77
|
+
if (args.limit && args.limit > 0) {
|
|
78
|
+
packages = packages.slice(0, args.limit);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (args.dryrun) {
|
|
82
|
+
OutputHelper.info(
|
|
83
|
+
`[DRYRUN] Would bundle ${packages.length} packages: ${packages
|
|
84
|
+
.map((p) => p.name)
|
|
85
|
+
.join(', ')}`
|
|
86
|
+
);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
await _writeBundleAsync(args, packages);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function _writeBundleAsync(
|
|
94
|
+
args: BatchBundleArgs,
|
|
95
|
+
packages: BatchTarget[]
|
|
96
|
+
): Promise<void> {
|
|
97
|
+
if (packages.length === 0) {
|
|
98
|
+
OutputHelper.warn('No testable packages found; writing an empty bundle.');
|
|
99
|
+
await writePrebuiltBatchBundleAsync(args.file, [], new Map());
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// No client: building never uploads, so there is no key to need.
|
|
104
|
+
const batchContext = new BatchScriptJobContext(
|
|
105
|
+
new LocalJobContext(new BaseReporter()),
|
|
106
|
+
packages,
|
|
107
|
+
{
|
|
108
|
+
maxChunkBytes:
|
|
109
|
+
args.maxPlaceMb !== undefined
|
|
110
|
+
? args.maxPlaceMb * 1024 * 1024
|
|
111
|
+
: undefined,
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
// Prepared one at a time so every package's deploy-metadata stamp lands in
|
|
117
|
+
// the shared place before it is packed, and the last package's stamp wins.
|
|
118
|
+
// A live aggregated run stamps only after the shared place has uploaded,
|
|
119
|
+
// so its specs never see a stamp at all.
|
|
120
|
+
const hasJestConfig = new Map<string, boolean>();
|
|
121
|
+
for (const pkg of packages) {
|
|
122
|
+
const prepared = await prepareTestAsync(batchContext, {
|
|
123
|
+
packagePath: pkg.path,
|
|
124
|
+
packageName: pkg.name,
|
|
125
|
+
target: pkg.target,
|
|
126
|
+
});
|
|
127
|
+
hasJestConfig.set(pkg.name, prepared.hasJestConfig);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const chunks = await batchContext.getBuiltChunksAsync();
|
|
131
|
+
await writePrebuiltBatchBundleAsync(args.file, chunks, hasJestConfig);
|
|
132
|
+
OutputHelper.info(
|
|
133
|
+
`Wrote ${packages.length} package${packages.length === 1 ? '' : 's'} in ${
|
|
134
|
+
chunks.length
|
|
135
|
+
} place${chunks.length === 1 ? '' : 's'} to ${args.file}.`
|
|
136
|
+
);
|
|
137
|
+
} finally {
|
|
138
|
+
await batchContext.disposeAsync();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -11,6 +11,8 @@ import { getApiKeyAsync } from '@quenty/nevermore-cli-helpers';
|
|
|
11
11
|
import { runBatchAsync } from '../../utils/batch/batch-runner.js';
|
|
12
12
|
import { renderBatchOutcome } from '../../utils/testing/parsers/batch-log-renderer.js';
|
|
13
13
|
import { emitDiagnostic } from '../../utils/testing/parsers/batch-log-parser.js';
|
|
14
|
+
import { type DeployTarget } from '@quenty/nevermore-deploy';
|
|
15
|
+
import { type BuildContext } from '@quenty/nevermore-template-helpers';
|
|
14
16
|
import { createBasePlaceResolver } from '../../utils/build/base-place-resolver-factory.js';
|
|
15
17
|
import {
|
|
16
18
|
type JobContext,
|
|
@@ -37,9 +39,13 @@ import {
|
|
|
37
39
|
createTestCommentConfig,
|
|
38
40
|
} from '../../utils/testing/reporting/index.js';
|
|
39
41
|
import {
|
|
42
|
+
executePreparedTestAsync,
|
|
40
43
|
runSingleTestAsync,
|
|
44
|
+
type SingleTestOptions,
|
|
41
45
|
type SingleTestResult,
|
|
42
46
|
} from '../../utils/testing/runner/test-runner.js';
|
|
47
|
+
import { type CombinedPlaceChunk } from '../../utils/testing/runner/combined-project-generator.js';
|
|
48
|
+
import { readPrebuiltBatchBundleAsync } from '../../utils/testing/runner/prebuilt-batch-bundle.js';
|
|
43
49
|
import { isCI } from '../../utils/nevermore-cli-utils.js';
|
|
44
50
|
|
|
45
51
|
interface BatchTestArgs extends NevermoreGlobalArgs {
|
|
@@ -56,6 +62,7 @@ interface BatchTestArgs extends NevermoreGlobalArgs {
|
|
|
56
62
|
batchUniverseId?: number;
|
|
57
63
|
maxPlaceMb?: number;
|
|
58
64
|
timeout?: number;
|
|
65
|
+
bundle?: string;
|
|
59
66
|
}
|
|
60
67
|
|
|
61
68
|
export const batchTestCommand: CommandModule<
|
|
@@ -129,6 +136,14 @@ export const batchTestCommand: CommandModule<
|
|
|
129
136
|
'Max script execution time in seconds for the whole batch. Sent to the Open Cloud API so Roblox cancels server-side on overrun. Max 300s (API limit). (default: 300)',
|
|
130
137
|
type: 'number',
|
|
131
138
|
})
|
|
139
|
+
.option('bundle', {
|
|
140
|
+
describe:
|
|
141
|
+
'Run the places in a *.nevermore.tests.tar written by "batch bundle" instead of finding ' +
|
|
142
|
+
'and building packages. The bundle never chooses where it is uploaded: ' +
|
|
143
|
+
'that is --batch-place-id/--batch-universe-id, or else the test place this ' +
|
|
144
|
+
'checkout gives one of its packages.',
|
|
145
|
+
type: 'string',
|
|
146
|
+
})
|
|
132
147
|
// Accepted only to fail with a useful message. A batch runs one shared
|
|
133
148
|
// script across packages, so there is nothing for arbitrary Luau to mean
|
|
134
149
|
// here — but yargs strict mode would otherwise reject it with a bare
|
|
@@ -145,6 +160,18 @@ export const batchTestCommand: CommandModule<
|
|
|
145
160
|
' cd <package> && nevermore test --cloud --script-text \'print("hi")\''
|
|
146
161
|
);
|
|
147
162
|
}
|
|
163
|
+
if (args.bundle !== undefined) {
|
|
164
|
+
if (args.all || args.limit !== undefined) {
|
|
165
|
+
throw new Error(
|
|
166
|
+
'--bundle runs every package in the bundle; drop --all and --limit.'
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
if (args.aggregated === false) {
|
|
170
|
+
throw new Error(
|
|
171
|
+
'--bundle runs an aggregated batch; drop --no-aggregated.'
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
148
175
|
return true;
|
|
149
176
|
})
|
|
150
177
|
);
|
|
@@ -160,12 +187,38 @@ export const batchTestCommand: CommandModule<
|
|
|
160
187
|
};
|
|
161
188
|
|
|
162
189
|
async function _runAsync(args: BatchTestArgs): Promise<void> {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
190
|
+
const prebuilt =
|
|
191
|
+
args.bundle !== undefined
|
|
192
|
+
? await _loadPrebuiltRunAsync(args, args.bundle)
|
|
193
|
+
: undefined;
|
|
194
|
+
let exitCode: number | undefined;
|
|
195
|
+
try {
|
|
196
|
+
exitCode = await _runPackagesAsync(args, prebuilt);
|
|
197
|
+
} finally {
|
|
198
|
+
await prebuilt?.buildContext.cleanupAsync();
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Node.js fetch (undici) keeps TCP connections alive in a global pool,
|
|
202
|
+
// which prevents the event loop from draining. Explicit exit required.
|
|
203
|
+
if (exitCode !== undefined) {
|
|
204
|
+
process.exit(exitCode);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
166
207
|
|
|
167
|
-
|
|
168
|
-
|
|
208
|
+
async function _runPackagesAsync(
|
|
209
|
+
args: BatchTestArgs,
|
|
210
|
+
prebuilt: PrebuiltRun | undefined
|
|
211
|
+
): Promise<number | undefined> {
|
|
212
|
+
let packages: BatchTarget[];
|
|
213
|
+
if (prebuilt) {
|
|
214
|
+
packages = prebuilt.packages;
|
|
215
|
+
} else {
|
|
216
|
+
packages = args.all
|
|
217
|
+
? await discoverAllTestableBatchTargetsAsync()
|
|
218
|
+
: await discoverChangedTestableBatchTargetsAsync(args.base!);
|
|
219
|
+
if (args.limit && args.limit > 0) {
|
|
220
|
+
packages = packages.slice(0, args.limit);
|
|
221
|
+
}
|
|
169
222
|
}
|
|
170
223
|
|
|
171
224
|
if (packages.length === 0) {
|
|
@@ -173,7 +226,7 @@ async function _runAsync(args: BatchTestArgs): Promise<void> {
|
|
|
173
226
|
'No testable packages found. Packages need a deploy.nevermore.json with a "test" target.\n' +
|
|
174
227
|
'Run "nevermore deploy init" inside a package to set one up.'
|
|
175
228
|
);
|
|
176
|
-
return;
|
|
229
|
+
return undefined;
|
|
177
230
|
}
|
|
178
231
|
|
|
179
232
|
if (args.dryrun) {
|
|
@@ -181,7 +234,7 @@ async function _runAsync(args: BatchTestArgs): Promise<void> {
|
|
|
181
234
|
OutputHelper.info(
|
|
182
235
|
`[DRYRUN] Would test ${packages.length} packages: ${names}`
|
|
183
236
|
);
|
|
184
|
-
return;
|
|
237
|
+
return undefined;
|
|
185
238
|
}
|
|
186
239
|
|
|
187
240
|
const cloud = args.cloud ?? false;
|
|
@@ -273,8 +326,8 @@ async function _runAsync(args: BatchTestArgs): Promise<void> {
|
|
|
273
326
|
|
|
274
327
|
const batchContext = aggregated
|
|
275
328
|
? new BatchScriptJobContext(innerContext, packages, {
|
|
276
|
-
batchPlaceId: args.batchPlaceId,
|
|
277
|
-
batchUniverseId: args.batchUniverseId,
|
|
329
|
+
batchPlaceId: prebuilt?.target.placeId ?? args.batchPlaceId,
|
|
330
|
+
batchUniverseId: prebuilt?.target.universeId ?? args.batchUniverseId,
|
|
278
331
|
batchTimeoutMs: timeoutMs,
|
|
279
332
|
// Only an upload is size-limited, so a local run stays one place
|
|
280
333
|
// unless asked to split.
|
|
@@ -285,6 +338,10 @@ async function _runAsync(args: BatchTestArgs): Promise<void> {
|
|
|
285
338
|
? undefined
|
|
286
339
|
: Infinity,
|
|
287
340
|
reporter,
|
|
341
|
+
prebuilt: prebuilt && {
|
|
342
|
+
chunks: prebuilt.chunks,
|
|
343
|
+
buildContext: prebuilt.buildContext,
|
|
344
|
+
},
|
|
288
345
|
})
|
|
289
346
|
: undefined;
|
|
290
347
|
const context: JobContext = batchContext ?? innerContext;
|
|
@@ -326,7 +383,8 @@ async function _runAsync(args: BatchTestArgs): Promise<void> {
|
|
|
326
383
|
pkg,
|
|
327
384
|
context,
|
|
328
385
|
timeoutMs,
|
|
329
|
-
aggregated
|
|
386
|
+
aggregated,
|
|
387
|
+
prebuilt?.hasJestConfig.get(pkg.name)
|
|
330
388
|
);
|
|
331
389
|
|
|
332
390
|
return {
|
|
@@ -360,19 +418,17 @@ async function _runAsync(args: BatchTestArgs): Promise<void> {
|
|
|
360
418
|
}
|
|
361
419
|
|
|
362
420
|
await reporter.stopAsync();
|
|
363
|
-
|
|
364
|
-
// Node.js fetch (undici) keeps TCP connections alive in a global pool,
|
|
365
|
-
// which prevents the event loop from draining. Explicit exit required.
|
|
366
|
-
process.exit(exitCode);
|
|
421
|
+
return exitCode;
|
|
367
422
|
}
|
|
368
423
|
|
|
369
424
|
async function _runWithRetryAsync(
|
|
370
425
|
pkg: BatchTarget,
|
|
371
426
|
context: JobContext,
|
|
372
427
|
timeoutMs: number,
|
|
373
|
-
aggregated: boolean
|
|
428
|
+
aggregated: boolean,
|
|
429
|
+
prebuiltHasJestConfig: boolean | undefined
|
|
374
430
|
): Promise<SingleTestResult> {
|
|
375
|
-
const opts = {
|
|
431
|
+
const opts: SingleTestOptions = {
|
|
376
432
|
packagePath: pkg.path,
|
|
377
433
|
packageName: pkg.name,
|
|
378
434
|
timeoutMs,
|
|
@@ -382,11 +438,95 @@ async function _runWithRetryAsync(
|
|
|
382
438
|
suppressCountsProvenance: aggregated,
|
|
383
439
|
};
|
|
384
440
|
|
|
441
|
+
if (prebuiltHasJestConfig !== undefined) {
|
|
442
|
+
return _retryOnTransientAsync(pkg.name, async () =>
|
|
443
|
+
executePreparedTestAsync(
|
|
444
|
+
context,
|
|
445
|
+
{
|
|
446
|
+
builtPlace: await context.buildPlaceAsync(opts),
|
|
447
|
+
scriptContent: '',
|
|
448
|
+
hasJestConfig: prebuiltHasJestConfig,
|
|
449
|
+
},
|
|
450
|
+
opts
|
|
451
|
+
)
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
|
|
385
455
|
return _retryOnTransientAsync(pkg.name, () =>
|
|
386
456
|
runSingleTestAsync(context, opts)
|
|
387
457
|
);
|
|
388
458
|
}
|
|
389
459
|
|
|
460
|
+
interface PrebuiltRun {
|
|
461
|
+
target: DeployTarget;
|
|
462
|
+
packages: BatchTarget[];
|
|
463
|
+
chunks: CombinedPlaceChunk[];
|
|
464
|
+
hasJestConfig: Map<string, boolean>;
|
|
465
|
+
buildContext: BuildContext;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
async function _loadPrebuiltRunAsync(
|
|
469
|
+
args: BatchTestArgs,
|
|
470
|
+
bundleFile: string
|
|
471
|
+
): Promise<PrebuiltRun> {
|
|
472
|
+
const bundle = await readPrebuiltBatchBundleAsync(bundleFile);
|
|
473
|
+
let target: DeployTarget;
|
|
474
|
+
try {
|
|
475
|
+
target = await _resolvePrebuiltTargetAsync(
|
|
476
|
+
args,
|
|
477
|
+
new Set(bundle.packages.map((p) => p.name))
|
|
478
|
+
);
|
|
479
|
+
} catch (err) {
|
|
480
|
+
await bundle.buildContext.cleanupAsync();
|
|
481
|
+
throw err;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
OutputHelper.info(
|
|
485
|
+
`Running ${bundle.packages.length} prebuilt package${
|
|
486
|
+
bundle.packages.length === 1 ? '' : 's'
|
|
487
|
+
} in ${bundle.chunks.length} place${
|
|
488
|
+
bundle.chunks.length === 1 ? '' : 's'
|
|
489
|
+
} on place ${target.placeId}.`
|
|
490
|
+
);
|
|
491
|
+
|
|
492
|
+
return {
|
|
493
|
+
target,
|
|
494
|
+
packages: bundle.packages.map((p) => ({
|
|
495
|
+
name: p.name,
|
|
496
|
+
packageName: p.name,
|
|
497
|
+
path: process.cwd(),
|
|
498
|
+
target,
|
|
499
|
+
})),
|
|
500
|
+
chunks: bundle.chunks,
|
|
501
|
+
hasJestConfig: new Map(
|
|
502
|
+
bundle.packages.map((p) => [p.name, p.hasJestConfig])
|
|
503
|
+
),
|
|
504
|
+
buildContext: bundle.buildContext,
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Where a bundle uploads to, picked the way a normal batch run picks it: the
|
|
510
|
+
* test place of one of its packages, read from this checkout rather than from
|
|
511
|
+
* the bundle.
|
|
512
|
+
*/
|
|
513
|
+
async function _resolvePrebuiltTargetAsync(
|
|
514
|
+
args: BatchTestArgs,
|
|
515
|
+
bundledNames: Set<string>
|
|
516
|
+
): Promise<DeployTarget> {
|
|
517
|
+
const known = await discoverAllTestableBatchTargetsAsync();
|
|
518
|
+
const base = known.find((t) => bundledNames.has(t.name)) ?? known[0];
|
|
519
|
+
const universeId = args.batchUniverseId ?? base?.target.universeId;
|
|
520
|
+
const placeId = args.batchPlaceId ?? base?.target.placeId;
|
|
521
|
+
if (!universeId || !placeId) {
|
|
522
|
+
throw new Error(
|
|
523
|
+
'No test place to upload the bundle to: this checkout has no testable ' +
|
|
524
|
+
'package. Pass --batch-place-id and --batch-universe-id.'
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
return { universeId, placeId, project: '' };
|
|
528
|
+
}
|
|
529
|
+
|
|
390
530
|
/**
|
|
391
531
|
* Run something once more if it failed for a reason that tends not to repeat.
|
|
392
532
|
*
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Argv, CommandModule } from 'yargs';
|
|
2
2
|
import { NevermoreGlobalArgs } from '../../args/global-args.js';
|
|
3
|
+
import { batchBundleCommand } from './batch-bundle-command.js';
|
|
3
4
|
import { batchDeployCommand } from './batch-deploy-command.js';
|
|
4
5
|
import { batchTestCommand } from './batch-test-command.js';
|
|
5
6
|
|
|
@@ -8,6 +9,7 @@ export class BatchCommand<T> implements CommandModule<T, NevermoreGlobalArgs> {
|
|
|
8
9
|
public describe = 'Run operations across multiple packages';
|
|
9
10
|
|
|
10
11
|
public builder = (args: Argv<T>) => {
|
|
12
|
+
args.command(batchBundleCommand as any);
|
|
11
13
|
args.command(batchDeployCommand as any);
|
|
12
14
|
args.command(batchTestCommand as any);
|
|
13
15
|
return args as Argv<NevermoreGlobalArgs>;
|
|
@@ -27,6 +27,7 @@ type ErrorReporter = Reporter & {
|
|
|
27
27
|
interface CiPostTestResultsArgs extends NevermoreGlobalArgs {
|
|
28
28
|
input: string;
|
|
29
29
|
runOutcome?: string;
|
|
30
|
+
sourcemap?: string;
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
/** Create the standard set of GitHub reporters for posting results. */
|
|
@@ -61,6 +62,12 @@ export const ciPostTestResultsCommand: CommandModule<
|
|
|
61
62
|
'When the results file is missing and run-outcome is "success", ' +
|
|
62
63
|
'posts a neutral "no tests" comment instead of an error.',
|
|
63
64
|
type: 'string',
|
|
65
|
+
})
|
|
66
|
+
.option('sourcemap', {
|
|
67
|
+
describe:
|
|
68
|
+
'Sourcemap that test failure annotations resolve files against ' +
|
|
69
|
+
'(default: sourcemap.json in the current directory)',
|
|
70
|
+
type: 'string',
|
|
64
71
|
});
|
|
65
72
|
},
|
|
66
73
|
handler: async (args) => {
|
|
@@ -100,7 +107,10 @@ export const ciPostTestResultsCommand: CommandModule<
|
|
|
100
107
|
}
|
|
101
108
|
|
|
102
109
|
// Emit test failure annotations
|
|
103
|
-
const sourcemapResolver = tryLoadSourcemapResolver(
|
|
110
|
+
const sourcemapResolver = tryLoadSourcemapResolver(
|
|
111
|
+
process.cwd(),
|
|
112
|
+
args.sourcemap
|
|
113
|
+
);
|
|
104
114
|
const workspace = await tryLoadAnnotationWorkspaceAsync(process.cwd());
|
|
105
115
|
const parsedDiagnostics: Diagnostic[] = [];
|
|
106
116
|
for (const failure of state.getFailures()) {
|