@dbx-tools/projen 0.9.19 → 0.9.21
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/._LICENSE +0 -0
- package/._README.md +0 -0
- package/._index.ts +0 -0
- package/._package.json +0 -0
- package/README.md +67 -83
- package/index.ts +2 -7
- package/package.json +9 -5
- package/src/.__lazy-require.ts +0 -0
- package/src/.__release-platform.ts +0 -0
- package/src/.__rust-project.ts +0 -0
- package/src/.__rust-release-workflow.ts +0 -0
- package/src/.__task-command.ts +0 -0
- package/src/._barrels.ts +0 -0
- package/src/._bun-app.ts +0 -0
- package/src/._bun-workflow.ts +0 -0
- package/src/._clean.ts +0 -0
- package/src/._codegen.ts +0 -0
- package/src/._dbx-tools-config.ts +0 -0
- package/src/._engine-root.ts +0 -0
- package/src/._generated.ts +0 -0
- package/src/._mixin.ts +0 -0
- package/src/._module-exports.ts +0 -0
- package/src/._openapi.ts +0 -0
- package/src/._packages.ts +0 -0
- package/src/._pnpm-workspace.ts +0 -0
- package/src/._project-js.ts +0 -0
- package/src/._project-predicate.ts +0 -0
- package/src/._project-py.ts +0 -0
- package/src/._project-rs.ts +0 -0
- package/src/._project.ts +0 -0
- package/src/._projen-version.ts +0 -0
- package/src/._publish.ts +0 -0
- package/src/._release-catalog.ts +0 -0
- package/src/._release-dispatch.ts +0 -0
- package/src/._release-github.ts +0 -0
- package/src/._release.ts +0 -0
- package/src/._scaffold.ts +0 -0
- package/src/._tags.ts +0 -0
- package/src/._tsconfig.ts +0 -0
- package/src/._uniffi.ts +0 -0
- package/src/._vscode.ts +0 -0
- package/src/._watch.ts +0 -0
- package/src/._workspace-lock.ts +0 -0
- package/src/._workspace-version.ts +0 -0
- package/src/_rust-release-workflow.ts +4 -391
- package/src/_task-command.ts +75 -0
- package/src/project-js.ts +2 -42
- package/src/project-py.ts +5 -96
- package/src/project-rs.ts +3 -76
- package/src/release-catalog.ts +37 -203
- package/src/release.ts +12 -634
- package/src/scaffold.ts +2 -6
- package/src/workspace-version.ts +9 -121
- package/tasks/._barrels.ts +0 -0
- package/tasks/._bump.ts +0 -0
- package/tasks/._clean.ts +0 -0
- package/tasks/._compile-workspace.ts +0 -0
- package/tasks/._local-publish.ts +0 -0
- package/tasks/._openapi.ts +0 -0
- package/tasks/._projenrc.ts +0 -0
- package/tasks/._publish-npm.ts +0 -0
- package/tasks/._publish-python.ts +0 -0
- package/tasks/._publish-uniffi-local.ts +0 -0
- package/tasks/._publish.ts +0 -0
- package/tasks/._python-registry.ts +0 -0
- package/tasks/._release-assets.ts +0 -0
- package/tasks/._release-candidate.ts +0 -0
- package/tasks/._release-manifest.ts +0 -0
- package/tasks/._release-pr.ts +0 -0
- package/tasks/._release-summary.ts +0 -0
- package/tasks/._release-version.ts +0 -0
- package/tasks/._rust.ts +0 -0
- package/tasks/._sync.ts +0 -0
- package/tasks/._uniffi-python.d.ts +0 -0
- package/tasks/._uniffi-python.js +0 -0
- package/tasks/._uniffi-release.mjs +0 -0
- package/tasks/._uniffi.ts +0 -0
- package/tasks/._version-check.ts +0 -0
- package/tasks/bump.ts +17 -34
- package/tasks/local-publish.ts +124 -117
- package/tasks/publish-npm.ts +62 -30
- package/tasks/publish-python.ts +38 -140
- package/tasks/publish-uniffi-local.ts +129 -84
- package/tasks/publish.ts +25 -139
- package/tasks/python-registry.ts +2 -9
- package/tasks/release-assets.ts +56 -65
- package/tasks/release-candidate.ts +123 -90
- package/tasks/release-pr.ts +266 -240
- package/tasks/release-summary.ts +8 -10
- package/tasks/release-version.ts +23 -2
- package/tasks/rust.ts +8 -13
- package/tasks/uniffi-python.d.ts +2 -3
- package/tasks/uniffi-python.js +7 -20
- package/tasks/uniffi-release.mjs +19 -13
- package/tasks/uniffi.ts +15 -24
- package/tasks/version-check.ts +24 -56
- package/src/release-plan.ts +0 -269
- package/src/release-please.ts +0 -242
- package/tasks/release-bootstrap.ts +0 -59
- package/tasks/release-plan.ts +0 -89
- package/tasks/release-please.ts +0 -162
- package/tasks/release-request.ts +0 -166
- package/tasks/release-summary-units.ts +0 -75
- package/tasks/stamp-python.ts +0 -13
|
@@ -1,46 +1,23 @@
|
|
|
1
|
-
/** Rust release planning
|
|
1
|
+
/** Rust release planning, candidate configuration, and Cargo promotion. */
|
|
2
2
|
import { existsSync, readFileSync } from "node:fs";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { dirname, join, resolve } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
-
import { stringUtils } from "@dbx-tools/shared-core";
|
|
7
6
|
import { TextFile, javascript } from "projen";
|
|
8
|
-
import { JobPermission, type Job
|
|
9
|
-
import { releaseBinaryAssetName } from "./_release-platform.ts";
|
|
7
|
+
import { JobPermission, type Job } from "projen/lib/github/workflows-model";
|
|
10
8
|
import { UNIFFI_BINDGEN_FEATURE, type RustProject } from "./_rust-project.ts";
|
|
11
|
-
import { BUN_VERSION } from "./bun-workflow.ts";
|
|
12
|
-
import type { DBXToolsJavaScriptProject } from "./project-js.ts";
|
|
13
9
|
import type {
|
|
14
10
|
DBXToolsRustWorkspaceOptions,
|
|
15
11
|
RustBindingMapping,
|
|
16
12
|
RustReleaseOs,
|
|
17
13
|
UniFFIReleaseTarget,
|
|
18
14
|
} from "./project-rs.ts";
|
|
19
|
-
import { defaultReleaseUnitId } from "./release-catalog.ts";
|
|
20
15
|
import { RELEASE_VERSION, releaseSourceSteps } from "./release-dispatch.ts";
|
|
21
|
-
import {
|
|
22
|
-
independentReleaseSetupSteps,
|
|
23
|
-
npmPublishEnvironment,
|
|
24
|
-
releasePublishCondition,
|
|
25
|
-
} from "./release.ts";
|
|
16
|
+
import { releasePublishCondition } from "./release.ts";
|
|
26
17
|
|
|
27
18
|
const require = createRequire(import.meta.url);
|
|
28
|
-
|
|
29
19
|
type RustPackageDependencyResolver = (pkg: RustProject) => RustProject[];
|
|
30
20
|
|
|
31
|
-
const RUST_BUILD_ENV = {
|
|
32
|
-
CARGO_INCREMENTAL: "0",
|
|
33
|
-
CARGO_TERM_COLOR: "always",
|
|
34
|
-
} as const;
|
|
35
|
-
|
|
36
|
-
function timedBash(phase: string, command: string): string {
|
|
37
|
-
return [
|
|
38
|
-
"SECONDS=0",
|
|
39
|
-
`trap 'status=$?; echo "phase=${phase} duration_seconds=$SECONDS status=$status"; exit "$status"' EXIT`,
|
|
40
|
-
command,
|
|
41
|
-
].join("\n");
|
|
42
|
-
}
|
|
43
|
-
|
|
44
21
|
function taskSource(name: string): string {
|
|
45
22
|
const sourceDirectory = dirname(fileURLToPath(import.meta.url));
|
|
46
23
|
const candidates = [
|
|
@@ -257,17 +234,6 @@ export function planRustRelease(
|
|
|
257
234
|
hasTargetOutputs,
|
|
258
235
|
};
|
|
259
236
|
}
|
|
260
|
-
|
|
261
|
-
function rustBuildJobIds(plan: RustReleasePlan): string[] {
|
|
262
|
-
return plan.targets.length ? ["rust-build"] : [];
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
function rustBuildResultCondition(plan: RustReleasePlan): string {
|
|
266
|
-
return rustBuildJobIds(plan)
|
|
267
|
-
.map((job) => `needs.${job}.result != 'failure' && needs.${job}.result != 'cancelled'`)
|
|
268
|
-
.join(" && ");
|
|
269
|
-
}
|
|
270
|
-
|
|
271
237
|
export function configureRustReleaseTask(
|
|
272
238
|
project: javascript.NodeProject,
|
|
273
239
|
plan: RustReleasePlan,
|
|
@@ -310,214 +276,6 @@ export function configureRustReleaseTask(
|
|
|
310
276
|
project.tryRemoveFile(".projen/rust-release.mjs");
|
|
311
277
|
}
|
|
312
278
|
|
|
313
|
-
function rustBindingCommands(plan: RustReleasePlan, independent: boolean): string[] {
|
|
314
|
-
return plan.bindings.map((binding) => {
|
|
315
|
-
const unit = defaultReleaseUnitId("rust", binding.crate);
|
|
316
|
-
const command = [
|
|
317
|
-
`node ${plan.releaseTask} build`,
|
|
318
|
-
`--crate "${binding.crate}"`,
|
|
319
|
-
`--node "${binding.node}"`,
|
|
320
|
-
`--python "${binding.python}"`,
|
|
321
|
-
`--node-package "${binding.nodePackage}"`,
|
|
322
|
-
`--python-package "${binding.pythonPackage}"`,
|
|
323
|
-
`--python-module "${binding.pythonModule}"`,
|
|
324
|
-
'--cargo-target "${{ matrix.cargo }}"',
|
|
325
|
-
'--node-triple "${{ matrix.node }}"',
|
|
326
|
-
'--python-tag "${{ matrix.python }}"',
|
|
327
|
-
'--os "${{ matrix.os }}"',
|
|
328
|
-
'--cpu "${{ matrix.cpu }}"',
|
|
329
|
-
'--libc "${{ matrix.libc }}"',
|
|
330
|
-
independent
|
|
331
|
-
? `--version "$(jq -r --arg unit "${unit}" '.units[] | select(.id == $unit) | .newVersion' dist/release-plan.json)"`
|
|
332
|
-
: '--version "$VERSION"',
|
|
333
|
-
`--output "dist/release/${binding.crate}/\${{ matrix.node }}"`,
|
|
334
|
-
"--skip-build",
|
|
335
|
-
].join(" \\\n ");
|
|
336
|
-
return independent
|
|
337
|
-
? [
|
|
338
|
-
`if jq -e --arg unit "${unit}" '.units[] | select(.id == $unit)' dist/release-plan.json >/dev/null; then`,
|
|
339
|
-
` ${command.replaceAll("\n", "\n ")}`,
|
|
340
|
-
"fi",
|
|
341
|
-
].join("\n")
|
|
342
|
-
: command;
|
|
343
|
-
});
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
function rustReleaseBinaryCondition(excludedOs: readonly RustReleaseOs[]): string | undefined {
|
|
347
|
-
return excludedOs.length
|
|
348
|
-
? `\${{ ${excludedOs.map((os) => `matrix.os != '${os}'`).join(" && ")} }}`
|
|
349
|
-
: undefined;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
function rustBinaryCommands(plan: RustReleasePlan, independent: boolean): string[] {
|
|
353
|
-
return plan.releaseBinaries.flatMap((pkg) => {
|
|
354
|
-
const unit = defaultReleaseUnitId("rust", pkg.crate);
|
|
355
|
-
const windowsAsset = releaseBinaryAssetName(pkg.binary, "${{ matrix.node }}", "win32");
|
|
356
|
-
const unixAsset = releaseBinaryAssetName(pkg.binary, "${{ matrix.node }}", "linux");
|
|
357
|
-
const commands = [
|
|
358
|
-
`mkdir -p "dist/release/${pkg.crate}/\${{ matrix.node }}/binary/stage"`,
|
|
359
|
-
`SOURCE="target/\${{ matrix.cargo }}/release/${pkg.binary}\${{ matrix.os == 'win32' && '.exe' || '' }}"`,
|
|
360
|
-
`DESTINATION="dist/release/${pkg.crate}/\${{ matrix.node }}/binary/stage/${pkg.binary}\${{ matrix.os == 'win32' && '.exe' || '' }}"`,
|
|
361
|
-
'cp "$SOURCE" "$DESTINATION"',
|
|
362
|
-
'if [ "${{ matrix.os }}" = "win32" ]; then',
|
|
363
|
-
` 7z a "dist/release/${pkg.crate}/\${{ matrix.node }}/binary/${windowsAsset}" "$DESTINATION"`,
|
|
364
|
-
"else",
|
|
365
|
-
` tar -C "dist/release/${pkg.crate}/\${{ matrix.node }}/binary/stage" -czf "dist/release/${pkg.crate}/\${{ matrix.node }}/binary/${unixAsset}" "${pkg.binary}"`,
|
|
366
|
-
"fi",
|
|
367
|
-
`rm -rf "dist/release/${pkg.crate}/\${{ matrix.node }}/binary/stage"`,
|
|
368
|
-
];
|
|
369
|
-
const excludedCondition = pkg.excludedOs
|
|
370
|
-
.map((os) => `[ "\${{ matrix.os }}" != "${os}" ]`)
|
|
371
|
-
.join(" && ");
|
|
372
|
-
const platformCommands = excludedCondition
|
|
373
|
-
? [`if ${excludedCondition}; then`, ...commands.map((command) => ` ${command}`), "fi"]
|
|
374
|
-
: commands;
|
|
375
|
-
return independent
|
|
376
|
-
? [
|
|
377
|
-
`if jq -e --arg unit "${unit}" '.units[] | select(.id == $unit)' dist/release-plan.json >/dev/null; then`,
|
|
378
|
-
...platformCommands.map((command) => ` ${command}`),
|
|
379
|
-
"fi",
|
|
380
|
-
]
|
|
381
|
-
: platformCommands;
|
|
382
|
-
});
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
function rustArtifactSteps(plan: RustReleasePlan): JobStep[] {
|
|
386
|
-
const binaryCrates = [...new Set(plan.releaseBinaries.map((binary) => binary.crate))];
|
|
387
|
-
return [
|
|
388
|
-
...plan.bindings.flatMap((binding) => [
|
|
389
|
-
...(binding.node
|
|
390
|
-
? [
|
|
391
|
-
{
|
|
392
|
-
name: `Upload ${binding.crate} native npm package`,
|
|
393
|
-
uses: "actions/upload-artifact@v7",
|
|
394
|
-
with: {
|
|
395
|
-
name: `${binding.crate}-\${{ matrix.node }}-npm`,
|
|
396
|
-
path: `dist/release/${binding.crate}/\${{ matrix.node }}/npm/*.tgz`,
|
|
397
|
-
"retention-days": 7,
|
|
398
|
-
},
|
|
399
|
-
},
|
|
400
|
-
]
|
|
401
|
-
: []),
|
|
402
|
-
...(binding.python
|
|
403
|
-
? [
|
|
404
|
-
{
|
|
405
|
-
name: `Upload ${binding.crate} Python wheel`,
|
|
406
|
-
uses: "actions/upload-artifact@v7",
|
|
407
|
-
with: {
|
|
408
|
-
name: `${binding.pythonPackage}--\${{ matrix.python }}--python-wheel`,
|
|
409
|
-
path: `dist/release/${binding.crate}/\${{ matrix.node }}/python/*.whl`,
|
|
410
|
-
"retention-days": 7,
|
|
411
|
-
},
|
|
412
|
-
},
|
|
413
|
-
]
|
|
414
|
-
: []),
|
|
415
|
-
]),
|
|
416
|
-
...binaryCrates.map((crate) => {
|
|
417
|
-
const binaries = plan.releaseBinaries.filter((binary) => binary.crate === crate);
|
|
418
|
-
const excludedOs =
|
|
419
|
-
binaries[0]?.excludedOs.filter((os) =>
|
|
420
|
-
binaries.every((binary) => binary.excludedOs.includes(os)),
|
|
421
|
-
) ?? [];
|
|
422
|
-
return {
|
|
423
|
-
name: `Upload ${crate} release binary`,
|
|
424
|
-
uses: "actions/upload-artifact@v7",
|
|
425
|
-
...(rustReleaseBinaryCondition(excludedOs)
|
|
426
|
-
? { if: rustReleaseBinaryCondition(excludedOs) }
|
|
427
|
-
: {}),
|
|
428
|
-
with: {
|
|
429
|
-
name: `${crate}-\${{ matrix.node }}-binary`,
|
|
430
|
-
path: `dist/release/${crate}/\${{ matrix.node }}/binary/*`,
|
|
431
|
-
"retention-days": 7,
|
|
432
|
-
},
|
|
433
|
-
};
|
|
434
|
-
}),
|
|
435
|
-
];
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
/** Build a Bash loop that preserves matrix values across LF and CRLF runners. */
|
|
439
|
-
function matrixArgumentLoop(variable: string, field: string, flag: string): string {
|
|
440
|
-
return `while IFS= read -r ${variable}; do ${variable}="\${${variable}%$'\\r'}"; ${variable}_ARGS+=(${flag} "$${variable}"); done < <(jq -r '.[]' <<<'\${{ toJSON(matrix.${field}) }}')`;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
function rustCargoBuildCommand(plan: RustReleasePlan): string {
|
|
444
|
-
return [
|
|
445
|
-
"PACKAGE_ARGS=()",
|
|
446
|
-
"FEATURE_ARGS=()",
|
|
447
|
-
matrixArgumentLoop("PACKAGE", "packages", "--package"),
|
|
448
|
-
matrixArgumentLoop("FEATURE", "features", "--features"),
|
|
449
|
-
`cargo build --release --timings "\${PACKAGE_ARGS[@]}" "\${FEATURE_ARGS[@]}"${
|
|
450
|
-
plan.usesCargoLock ? " --locked" : ""
|
|
451
|
-
} --target "\${{ matrix.cargo }}"`,
|
|
452
|
-
].join("\n");
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
export function rustBuildJob(plan: RustReleasePlan, setup: readonly JobStep[]): Job {
|
|
456
|
-
const bindingCommands = rustBindingCommands(plan, true);
|
|
457
|
-
const binaryCommands = rustBinaryCommands(plan, true);
|
|
458
|
-
return {
|
|
459
|
-
if: "${{ needs.release-plan.outputs.rust_targets != '[]' && (github.event_name == 'push' || inputs.stage != 'docs') }}",
|
|
460
|
-
name: "Rust / ${{ matrix.node }}",
|
|
461
|
-
needs: ["release-plan"],
|
|
462
|
-
runsOn: ["${{ matrix.runner }}"],
|
|
463
|
-
permissions: { contents: JobPermission.READ },
|
|
464
|
-
env: { ...RUST_BUILD_ENV, BUN_VERSION },
|
|
465
|
-
strategy: {
|
|
466
|
-
failFast: false,
|
|
467
|
-
matrix: {
|
|
468
|
-
include: "${{ fromJSON(needs.release-plan.outputs.rust_targets) }}" as never,
|
|
469
|
-
},
|
|
470
|
-
},
|
|
471
|
-
steps: [
|
|
472
|
-
...setup,
|
|
473
|
-
...(plan.hasPythonBindings ? [{ name: "Setup uv", uses: "astral-sh/setup-uv@v7" }] : []),
|
|
474
|
-
{
|
|
475
|
-
name: "Setup Rust",
|
|
476
|
-
uses: `dtolnay/rust-toolchain@${plan.releaseRustVersion}`,
|
|
477
|
-
with: { targets: "${{ matrix.cargo }}" },
|
|
478
|
-
},
|
|
479
|
-
{
|
|
480
|
-
name: "Install Linux native dependencies",
|
|
481
|
-
if: "${{ matrix.os == 'linux' }}",
|
|
482
|
-
// prettier-ignore
|
|
483
|
-
run: stringUtils.dedent(
|
|
484
|
-
// ============================================================================
|
|
485
|
-
/*bash*/`
|
|
486
|
-
sudo rm -f /etc/apt/sources.list.d/google-chrome.list
|
|
487
|
-
sudo apt-get update
|
|
488
|
-
sudo apt-get install --yes libdbus-1-dev pkg-config
|
|
489
|
-
`
|
|
490
|
-
// ============================================================================
|
|
491
|
-
),
|
|
492
|
-
},
|
|
493
|
-
{
|
|
494
|
-
name: "Build Rust release outputs",
|
|
495
|
-
shell: "bash",
|
|
496
|
-
run: timedBash("rust", rustCargoBuildCommand(plan)),
|
|
497
|
-
},
|
|
498
|
-
...(bindingCommands.length
|
|
499
|
-
? [
|
|
500
|
-
{
|
|
501
|
-
name: "Package UniFFI outputs",
|
|
502
|
-
shell: "bash",
|
|
503
|
-
run: timedBash("uniffi_packaging", bindingCommands.join("\n")),
|
|
504
|
-
},
|
|
505
|
-
]
|
|
506
|
-
: []),
|
|
507
|
-
...(binaryCommands.length
|
|
508
|
-
? [
|
|
509
|
-
{
|
|
510
|
-
name: "Package release binaries",
|
|
511
|
-
shell: "bash",
|
|
512
|
-
run: timedBash("binary_packaging", binaryCommands.join("\n")),
|
|
513
|
-
},
|
|
514
|
-
]
|
|
515
|
-
: []),
|
|
516
|
-
...rustArtifactSteps(plan),
|
|
517
|
-
],
|
|
518
|
-
};
|
|
519
|
-
}
|
|
520
|
-
|
|
521
279
|
export function rustCargoPublishJob(plan: RustReleasePlan): Job {
|
|
522
280
|
return {
|
|
523
281
|
if: releasePublishCondition("cargo", ["needs.verify-context.result == 'success'"]),
|
|
@@ -542,7 +300,7 @@ export function rustCargoPublishJob(plan: RustReleasePlan): Job {
|
|
|
542
300
|
`if cargo info "${crate}@$RELEASE_VERSION" >/dev/null 2>&1; then`,
|
|
543
301
|
` echo "skip published ${crate}@$RELEASE_VERSION"`,
|
|
544
302
|
"else",
|
|
545
|
-
` cargo publish --package "${crate}" --registry crates-io --
|
|
303
|
+
` cargo publish --package "${crate}" --registry crates-io --locked`,
|
|
546
304
|
"fi",
|
|
547
305
|
].join("\n"),
|
|
548
306
|
)
|
|
@@ -551,148 +309,3 @@ export function rustCargoPublishJob(plan: RustReleasePlan): Job {
|
|
|
551
309
|
],
|
|
552
310
|
};
|
|
553
311
|
}
|
|
554
|
-
|
|
555
|
-
export function independentRustCargoPublishJob(
|
|
556
|
-
project: DBXToolsJavaScriptProject,
|
|
557
|
-
plan: RustReleasePlan,
|
|
558
|
-
): Job {
|
|
559
|
-
const commands = plan.publicCrates.map((crate) =>
|
|
560
|
-
[
|
|
561
|
-
`VERSION="$(jq -r --arg package "${crate}" '.rustPackages[] | select(.identity == $package) | .version' dist/release-plan.json)"`,
|
|
562
|
-
'if [ -n "$VERSION" ]; then',
|
|
563
|
-
` if cargo info "${crate}@$VERSION" >/dev/null 2>&1; then`,
|
|
564
|
-
` echo "skip published ${crate}@$VERSION"`,
|
|
565
|
-
" else",
|
|
566
|
-
` cargo publish --package "${crate}" --registry crates-io --no-verify`,
|
|
567
|
-
" fi",
|
|
568
|
-
"fi",
|
|
569
|
-
].join("\n"),
|
|
570
|
-
);
|
|
571
|
-
const buildCondition = rustBuildResultCondition(plan);
|
|
572
|
-
return {
|
|
573
|
-
if: plan.hasTargetOutputs
|
|
574
|
-
? `\${{ always() && needs.release-plan.outputs.rust == 'true' && ${buildCondition} && (github.event_name == 'push' || inputs.stage == 'all' || inputs.stage == 'rust') }}`
|
|
575
|
-
: "${{ needs.release-plan.outputs.rust == 'true' && (github.event_name == 'push' || inputs.stage == 'all' || inputs.stage == 'rust') }}",
|
|
576
|
-
needs: ["release-plan", ...rustBuildJobIds(plan)],
|
|
577
|
-
runsOn: ["ubuntu-latest"],
|
|
578
|
-
permissions: { contents: JobPermission.READ },
|
|
579
|
-
env: { BUN_VERSION },
|
|
580
|
-
steps: [
|
|
581
|
-
...independentReleaseSetupSteps(project),
|
|
582
|
-
{
|
|
583
|
-
name: "Setup Rust",
|
|
584
|
-
uses: `dtolnay/rust-toolchain@${plan.releaseRustVersion}`,
|
|
585
|
-
},
|
|
586
|
-
{
|
|
587
|
-
name: "Publish affected Cargo crates",
|
|
588
|
-
env: { CARGO_REGISTRY_TOKEN: "${{ secrets.CARGO_REGISTRY_TOKEN }}" },
|
|
589
|
-
run: commands.join("\n"),
|
|
590
|
-
},
|
|
591
|
-
],
|
|
592
|
-
};
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
export function independentRustGitHubReleaseJob(
|
|
596
|
-
project: DBXToolsJavaScriptProject,
|
|
597
|
-
plan: RustReleasePlan,
|
|
598
|
-
): Job {
|
|
599
|
-
return {
|
|
600
|
-
if: "${{ needs.release-plan.outputs.github == 'true' && (github.event_name == 'push' || inputs.stage == 'all' || inputs.stage == 'github') }}",
|
|
601
|
-
needs: ["release-plan", ...rustBuildJobIds(plan)],
|
|
602
|
-
runsOn: ["ubuntu-latest"],
|
|
603
|
-
permissions: { contents: JobPermission.WRITE },
|
|
604
|
-
env: { BUN_VERSION },
|
|
605
|
-
steps: [
|
|
606
|
-
...independentReleaseSetupSteps(project),
|
|
607
|
-
{
|
|
608
|
-
name: "Download release binaries",
|
|
609
|
-
uses: "actions/download-artifact@v8",
|
|
610
|
-
with: {
|
|
611
|
-
pattern: "*-binary",
|
|
612
|
-
path: "dist/rust-release",
|
|
613
|
-
"merge-multiple": true,
|
|
614
|
-
},
|
|
615
|
-
},
|
|
616
|
-
{
|
|
617
|
-
name: "Upload affected GitHub release assets",
|
|
618
|
-
env: { GH_TOKEN: "${{ github.token }}" },
|
|
619
|
-
shell: "bash",
|
|
620
|
-
run: plan.releaseBinaries
|
|
621
|
-
.map((binary) => {
|
|
622
|
-
const unit = defaultReleaseUnitId("rust", binary.crate);
|
|
623
|
-
return [
|
|
624
|
-
`VERSION="$(jq -r --arg unit "${unit}" '.units[] | select(.id == $unit) | .newVersion' dist/release-plan.json)"`,
|
|
625
|
-
'if [ -n "$VERSION" ]; then',
|
|
626
|
-
` gh release upload "${unit}-v$VERSION" dist/rust-release/${binary.binary}-* --clobber`,
|
|
627
|
-
"fi",
|
|
628
|
-
].join("\n");
|
|
629
|
-
})
|
|
630
|
-
.join("\n"),
|
|
631
|
-
},
|
|
632
|
-
],
|
|
633
|
-
};
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
export function independentRustNativeNpmPublishJob(project: DBXToolsJavaScriptProject): Job {
|
|
637
|
-
return {
|
|
638
|
-
if: "${{ needs.release-plan.outputs.node == 'true' && (github.event_name == 'push' || inputs.stage == 'all' || inputs.stage == 'node') }}",
|
|
639
|
-
needs: ["release-plan", "rust-build"],
|
|
640
|
-
runsOn: ["ubuntu-latest"],
|
|
641
|
-
permissions: { contents: JobPermission.READ, idToken: JobPermission.WRITE },
|
|
642
|
-
timeoutMinutes: 15,
|
|
643
|
-
env: { BUN_VERSION, CI: "true" },
|
|
644
|
-
steps: [
|
|
645
|
-
...independentReleaseSetupSteps(project),
|
|
646
|
-
{
|
|
647
|
-
name: "Download native npm packages",
|
|
648
|
-
uses: "actions/download-artifact@v8",
|
|
649
|
-
with: {
|
|
650
|
-
pattern: "*-npm",
|
|
651
|
-
path: "dist/uniffi/native",
|
|
652
|
-
"merge-multiple": true,
|
|
653
|
-
},
|
|
654
|
-
},
|
|
655
|
-
{
|
|
656
|
-
name: "Publish affected native npm packages",
|
|
657
|
-
env: npmPublishEnvironment(),
|
|
658
|
-
run: "bun node_modules/@dbx-tools/projen/tasks/publish-npm.ts --directory dist/uniffi/native",
|
|
659
|
-
},
|
|
660
|
-
],
|
|
661
|
-
};
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
export function independentRustNodeFacadePublishJob(
|
|
665
|
-
project: DBXToolsJavaScriptProject,
|
|
666
|
-
bindings: readonly RustBindingMapping[],
|
|
667
|
-
): Job {
|
|
668
|
-
return {
|
|
669
|
-
if: "${{ needs.release-plan.outputs.node == 'true' && (github.event_name == 'push' || inputs.stage == 'all' || inputs.stage == 'node') }}",
|
|
670
|
-
needs: ["release-plan", "publish-node", "publish-native-npm"],
|
|
671
|
-
runsOn: ["ubuntu-latest"],
|
|
672
|
-
permissions: { contents: JobPermission.READ, idToken: JobPermission.WRITE },
|
|
673
|
-
timeoutMinutes: 30,
|
|
674
|
-
env: { BUN_VERSION, CI: "true" },
|
|
675
|
-
steps: [
|
|
676
|
-
...independentReleaseSetupSteps(project),
|
|
677
|
-
{
|
|
678
|
-
name: "Build and publish affected UniFFI npm facades",
|
|
679
|
-
env: npmPublishEnvironment(),
|
|
680
|
-
shell: "bash",
|
|
681
|
-
run: bindings
|
|
682
|
-
.flatMap((binding) => {
|
|
683
|
-
if (!binding.node || !binding.nodePackage) return [];
|
|
684
|
-
const unit = defaultReleaseUnitId("rust", binding.crate);
|
|
685
|
-
const output = `dist/uniffi/facades/${binding.crate}`;
|
|
686
|
-
return [
|
|
687
|
-
`VERSION="$(jq -r --arg unit "${unit}" '.units[] | select(.id == $unit) | .newVersion' dist/release-plan.json)"`,
|
|
688
|
-
'if [ -n "$VERSION" ]; then',
|
|
689
|
-
` node .projen/uniffi-release.mjs facade --node "${binding.node}" --node-package "${binding.nodePackage}" --node-triple "linux-x64-gnu" --version "$VERSION" --output "${output}"`,
|
|
690
|
-
` bun node_modules/@dbx-tools/projen/tasks/publish-npm.ts --directory "${output}/npm-facade" --version "$VERSION"`,
|
|
691
|
-
"fi",
|
|
692
|
-
];
|
|
693
|
-
})
|
|
694
|
-
.join("\n"),
|
|
695
|
-
},
|
|
696
|
-
],
|
|
697
|
-
};
|
|
698
|
-
}
|
package/src/_task-command.ts
CHANGED
|
@@ -12,6 +12,13 @@ export interface CaptureTaskCommandOptions extends TaskCommandOptions {
|
|
|
12
12
|
readonly check?: boolean;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
export type ProbeTaskCommandOptions = TaskCommandOptions;
|
|
16
|
+
|
|
17
|
+
export interface LoggedTaskCommandOptions extends TaskCommandOptions {
|
|
18
|
+
/** Receive normalized stdout and stderr lines after the command exits. */
|
|
19
|
+
readonly onLine: (line: string) => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
15
22
|
function executable(command: string): string {
|
|
16
23
|
return command === "bun" && process.versions.bun ? process.execPath : command;
|
|
17
24
|
}
|
|
@@ -69,6 +76,47 @@ export function captureTaskCommand(
|
|
|
69
76
|
return result.exitCode === 0 ? (result.stdout?.trim() ?? "") : "";
|
|
70
77
|
}
|
|
71
78
|
|
|
79
|
+
/** Capture trimmed stdout while preserving command failure as `undefined`. */
|
|
80
|
+
export function probeTaskCommand(
|
|
81
|
+
cwd: string,
|
|
82
|
+
command: string,
|
|
83
|
+
args: readonly string[],
|
|
84
|
+
options: ProbeTaskCommandOptions = {},
|
|
85
|
+
): string | undefined {
|
|
86
|
+
const result = exec.spawnSync(executable(command), [...args], {
|
|
87
|
+
cwd,
|
|
88
|
+
env: options.env,
|
|
89
|
+
stdout: "capture",
|
|
90
|
+
stderr: options.stderr ?? "ignore",
|
|
91
|
+
stdin: "ignore",
|
|
92
|
+
check: false,
|
|
93
|
+
});
|
|
94
|
+
return result.exitCode === 0 ? (result.stdout?.trim() ?? "") : undefined;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Run a checked command while routing captured output through one line policy. */
|
|
98
|
+
export function runLoggedTaskCommand(
|
|
99
|
+
cwd: string,
|
|
100
|
+
command: string,
|
|
101
|
+
args: readonly string[],
|
|
102
|
+
options: LoggedTaskCommandOptions,
|
|
103
|
+
): void {
|
|
104
|
+
const result = exec.spawnSync(executable(command), [...args], {
|
|
105
|
+
cwd,
|
|
106
|
+
env: options.env,
|
|
107
|
+
stdout: "capture",
|
|
108
|
+
stderr: "capture",
|
|
109
|
+
stdin: "ignore",
|
|
110
|
+
check: false,
|
|
111
|
+
});
|
|
112
|
+
for (const line of [...result.stdoutLines, ...result.stderrLines]) {
|
|
113
|
+
if (line) options.onLine(line);
|
|
114
|
+
}
|
|
115
|
+
if (result.exitCode !== 0) {
|
|
116
|
+
throw new Error(`${command} exited with ${result.exitCode}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
72
120
|
/** Whether a quiet, non-interactive command exits successfully. */
|
|
73
121
|
export function taskCommandSucceeds(
|
|
74
122
|
cwd: string,
|
|
@@ -87,3 +135,30 @@ export function taskCommandSucceeds(
|
|
|
87
135
|
}).exitCode === 0
|
|
88
136
|
);
|
|
89
137
|
}
|
|
138
|
+
|
|
139
|
+
/** Run Git with the shared non-interactive checked command policy. */
|
|
140
|
+
export function runGitTaskCommand(
|
|
141
|
+
cwd: string,
|
|
142
|
+
args: readonly string[],
|
|
143
|
+
options: TaskCommandOptions = {},
|
|
144
|
+
): void {
|
|
145
|
+
runTaskCommand(cwd, "git", args, options);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** Capture Git output, returning an empty string for optional offline probes. */
|
|
149
|
+
export function captureGitTaskCommand(
|
|
150
|
+
cwd: string,
|
|
151
|
+
args: readonly string[],
|
|
152
|
+
options: CaptureTaskCommandOptions = {},
|
|
153
|
+
): string {
|
|
154
|
+
return captureTaskCommand(cwd, "git", args, options);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** Whether a quiet Git command succeeds. */
|
|
158
|
+
export function gitTaskCommandSucceeds(
|
|
159
|
+
cwd: string,
|
|
160
|
+
args: readonly string[],
|
|
161
|
+
options: Pick<TaskCommandOptions, "env"> = {},
|
|
162
|
+
): boolean {
|
|
163
|
+
return taskCommandSucceeds(cwd, "git", args, options);
|
|
164
|
+
}
|
package/src/project-js.ts
CHANGED
|
@@ -15,7 +15,7 @@ import { type IConstruct } from "constructs";
|
|
|
15
15
|
import { Component, IgnoreFile, Project, type TaskOptions, javascript, typescript } from "projen";
|
|
16
16
|
import { BuildWorkflow } from "projen/lib/build";
|
|
17
17
|
import { AutoMerge } from "projen/lib/github";
|
|
18
|
-
import { JobPermission, type JobStep
|
|
18
|
+
import { JobPermission, type JobStep } from "projen/lib/github/workflows-model";
|
|
19
19
|
import type { ReleaseProjectOptions } from "projen/lib/release";
|
|
20
20
|
import { mixin } from "..";
|
|
21
21
|
import { generateBarrels } from "./barrels.ts";
|
|
@@ -44,7 +44,6 @@ import { PROJEN_VERSION } from "./projen-version.ts";
|
|
|
44
44
|
import { applyCompiledPublish } from "./publish.ts";
|
|
45
45
|
import {
|
|
46
46
|
DBXToolsReleaseCatalog,
|
|
47
|
-
type DBXToolsVersioningMode,
|
|
48
47
|
type ExternalReleaseProjectRegistration,
|
|
49
48
|
type ReleaseDependencyInput,
|
|
50
49
|
type ReleaseUnitRule,
|
|
@@ -628,18 +627,12 @@ export type DBXToolsJavaScriptProjectOptions = CommonProjectOptions &
|
|
|
628
627
|
readonly releaseValidationTasks?: readonly string[];
|
|
629
628
|
/** Optional AI-generated release summary. Defaults to enabled. */
|
|
630
629
|
readonly releaseSummary?: boolean | ReleaseSummaryOptions;
|
|
631
|
-
/** Existing source branch safely fast-forwarded after an independent release. */
|
|
632
|
-
readonly releaseSyncBranch?: string | false;
|
|
633
630
|
/** Set to `false` to omit normal npm workspace publication. */
|
|
634
631
|
readonly nodeRelease?: boolean;
|
|
635
632
|
/** Unified dbx-tools release workflow, or no release surface. Defaults to `dbx-tools`. */
|
|
636
633
|
readonly releaseMode?: DBXToolsReleaseMode;
|
|
637
|
-
/** Package version ownership mode. Defaults to `fixed`. */
|
|
638
|
-
readonly versioningMode?: DBXToolsVersioningMode;
|
|
639
634
|
/** Explicit stable release-unit grouping rules. */
|
|
640
635
|
readonly releaseUnits?: readonly ReleaseUnitRule[];
|
|
641
|
-
/** Commit before the first independent Release Please history. */
|
|
642
|
-
readonly releaseBootstrapSha?: string;
|
|
643
636
|
/** Publishable workspace members synthesized outside the attached project tree. */
|
|
644
637
|
readonly externalReleaseProjects?: readonly ExternalReleaseProjectRegistration[];
|
|
645
638
|
/** Prefix for generated release tags. Defaults to `v`. */
|
|
@@ -723,10 +716,8 @@ export class DBXToolsNodeProject
|
|
|
723
716
|
// (its build phase installs with pnpm and reads catalog + `allowBuilds`).
|
|
724
717
|
pnpmWorkspace.attachWorkspaceFile(this);
|
|
725
718
|
this.releaseCatalog = new DBXToolsReleaseCatalog(this, {
|
|
726
|
-
mode: options.versioningMode,
|
|
727
719
|
units: options.releaseUnits,
|
|
728
720
|
externalProjects: options.externalReleaseProjects,
|
|
729
|
-
bootstrapSha: options.releaseBootstrapSha,
|
|
730
721
|
});
|
|
731
722
|
registerJavaScriptReleaseProject(this);
|
|
732
723
|
this.package.addField("version", () => this.releaseCatalog.versionFor(this));
|
|
@@ -862,10 +853,8 @@ export class DBXToolsTypeScriptProject
|
|
|
862
853
|
(parent instanceof DBXToolsNodeProject || parent instanceof DBXToolsTypeScriptProject)
|
|
863
854
|
? parent.releaseCatalog
|
|
864
855
|
: new DBXToolsReleaseCatalog(this, {
|
|
865
|
-
mode: options.versioningMode,
|
|
866
856
|
units: options.releaseUnits,
|
|
867
857
|
externalProjects: options.externalReleaseProjects,
|
|
868
|
-
bootstrapSha: options.releaseBootstrapSha,
|
|
869
858
|
});
|
|
870
859
|
// Pairs with `jsx` in SHARED_COMPILER_OPTIONS: projen's default `include` is
|
|
871
860
|
// `src/**/*.ts` only, which silently omits a `.tsx` file from the program
|
|
@@ -937,35 +926,7 @@ function configureBuildWorkflow(
|
|
|
937
926
|
});
|
|
938
927
|
validation.exec("bunx projen default");
|
|
939
928
|
validation.exec("bun run compile");
|
|
940
|
-
const configured = {
|
|
941
|
-
...options.buildWorkflowOptions,
|
|
942
|
-
...(!options.buildWorkflowOptions?.workflowTriggers &&
|
|
943
|
-
project.releaseCatalog.mode === "independent"
|
|
944
|
-
? {
|
|
945
|
-
workflowTriggers: {
|
|
946
|
-
pullRequest: {
|
|
947
|
-
types: ["opened", "synchronize", "reopened", "closed"],
|
|
948
|
-
paths: [
|
|
949
|
-
"**",
|
|
950
|
-
"!.projen/release-units.json",
|
|
951
|
-
"!.release-please-manifest.json",
|
|
952
|
-
"!.release-units/**",
|
|
953
|
-
"!.release-notes/**",
|
|
954
|
-
"!docs/releases/**",
|
|
955
|
-
"!Cargo.lock",
|
|
956
|
-
"!**/Cargo.toml",
|
|
957
|
-
"!**/package.json",
|
|
958
|
-
"!**/pyproject.toml",
|
|
959
|
-
"!**/index.ts",
|
|
960
|
-
"!packages/js/node/rust-binary/src/_release-binaries.ts",
|
|
961
|
-
"!packages/js/node/appkit-graphiti/src/_python-runtime.ts",
|
|
962
|
-
],
|
|
963
|
-
},
|
|
964
|
-
workflowDispatch: {},
|
|
965
|
-
} satisfies Triggers,
|
|
966
|
-
}
|
|
967
|
-
: {}),
|
|
968
|
-
};
|
|
929
|
+
const configured = { ...options.buildWorkflowOptions };
|
|
969
930
|
const compatibility = nodeWorkflowCompatibility(project);
|
|
970
931
|
const configuredRunner = configured.runsOn !== undefined || configured.runsOnGroup !== undefined;
|
|
971
932
|
const workflow = new BuildWorkflow(project, {
|
|
@@ -1620,7 +1581,6 @@ function initProject(
|
|
|
1620
1581
|
pythonRoot: options.releasePythonRoot,
|
|
1621
1582
|
validationTasks: options.releaseValidationTasks,
|
|
1622
1583
|
summary: options.releaseSummary,
|
|
1623
|
-
syncBranch: options.releaseSyncBranch,
|
|
1624
1584
|
});
|
|
1625
1585
|
}
|
|
1626
1586
|
}
|