@quenty/nevermore-cli 4.50.1 → 4.52.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 +18 -0
- package/dist/commands/batch-command/batch-bundle-command.d.ts +15 -0
- package/dist/commands/batch-command/batch-bundle-command.d.ts.map +1 -0
- package/dist/commands/batch-command/batch-bundle-command.js +168 -0
- package/dist/commands/batch-command/batch-bundle-command.js.map +1 -0
- package/dist/commands/batch-command/batch-deploy-command.d.ts +2 -0
- package/dist/commands/batch-command/batch-deploy-command.d.ts.map +1 -1
- package/dist/commands/batch-command/batch-deploy-command.js +115 -16
- package/dist/commands/batch-command/batch-deploy-command.js.map +1 -1
- 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 +109 -17
- 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/deploy-command/index.d.ts.map +1 -1
- package/dist/commands/deploy-command/index.js +7 -0
- package/dist/commands/deploy-command/index.js.map +1 -1
- package/dist/commands/test-command/test-command.d.ts +1 -0
- package/dist/commands/test-command/test-command.d.ts.map +1 -1
- package/dist/commands/test-command/test-command.js +19 -3
- package/dist/commands/test-command/test-command.js.map +1 -1
- package/dist/commands/tools-command/ci-post-deploy-results.d.ts.map +1 -1
- package/dist/commands/tools-command/ci-post-deploy-results.js +6 -2
- package/dist/commands/tools-command/ci-post-deploy-results.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 +12 -3
- package/dist/commands/tools-command/ci-post-test-results.js.map +1 -1
- package/dist/utils/batch/changed-packages-utils.d.ts +11 -0
- package/dist/utils/batch/changed-packages-utils.d.ts.map +1 -1
- package/dist/utils/batch/changed-packages-utils.js +14 -0
- package/dist/utils/batch/changed-packages-utils.js.map +1 -1
- package/dist/utils/build/build.d.ts +7 -0
- package/dist/utils/build/build.d.ts.map +1 -1
- package/dist/utils/build/build.js.map +1 -1
- package/dist/utils/bundle/untrusted-tar.d.ts +28 -0
- package/dist/utils/bundle/untrusted-tar.d.ts.map +1 -0
- package/dist/utils/bundle/untrusted-tar.js +116 -0
- package/dist/utils/bundle/untrusted-tar.js.map +1 -0
- package/dist/utils/deploy/deploy-github-columns.d.ts +8 -1
- package/dist/utils/deploy/deploy-github-columns.d.ts.map +1 -1
- package/dist/utils/deploy/deploy-github-columns.js.map +1 -1
- package/dist/utils/deploy/deploy-metadata.d.ts +5 -0
- package/dist/utils/deploy/deploy-metadata.d.ts.map +1 -1
- package/dist/utils/deploy/deploy-metadata.js +36 -0
- package/dist/utils/deploy/deploy-metadata.js.map +1 -1
- package/dist/utils/deploy/deploy-metadata.test.js +35 -2
- package/dist/utils/deploy/deploy-metadata.test.js.map +1 -1
- package/dist/utils/deploy/prebuilt-deploy-bundle.d.ts +38 -0
- package/dist/utils/deploy/prebuilt-deploy-bundle.d.ts.map +1 -0
- package/dist/utils/deploy/prebuilt-deploy-bundle.js +209 -0
- package/dist/utils/deploy/prebuilt-deploy-bundle.js.map +1 -0
- package/dist/utils/deploy/prebuilt-deploy-bundle.test.d.ts +2 -0
- package/dist/utils/deploy/prebuilt-deploy-bundle.test.d.ts.map +1 -0
- package/dist/utils/deploy/prebuilt-deploy-bundle.test.js +194 -0
- package/dist/utils/deploy/prebuilt-deploy-bundle.test.js.map +1 -0
- package/dist/utils/job-context/base-job-context.d.ts.map +1 -1
- package/dist/utils/job-context/base-job-context.js +3 -2
- package/dist/utils/job-context/base-job-context.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/open-cloud/open-cloud-client.d.ts +1 -0
- package/dist/utils/open-cloud/open-cloud-client.d.ts.map +1 -1
- package/dist/utils/open-cloud/open-cloud-client.js +5 -0
- package/dist/utils/open-cloud/open-cloud-client.js.map +1 -1
- package/dist/utils/open-cloud/open-cloud-client.test.js +11 -0
- package/dist/utils/open-cloud/open-cloud-client.test.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 +145 -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 +197 -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 +236 -0
- package/src/commands/batch-command/batch-deploy-command.ts +160 -16
- package/src/commands/batch-command/batch-test-command.ts +162 -18
- package/src/commands/batch-command/index.ts +2 -0
- package/src/commands/deploy-command/index.ts +7 -0
- package/src/commands/test-command/test-command.ts +20 -3
- package/src/commands/tools-command/ci-post-deploy-results.ts +9 -2
- package/src/commands/tools-command/ci-post-test-results.ts +20 -3
- package/src/utils/batch/changed-packages-utils.ts +23 -0
- package/src/utils/build/build.ts +7 -0
- package/src/utils/bundle/untrusted-tar.ts +160 -0
- package/src/utils/deploy/deploy-github-columns.ts +8 -1
- package/src/utils/deploy/deploy-metadata.test.ts +50 -1
- package/src/utils/deploy/deploy-metadata.ts +39 -0
- package/src/utils/deploy/prebuilt-deploy-bundle.test.ts +265 -0
- package/src/utils/deploy/prebuilt-deploy-bundle.ts +297 -0
- package/src/utils/job-context/base-job-context.ts +4 -2
- package/src/utils/job-context/batch-script-job-context.ts +34 -3
- package/src/utils/open-cloud/open-cloud-client.test.ts +15 -0
- package/src/utils/open-cloud/open-cloud-client.ts +11 -0
- 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 +272 -0
- package/src/utils/testing/runner/prebuilt-batch-bundle.ts +204 -0
- package/src/utils/testing/runner/test-runner.ts +43 -13
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
import { CommandModule } from 'yargs';
|
|
3
|
+
import { OutputHelper } from '@quenty/cli-output-helpers';
|
|
4
|
+
import { BaseReporter } from '@quenty/cli-output-helpers/reporting';
|
|
5
|
+
import { NevermoreGlobalArgs } from '../../args/global-args.js';
|
|
6
|
+
import {
|
|
7
|
+
BatchScriptJobContext,
|
|
8
|
+
LocalJobContext,
|
|
9
|
+
} from '../../utils/job-context/index.js';
|
|
10
|
+
import {
|
|
11
|
+
discoverAllTestableBatchTargetsAsync,
|
|
12
|
+
discoverChangedTestableBatchTargetsAsync,
|
|
13
|
+
discoverDeployBatchTargetsAsync,
|
|
14
|
+
} from '../../utils/batch/changed-packages-utils.js';
|
|
15
|
+
import { gatherGitDeployInfo } from '../../utils/deploy/deploy-metadata.js';
|
|
16
|
+
import {
|
|
17
|
+
DEPLOY_BUNDLE_FILE_SUFFIX,
|
|
18
|
+
type PrebuiltDeployPlace,
|
|
19
|
+
writePrebuiltDeployBundleAsync,
|
|
20
|
+
} from '../../utils/deploy/prebuilt-deploy-bundle.js';
|
|
21
|
+
import { readPackageVersionAsync } from '../../utils/nevermore-cli-utils.js';
|
|
22
|
+
import { prepareTestAsync } from '../../utils/testing/runner/test-runner.js';
|
|
23
|
+
import {
|
|
24
|
+
BUNDLE_FILE_SUFFIX,
|
|
25
|
+
writePrebuiltBatchBundleAsync,
|
|
26
|
+
} from '../../utils/testing/runner/prebuilt-batch-bundle.js';
|
|
27
|
+
|
|
28
|
+
interface BatchBundleArgs extends NevermoreGlobalArgs {
|
|
29
|
+
file: string;
|
|
30
|
+
test?: boolean;
|
|
31
|
+
deploy?: boolean;
|
|
32
|
+
target?: string;
|
|
33
|
+
base?: string;
|
|
34
|
+
all?: boolean;
|
|
35
|
+
limit?: number;
|
|
36
|
+
maxPlaceMb?: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const batchBundleCommand: CommandModule<
|
|
40
|
+
NevermoreGlobalArgs,
|
|
41
|
+
BatchBundleArgs
|
|
42
|
+
> = {
|
|
43
|
+
command: 'bundle <file>',
|
|
44
|
+
describe:
|
|
45
|
+
'Build what "batch test" or "batch deploy" would run into one bundle file, without an API key. ' +
|
|
46
|
+
'Run it later with "batch test --bundle <file>" or "batch deploy --bundle <file>".',
|
|
47
|
+
builder: (yargs) => {
|
|
48
|
+
return yargs
|
|
49
|
+
.positional('file', {
|
|
50
|
+
describe: `File to write, conventionally <name>${BUNDLE_FILE_SUFFIX} or <name>${DEPLOY_BUNDLE_FILE_SUFFIX}`,
|
|
51
|
+
type: 'string',
|
|
52
|
+
demandOption: true,
|
|
53
|
+
})
|
|
54
|
+
.option('test', {
|
|
55
|
+
describe: 'Bundle the combined test places "batch test" would run',
|
|
56
|
+
type: 'boolean',
|
|
57
|
+
})
|
|
58
|
+
.option('deploy', {
|
|
59
|
+
describe:
|
|
60
|
+
'Bundle the places "batch deploy" would deploy, without their base place, which the deploying run merges',
|
|
61
|
+
type: 'boolean',
|
|
62
|
+
})
|
|
63
|
+
.option('target', {
|
|
64
|
+
describe: 'Deploy target name in deploy.nevermore.json (--deploy only)',
|
|
65
|
+
type: 'string',
|
|
66
|
+
})
|
|
67
|
+
.option('all', {
|
|
68
|
+
describe: 'Bundle every package, not just changed ones',
|
|
69
|
+
type: 'boolean',
|
|
70
|
+
default: false,
|
|
71
|
+
})
|
|
72
|
+
.option('base', {
|
|
73
|
+
describe: 'Git ref to diff against for change detection',
|
|
74
|
+
type: 'string',
|
|
75
|
+
default: 'origin/main',
|
|
76
|
+
})
|
|
77
|
+
.option('limit', {
|
|
78
|
+
describe: 'Max number of packages to bundle (for debugging)',
|
|
79
|
+
type: 'number',
|
|
80
|
+
})
|
|
81
|
+
.option('max-place-mb', {
|
|
82
|
+
describe:
|
|
83
|
+
'Size budget in MB for one combined place (--test only). Larger batches are split into several places. (default: 90, under the Open Cloud upload limit)',
|
|
84
|
+
type: 'number',
|
|
85
|
+
})
|
|
86
|
+
.check((args) => {
|
|
87
|
+
if (args.test === args.deploy || (!args.test && !args.deploy)) {
|
|
88
|
+
throw new Error('Pass exactly one of --test or --deploy.');
|
|
89
|
+
}
|
|
90
|
+
if (args.test && args.target !== undefined) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
'--target picks a deploy target; it applies to --deploy only.'
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
if (args.deploy && args.maxPlaceMb !== undefined) {
|
|
96
|
+
throw new Error(
|
|
97
|
+
'--max-place-mb sizes combined test places; it applies to --test only.'
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
return true;
|
|
101
|
+
}) as any;
|
|
102
|
+
},
|
|
103
|
+
handler: async (args) => {
|
|
104
|
+
try {
|
|
105
|
+
if (args.deploy) {
|
|
106
|
+
await _writeDeployBundleAsync(args);
|
|
107
|
+
} else {
|
|
108
|
+
await _writeTestBundleAsync(args);
|
|
109
|
+
}
|
|
110
|
+
} catch (err) {
|
|
111
|
+
OutputHelper.error(err instanceof Error ? err.message : String(err));
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
async function _writeTestBundleAsync(args: BatchBundleArgs): Promise<void> {
|
|
118
|
+
let packages = args.all
|
|
119
|
+
? await discoverAllTestableBatchTargetsAsync()
|
|
120
|
+
: await discoverChangedTestableBatchTargetsAsync(args.base!);
|
|
121
|
+
if (args.limit && args.limit > 0) {
|
|
122
|
+
packages = packages.slice(0, args.limit);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (args.dryrun) {
|
|
126
|
+
OutputHelper.info(
|
|
127
|
+
`[DRYRUN] Would bundle ${packages.length} packages: ${packages
|
|
128
|
+
.map((p) => p.name)
|
|
129
|
+
.join(', ')}`
|
|
130
|
+
);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (packages.length === 0) {
|
|
135
|
+
OutputHelper.warn('No testable packages found; writing an empty bundle.');
|
|
136
|
+
await writePrebuiltBatchBundleAsync(args.file, [], new Map());
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// No client: building never uploads, so there is no key to need.
|
|
141
|
+
const batchContext = new BatchScriptJobContext(
|
|
142
|
+
new LocalJobContext(new BaseReporter()),
|
|
143
|
+
packages,
|
|
144
|
+
{
|
|
145
|
+
maxChunkBytes:
|
|
146
|
+
args.maxPlaceMb !== undefined
|
|
147
|
+
? args.maxPlaceMb * 1024 * 1024
|
|
148
|
+
: undefined,
|
|
149
|
+
}
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
// Prepared one at a time so every package's deploy-metadata stamp lands in
|
|
154
|
+
// the shared place before it is packed, and the last package's stamp wins.
|
|
155
|
+
// A live aggregated run stamps only after the shared place has uploaded,
|
|
156
|
+
// so its specs never see a stamp at all.
|
|
157
|
+
const hasJestConfig = new Map<string, boolean>();
|
|
158
|
+
for (const pkg of packages) {
|
|
159
|
+
const prepared = await prepareTestAsync(batchContext, {
|
|
160
|
+
packagePath: pkg.path,
|
|
161
|
+
packageName: pkg.name,
|
|
162
|
+
target: pkg.target,
|
|
163
|
+
});
|
|
164
|
+
hasJestConfig.set(pkg.name, prepared.hasJestConfig);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const chunks = await batchContext.getBuiltChunksAsync();
|
|
168
|
+
await writePrebuiltBatchBundleAsync(args.file, chunks, hasJestConfig);
|
|
169
|
+
OutputHelper.info(
|
|
170
|
+
`Wrote ${packages.length} package${packages.length === 1 ? '' : 's'} in ${
|
|
171
|
+
chunks.length
|
|
172
|
+
} place${chunks.length === 1 ? '' : 's'} to ${args.file}.`
|
|
173
|
+
);
|
|
174
|
+
} finally {
|
|
175
|
+
await batchContext.disposeAsync();
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async function _writeDeployBundleAsync(args: BatchBundleArgs): Promise<void> {
|
|
180
|
+
const targetName = args.target ?? 'test';
|
|
181
|
+
const batchTargets = await discoverDeployBatchTargetsAsync({
|
|
182
|
+
targetName,
|
|
183
|
+
all: args.all,
|
|
184
|
+
base: args.base!,
|
|
185
|
+
limit: args.limit,
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
if (args.dryrun) {
|
|
189
|
+
OutputHelper.info(
|
|
190
|
+
`[DRYRUN] Would bundle ${batchTargets.length} places: ${batchTargets
|
|
191
|
+
.map((p) => p.name)
|
|
192
|
+
.join(', ')}`
|
|
193
|
+
);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (batchTargets.length === 0) {
|
|
198
|
+
OutputHelper.warn(
|
|
199
|
+
`No changed packages have a "${targetName}" target; writing an empty bundle.`
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const context = new LocalJobContext(new BaseReporter());
|
|
204
|
+
try {
|
|
205
|
+
const places: PrebuiltDeployPlace[] = [];
|
|
206
|
+
for (const buildTarget of batchTargets) {
|
|
207
|
+
const built = await context.buildPlaceAsync({
|
|
208
|
+
target: buildTarget.target,
|
|
209
|
+
packagePath: buildTarget.path,
|
|
210
|
+
packageName: buildTarget.name,
|
|
211
|
+
outputFileName: 'deploy.rbxl',
|
|
212
|
+
deferBasePlaceMerge: true,
|
|
213
|
+
});
|
|
214
|
+
places.push({
|
|
215
|
+
name: buildTarget.name,
|
|
216
|
+
rbxlPath: built.rbxlPath,
|
|
217
|
+
projectPath: path.resolve(buildTarget.path, buildTarget.target.project),
|
|
218
|
+
packageVersion: await readPackageVersionAsync(buildTarget.path),
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
await writePrebuiltDeployBundleAsync(
|
|
223
|
+
args.file,
|
|
224
|
+
targetName,
|
|
225
|
+
gatherGitDeployInfo(),
|
|
226
|
+
places
|
|
227
|
+
);
|
|
228
|
+
OutputHelper.info(
|
|
229
|
+
`Wrote ${places.length} place${places.length === 1 ? '' : 's'} to ${
|
|
230
|
+
args.file
|
|
231
|
+
}.`
|
|
232
|
+
);
|
|
233
|
+
} finally {
|
|
234
|
+
await context.disposeAsync();
|
|
235
|
+
}
|
|
236
|
+
}
|
|
@@ -24,7 +24,13 @@ import {
|
|
|
24
24
|
buildDeployMetadataAttributes,
|
|
25
25
|
gatherGitDeployInfo,
|
|
26
26
|
injectDeployMetadataAsync,
|
|
27
|
+
type GitDeployInfo,
|
|
27
28
|
} from '../../utils/deploy/deploy-metadata.js';
|
|
29
|
+
import {
|
|
30
|
+
type PrebuiltDeployBundle,
|
|
31
|
+
type PrebuiltDeployPlace,
|
|
32
|
+
readPrebuiltDeployBundleAsync,
|
|
33
|
+
} from '../../utils/deploy/prebuilt-deploy-bundle.js';
|
|
28
34
|
import { OpenCloudClient } from '../../utils/open-cloud/open-cloud-client.js';
|
|
29
35
|
import {
|
|
30
36
|
RateLimiter,
|
|
@@ -38,7 +44,7 @@ import {
|
|
|
38
44
|
import {
|
|
39
45
|
type BatchTarget,
|
|
40
46
|
discoverAllTargetPackagesAsync,
|
|
41
|
-
|
|
47
|
+
discoverDeployBatchTargetsAsync,
|
|
42
48
|
flattenToBatchTargets,
|
|
43
49
|
} from '../../utils/batch/changed-packages-utils.js';
|
|
44
50
|
import {
|
|
@@ -77,6 +83,8 @@ interface BatchDeployArgs extends NevermoreGlobalArgs {
|
|
|
77
83
|
watch?: string;
|
|
78
84
|
watchShareApiKey?: boolean;
|
|
79
85
|
watchUseGhAuth?: boolean;
|
|
86
|
+
bundle?: string;
|
|
87
|
+
bundleCommit?: string;
|
|
80
88
|
}
|
|
81
89
|
|
|
82
90
|
export const batchDeployCommand: CommandModule<
|
|
@@ -157,6 +165,36 @@ export const batchDeployCommand: CommandModule<
|
|
|
157
165
|
'Off by default — the key is stored by the service.',
|
|
158
166
|
type: 'boolean',
|
|
159
167
|
default: false,
|
|
168
|
+
})
|
|
169
|
+
.option('bundle', {
|
|
170
|
+
describe:
|
|
171
|
+
'Deploy the places in a *.nevermore.deploy.tar written by "batch bundle --deploy" instead of ' +
|
|
172
|
+
'finding and building packages. The bundle only names places: where each one deploys, ' +
|
|
173
|
+
"and the base place it merges onto, come from this checkout's deploy.nevermore.json.",
|
|
174
|
+
type: 'string',
|
|
175
|
+
})
|
|
176
|
+
.option('bundle-commit', {
|
|
177
|
+
describe:
|
|
178
|
+
'Fail unless the --bundle was built from this full commit sha, e.g. the PR head GitHub reports',
|
|
179
|
+
type: 'string',
|
|
180
|
+
})
|
|
181
|
+
.check((args) => {
|
|
182
|
+
if (args.bundleCommit !== undefined && args.bundle === undefined) {
|
|
183
|
+
throw new Error('--bundle-commit checks a --bundle; pass one.');
|
|
184
|
+
}
|
|
185
|
+
if (args.bundle !== undefined) {
|
|
186
|
+
if (args.all || args.limit !== undefined) {
|
|
187
|
+
throw new Error(
|
|
188
|
+
'--bundle deploys every place in the bundle; drop --all and --limit.'
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
if (args.watch !== undefined) {
|
|
192
|
+
throw new Error(
|
|
193
|
+
"--bundle deploys another checkout's build, which must not become a watch baseline; drop --watch."
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return true;
|
|
160
198
|
});
|
|
161
199
|
},
|
|
162
200
|
handler: async (args) => {
|
|
@@ -170,18 +208,58 @@ export const batchDeployCommand: CommandModule<
|
|
|
170
208
|
};
|
|
171
209
|
|
|
172
210
|
async function _runAsync(args: BatchDeployArgs): Promise<void> {
|
|
211
|
+
const bundle =
|
|
212
|
+
args.bundle !== undefined
|
|
213
|
+
? await readPrebuiltDeployBundleAsync(args.bundle)
|
|
214
|
+
: undefined;
|
|
215
|
+
let exitCode: number;
|
|
216
|
+
try {
|
|
217
|
+
exitCode = await _runDeployAsync(args, bundle);
|
|
218
|
+
} finally {
|
|
219
|
+
await bundle?.buildContext.cleanupAsync();
|
|
220
|
+
}
|
|
221
|
+
process.exit(exitCode);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
async function _runDeployAsync(
|
|
225
|
+
args: BatchDeployArgs,
|
|
226
|
+
bundle: PrebuiltDeployBundle | undefined
|
|
227
|
+
): Promise<number> {
|
|
173
228
|
const targetName = args.target ?? 'test';
|
|
174
229
|
// Parsed up front so a typo'd duration fails before anything is deployed.
|
|
175
230
|
const watchOption =
|
|
176
231
|
args.watch == null ? undefined : parseWatchOption(args.watch);
|
|
177
232
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
233
|
+
let batchTargets: BatchTarget[];
|
|
234
|
+
let prebuiltByName: Map<string, PrebuiltDeployPlace> | undefined;
|
|
235
|
+
if (
|
|
236
|
+
bundle &&
|
|
237
|
+
args.bundleCommit !== undefined &&
|
|
238
|
+
bundle.git.version !== args.bundleCommit
|
|
239
|
+
) {
|
|
240
|
+
throw new Error(
|
|
241
|
+
`The bundle was built from ${bundle.git.version}, not ${args.bundleCommit}.`
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
if (bundle) {
|
|
245
|
+
({ batchTargets, prebuiltByName } = await _resolveBundleTargetsAsync(
|
|
246
|
+
bundle,
|
|
247
|
+
targetName
|
|
248
|
+
));
|
|
249
|
+
} else {
|
|
250
|
+
batchTargets = await discoverDeployBatchTargetsAsync({
|
|
251
|
+
targetName,
|
|
252
|
+
all: args.all,
|
|
253
|
+
base: args.base!,
|
|
254
|
+
limit: args.limit,
|
|
255
|
+
});
|
|
256
|
+
}
|
|
182
257
|
|
|
183
|
-
if (
|
|
184
|
-
|
|
258
|
+
if (batchTargets.length === 0 && bundle) {
|
|
259
|
+
OutputHelper.warn(
|
|
260
|
+
`The bundle holds no places; nothing changed in a "${targetName}" target.`
|
|
261
|
+
);
|
|
262
|
+
return 0;
|
|
185
263
|
}
|
|
186
264
|
|
|
187
265
|
if (batchTargets.length === 0) {
|
|
@@ -217,7 +295,7 @@ async function _runAsync(args: BatchDeployArgs): Promise<void> {
|
|
|
217
295
|
dryrun: args.dryrun,
|
|
218
296
|
});
|
|
219
297
|
}
|
|
220
|
-
return;
|
|
298
|
+
return 0;
|
|
221
299
|
}
|
|
222
300
|
|
|
223
301
|
if (args.dryrun) {
|
|
@@ -247,7 +325,7 @@ async function _runAsync(args: BatchDeployArgs): Promise<void> {
|
|
|
247
325
|
dryrun: true,
|
|
248
326
|
});
|
|
249
327
|
}
|
|
250
|
-
return;
|
|
328
|
+
return 0;
|
|
251
329
|
}
|
|
252
330
|
|
|
253
331
|
const concurrency = args.concurrency ?? 3;
|
|
@@ -306,7 +384,8 @@ async function _runAsync(args: BatchDeployArgs): Promise<void> {
|
|
|
306
384
|
const context = new CloudJobContext(reporter, client, basePlaceResolver);
|
|
307
385
|
|
|
308
386
|
// Gathered once so every deployed package shares one timestamp and commit.
|
|
309
|
-
|
|
387
|
+
// A bundle's places carry the commit that built them, not this checkout's.
|
|
388
|
+
const deployGitInfo: GitDeployInfo = bundle?.git ?? gatherGitDeployInfo();
|
|
310
389
|
const deployTimestamp = new Date().toISOString();
|
|
311
390
|
|
|
312
391
|
await reporter.startAsync();
|
|
@@ -319,11 +398,18 @@ async function _runAsync(args: BatchDeployArgs): Promise<void> {
|
|
|
319
398
|
reporter,
|
|
320
399
|
bufferOutput: isGrouped,
|
|
321
400
|
executeAsync: async (buildTarget, pkgReporter) => {
|
|
401
|
+
const prebuilt = prebuiltByName?.get(buildTarget.name);
|
|
322
402
|
const builtPlace = await context.buildPlaceAsync({
|
|
323
403
|
target: buildTarget.target,
|
|
324
404
|
outputFileName: publish ? 'publish.rbxl' : 'deploy.rbxl',
|
|
325
405
|
packagePath: buildTarget.path,
|
|
326
406
|
packageName: buildTarget.name,
|
|
407
|
+
overrides: prebuilt
|
|
408
|
+
? {
|
|
409
|
+
placeFile: prebuilt.rbxlPath,
|
|
410
|
+
projectFile: prebuilt.projectPath,
|
|
411
|
+
}
|
|
412
|
+
: undefined,
|
|
327
413
|
});
|
|
328
414
|
|
|
329
415
|
const injected = await injectDeployMetadataAsync(
|
|
@@ -336,7 +422,9 @@ async function _runAsync(args: BatchDeployArgs): Promise<void> {
|
|
|
336
422
|
timestamp: deployTimestamp,
|
|
337
423
|
universeId: buildTarget.target.universeId,
|
|
338
424
|
placeId: buildTarget.target.placeId,
|
|
339
|
-
packageVersion:
|
|
425
|
+
packageVersion: prebuilt
|
|
426
|
+
? prebuilt.packageVersion
|
|
427
|
+
: await readPackageVersionAsync(buildTarget.path),
|
|
340
428
|
basePlaceId: buildTarget.target.basePlace?.placeId,
|
|
341
429
|
basePlaceVersion: builtPlace.basePlaceVersion,
|
|
342
430
|
},
|
|
@@ -360,6 +448,18 @@ async function _runAsync(args: BatchDeployArgs): Promise<void> {
|
|
|
360
448
|
// Eagerly release build artifacts after upload
|
|
361
449
|
await context.releaseBuiltPlaceAsync(builtPlace);
|
|
362
450
|
|
|
451
|
+
const deployed = {
|
|
452
|
+
packageName: buildTarget.name,
|
|
453
|
+
placeId: buildTarget.target.placeId,
|
|
454
|
+
universeId: buildTarget.target.universeId,
|
|
455
|
+
target: targetName,
|
|
456
|
+
version,
|
|
457
|
+
published: publish,
|
|
458
|
+
basePlaceVersion: builtPlace.basePlaceVersion,
|
|
459
|
+
commit: deployGitInfo.version,
|
|
460
|
+
branch: deployGitInfo.branch,
|
|
461
|
+
};
|
|
462
|
+
|
|
363
463
|
let logs: string;
|
|
364
464
|
if (args.smokeTest && buildTarget.target.basePlace) {
|
|
365
465
|
OutputHelper.verbose('Running post-deploy smoke test...');
|
|
@@ -374,8 +474,7 @@ async function _runAsync(args: BatchDeployArgs): Promise<void> {
|
|
|
374
474
|
logs = smokeResult.logs;
|
|
375
475
|
if (!smokeResult.success) {
|
|
376
476
|
return {
|
|
377
|
-
|
|
378
|
-
placeId: buildTarget.target.placeId,
|
|
477
|
+
...deployed,
|
|
379
478
|
success: false,
|
|
380
479
|
logs: _annotateSmokeTestFailure(logs),
|
|
381
480
|
failureLabel: 'SMOKE TEST FAILED',
|
|
@@ -387,8 +486,7 @@ async function _runAsync(args: BatchDeployArgs): Promise<void> {
|
|
|
387
486
|
}
|
|
388
487
|
|
|
389
488
|
return {
|
|
390
|
-
|
|
391
|
-
placeId: buildTarget.target.placeId,
|
|
489
|
+
...deployed,
|
|
392
490
|
success: true,
|
|
393
491
|
logs,
|
|
394
492
|
progressSummary: {
|
|
@@ -425,7 +523,53 @@ async function _runAsync(args: BatchDeployArgs): Promise<void> {
|
|
|
425
523
|
}
|
|
426
524
|
|
|
427
525
|
await reporter.stopAsync();
|
|
428
|
-
|
|
526
|
+
return exitCode;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Match each bundled place to this checkout's target of the same name.
|
|
531
|
+
*
|
|
532
|
+
* The bundle is untrusted, so it only gets to say which places it built. Place
|
|
533
|
+
* ids, universe ids and the base place all come from this checkout, which is
|
|
534
|
+
* what a same-repo PR's run would have used. A place this checkout does not
|
|
535
|
+
* know — a fork adding a new game — has nowhere trusted to go, so it fails
|
|
536
|
+
* rather than deploying to ids the fork chose.
|
|
537
|
+
*/
|
|
538
|
+
async function _resolveBundleTargetsAsync(
|
|
539
|
+
bundle: PrebuiltDeployBundle,
|
|
540
|
+
targetName: string
|
|
541
|
+
): Promise<{
|
|
542
|
+
batchTargets: BatchTarget[];
|
|
543
|
+
prebuiltByName: Map<string, PrebuiltDeployPlace>;
|
|
544
|
+
}> {
|
|
545
|
+
if (bundle.target !== targetName) {
|
|
546
|
+
throw new Error(
|
|
547
|
+
`The bundle was built for the "${bundle.target}" target, not "${targetName}". ` +
|
|
548
|
+
`Pass --target ${bundle.target}.`
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
const known = new Map(
|
|
553
|
+
flattenToBatchTargets(await discoverAllTargetPackagesAsync(targetName)).map(
|
|
554
|
+
(t) => [t.name, t]
|
|
555
|
+
)
|
|
556
|
+
);
|
|
557
|
+
const unknown = bundle.places
|
|
558
|
+
.map((p) => p.name)
|
|
559
|
+
.filter((name) => !known.has(name));
|
|
560
|
+
if (unknown.length > 0) {
|
|
561
|
+
throw new Error(
|
|
562
|
+
`The bundle holds places this checkout has no "${targetName}" target for: ` +
|
|
563
|
+
`${unknown.join(
|
|
564
|
+
', '
|
|
565
|
+
)}. A new place deploys once its deploy.nevermore.json is on this branch.`
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
return {
|
|
570
|
+
batchTargets: bundle.places.map((p) => known.get(p.name)!),
|
|
571
|
+
prebuiltByName: new Map(bundle.places.map((p) => [p.name, p])),
|
|
572
|
+
};
|
|
429
573
|
}
|
|
430
574
|
|
|
431
575
|
/**
|