@dbx-tools/projen 0.6.229 → 0.7.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/README.md +59 -85
- package/index.ts +9 -1
- package/package.json +8 -5
- package/src/openapi.ts +9 -1
- package/src/project-js.ts +68 -10
- package/src/project-py.ts +133 -4
- package/src/project-rs.ts +392 -25
- package/src/release-catalog.ts +832 -0
- package/src/release-dispatch.ts +3 -2
- package/src/release-plan.ts +236 -0
- package/src/release-please.ts +242 -0
- package/src/release.ts +428 -0
- package/tasks/publish-npm.ts +4 -4
- package/tasks/publish-python.ts +56 -14
- package/tasks/publish.ts +60 -30
- package/tasks/release-bootstrap.ts +59 -0
- package/tasks/release-plan.ts +89 -0
- package/tasks/release-please.ts +163 -0
- package/tasks/release-summary-units.ts +44 -0
- package/tasks/release-summary.ts +33 -7
- package/tasks/uniffi-python.d.ts +5 -0
- package/tasks/uniffi-python.js +21 -2
- package/tasks/uniffi-release.mjs +8 -3
- package/tasks/version-check.ts +43 -15
package/src/project-rs.ts
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
import { isDBXToolsJavaScriptProject } from "./project-predicate.ts";
|
|
18
18
|
import { pythonModuleName, type PythonPackageOptions } from "./project-py.ts";
|
|
19
19
|
import type { DBXToolsProject } from "./project.ts";
|
|
20
|
+
import { defaultReleaseUnitId, type ReleaseDependencyInput } from "./release-catalog.ts";
|
|
20
21
|
import {
|
|
21
22
|
RELEASE_SHA,
|
|
22
23
|
RELEASE_SUMMARY_FILE,
|
|
@@ -26,8 +27,10 @@ import {
|
|
|
26
27
|
} from "./release-dispatch.ts";
|
|
27
28
|
import {
|
|
28
29
|
hasNodeRelease,
|
|
30
|
+
independentReleaseSetupSteps,
|
|
29
31
|
npmPublishEnvironment,
|
|
30
32
|
nodeReleaseSetupSteps,
|
|
33
|
+
registerIndependentPublicationJob,
|
|
31
34
|
releaseArtifactSteps,
|
|
32
35
|
releaseStageCondition,
|
|
33
36
|
tryReleaseWorkflow,
|
|
@@ -330,6 +333,10 @@ export interface RustReleaseBinaryMapping {
|
|
|
330
333
|
readonly command: string;
|
|
331
334
|
readonly description: string;
|
|
332
335
|
readonly binaryName: string;
|
|
336
|
+
readonly unit: string;
|
|
337
|
+
readonly component: string;
|
|
338
|
+
readonly version: string;
|
|
339
|
+
readonly tag: string;
|
|
333
340
|
readonly repository: string;
|
|
334
341
|
readonly assets: readonly RustReleaseBinaryAssetMapping[];
|
|
335
342
|
}
|
|
@@ -426,6 +433,7 @@ export class DBXToolsRustProject extends Project implements DBXToolsProject {
|
|
|
426
433
|
readonly crateName: string;
|
|
427
434
|
readonly packageOptions: RustPackageOptions;
|
|
428
435
|
readonly uniffi: boolean;
|
|
436
|
+
readonly manifestFile: TomlFile;
|
|
429
437
|
|
|
430
438
|
constructor(
|
|
431
439
|
parent: javascript.NodeProject,
|
|
@@ -441,10 +449,18 @@ export class DBXToolsRustProject extends Project implements DBXToolsProject {
|
|
|
441
449
|
const library = existsSync(join(this.outdir, "src/lib.rs"));
|
|
442
450
|
const binary = existsSync(join(this.outdir, "src/main.rs"));
|
|
443
451
|
const binaryName = options.binaryName ?? crateName;
|
|
452
|
+
const packageVersion =
|
|
453
|
+
isDBXToolsJavaScriptProject()(parent) && parent.releaseCatalog.mode === "independent"
|
|
454
|
+
? parent.releaseCatalog.versionForRegistration(
|
|
455
|
+
"rust",
|
|
456
|
+
crateName,
|
|
457
|
+
`${root}/${options.directory}`,
|
|
458
|
+
)
|
|
459
|
+
: { workspace: true };
|
|
444
460
|
const manifest: Record<string, unknown> = {
|
|
445
461
|
package: {
|
|
446
462
|
name: crateName,
|
|
447
|
-
version:
|
|
463
|
+
version: packageVersion,
|
|
448
464
|
edition: { workspace: true },
|
|
449
465
|
"rust-version": { workspace: true },
|
|
450
466
|
description: options.description ?? crateName,
|
|
@@ -499,7 +515,7 @@ export class DBXToolsRustProject extends Project implements DBXToolsProject {
|
|
|
499
515
|
}
|
|
500
516
|
: {}),
|
|
501
517
|
};
|
|
502
|
-
new TomlFile(this, "Cargo.toml", { marker: false, obj: manifest });
|
|
518
|
+
this.manifestFile = new TomlFile(this, "Cargo.toml", { marker: false, obj: manifest });
|
|
503
519
|
if (this.uniffi) {
|
|
504
520
|
new TextFile(this, "uniffi-bindgen.rs", {
|
|
505
521
|
lines: ["fn main() {", " uniffi::uniffi_bindgen_main();", "}", ""],
|
|
@@ -592,6 +608,7 @@ function createRustPackageDependencyResolver(
|
|
|
592
608
|
}
|
|
593
609
|
|
|
594
610
|
function planRustReleaseBinaries(
|
|
611
|
+
project: javascript.NodeProject,
|
|
595
612
|
packages: readonly DBXToolsRustProject[],
|
|
596
613
|
resolved: ResolvedRustWorkspaceOptions,
|
|
597
614
|
): RustReleaseBinaryMapping[] {
|
|
@@ -620,10 +637,20 @@ function planRustReleaseBinaries(
|
|
|
620
637
|
pkg.crateName;
|
|
621
638
|
const excludedOs = new Set(pkg.packageOptions.releaseExcludeOs ?? []);
|
|
622
639
|
const binaryName = pkg.packageOptions.binaryName ?? pkg.crateName;
|
|
640
|
+
const identity = isDBXToolsJavaScriptProject()(project)
|
|
641
|
+
? project.releaseCatalog.releaseIdentityFor(pkg)
|
|
642
|
+
: {
|
|
643
|
+
component: defaultReleaseUnitId("rust", pkg.crateName),
|
|
644
|
+
version: readWorkspaceVersion(project.outdir),
|
|
645
|
+
};
|
|
623
646
|
return {
|
|
624
647
|
command,
|
|
625
648
|
description,
|
|
626
649
|
binaryName,
|
|
650
|
+
unit: "id" in identity ? identity.id : identity.component,
|
|
651
|
+
component: identity.component,
|
|
652
|
+
version: identity.version,
|
|
653
|
+
tag: `${identity.component}-v${identity.version}`,
|
|
627
654
|
repository: resolved.repository,
|
|
628
655
|
assets: resolved.nativeTargets
|
|
629
656
|
.filter((target) => !excludedOs.has(target.os))
|
|
@@ -782,11 +809,13 @@ function planNodeBindingPackages(
|
|
|
782
809
|
plan: RustBindingPlan,
|
|
783
810
|
resolved: ResolvedRustWorkspaceOptions,
|
|
784
811
|
): RustNodeBindingPackagePlan[] {
|
|
785
|
-
const version = readWorkspaceVersion(project.outdir);
|
|
786
812
|
return plan.packages
|
|
787
813
|
.filter((pkg) => (pkg.packageOptions.bindings ?? ["node", "python"]).includes("node"))
|
|
788
814
|
.map((binding) => {
|
|
789
815
|
const directory = `${string.toSlug(binding.packageOptions.directory)}-rs`;
|
|
816
|
+
const version = isDBXToolsJavaScriptProject()(project)
|
|
817
|
+
? project.releaseCatalog.versionFor(binding)
|
|
818
|
+
: readWorkspaceVersion(project.outdir);
|
|
790
819
|
return {
|
|
791
820
|
binding,
|
|
792
821
|
memberPath: `${resolved.nodeRoot}/${directory}`,
|
|
@@ -945,7 +974,9 @@ function configureRustWorkspaceFiles(
|
|
|
945
974
|
.map((pkg) => `${resolved.root}/${pkg.packageOptions.directory}`),
|
|
946
975
|
resolver: "2",
|
|
947
976
|
package: {
|
|
948
|
-
|
|
977
|
+
...(!isDBXToolsJavaScriptProject()(project) || project.releaseCatalog.mode === "fixed"
|
|
978
|
+
? { version: readWorkspaceVersion(project.outdir) }
|
|
979
|
+
: {}),
|
|
949
980
|
edition: options.edition ?? "2021",
|
|
950
981
|
"rust-version": options.rustVersion ?? "1.82",
|
|
951
982
|
license: options.license ?? DBX_TOOLS_LICENSE,
|
|
@@ -1120,9 +1151,10 @@ function configureRustReleaseTask(project: javascript.NodeProject, plan: RustRel
|
|
|
1120
1151
|
}
|
|
1121
1152
|
}
|
|
1122
1153
|
|
|
1123
|
-
function rustBindingCommands(plan: RustReleasePlan): string[] {
|
|
1124
|
-
return plan.bindings.map((binding) =>
|
|
1125
|
-
|
|
1154
|
+
function rustBindingCommands(plan: RustReleasePlan, independent: boolean): string[] {
|
|
1155
|
+
return plan.bindings.map((binding) => {
|
|
1156
|
+
const unit = defaultReleaseUnitId("rust", binding.crate);
|
|
1157
|
+
const command = [
|
|
1126
1158
|
`node ${plan.releaseTask} build`,
|
|
1127
1159
|
`--crate "${binding.crate}"`,
|
|
1128
1160
|
`--node "${binding.node}"`,
|
|
@@ -1136,11 +1168,20 @@ function rustBindingCommands(plan: RustReleasePlan): string[] {
|
|
|
1136
1168
|
'--os "${{ matrix.os }}"',
|
|
1137
1169
|
'--cpu "${{ matrix.cpu }}"',
|
|
1138
1170
|
'--libc "${{ matrix.libc }}"',
|
|
1139
|
-
|
|
1171
|
+
independent
|
|
1172
|
+
? `--version "$(jq -r --arg unit "${unit}" '.units[] | select(.id == $unit) | .newVersion' dist/release-plan.json)"`
|
|
1173
|
+
: '--version "$VERSION"',
|
|
1140
1174
|
`--output "dist/release/${binding.crate}/\${{ matrix.node }}"`,
|
|
1141
1175
|
"--skip-build",
|
|
1142
|
-
].join(" \\\n ")
|
|
1143
|
-
|
|
1176
|
+
].join(" \\\n ");
|
|
1177
|
+
return independent
|
|
1178
|
+
? [
|
|
1179
|
+
`if jq -e --arg unit "${unit}" '.units[] | select(.id == $unit)' dist/release-plan.json >/dev/null; then`,
|
|
1180
|
+
` ${command.replaceAll("\n", "\n ")}`,
|
|
1181
|
+
"fi",
|
|
1182
|
+
].join("\n")
|
|
1183
|
+
: command;
|
|
1184
|
+
});
|
|
1144
1185
|
}
|
|
1145
1186
|
|
|
1146
1187
|
function rustReleaseBinaryCondition(excludedOs: readonly RustReleaseOs[]): string | undefined {
|
|
@@ -1149,8 +1190,9 @@ function rustReleaseBinaryCondition(excludedOs: readonly RustReleaseOs[]): strin
|
|
|
1149
1190
|
: undefined;
|
|
1150
1191
|
}
|
|
1151
1192
|
|
|
1152
|
-
function rustBinaryCommands(plan: RustReleasePlan): string[] {
|
|
1193
|
+
function rustBinaryCommands(plan: RustReleasePlan, independent: boolean): string[] {
|
|
1153
1194
|
return plan.releaseBinaries.flatMap((pkg) => {
|
|
1195
|
+
const unit = defaultReleaseUnitId("rust", pkg.crate);
|
|
1154
1196
|
const windowsAsset = releaseBinaryAssetName(
|
|
1155
1197
|
pkg.binary,
|
|
1156
1198
|
"${{ matrix.node }}",
|
|
@@ -1172,9 +1214,16 @@ function rustBinaryCommands(plan: RustReleasePlan): string[] {
|
|
|
1172
1214
|
const excludedCondition = pkg.excludedOs
|
|
1173
1215
|
.map((os) => `[ "\${{ matrix.os }}" != "${os}" ]`)
|
|
1174
1216
|
.join(" && ");
|
|
1175
|
-
|
|
1217
|
+
const platformCommands = excludedCondition
|
|
1176
1218
|
? [`if ${excludedCondition}; then`, ...commands.map((command) => ` ${command}`), "fi"]
|
|
1177
1219
|
: commands;
|
|
1220
|
+
return independent
|
|
1221
|
+
? [
|
|
1222
|
+
`if jq -e --arg unit "${unit}" '.units[] | select(.id == $unit)' dist/release-plan.json >/dev/null; then`,
|
|
1223
|
+
...platformCommands.map((command) => ` ${command}`),
|
|
1224
|
+
"fi",
|
|
1225
|
+
]
|
|
1226
|
+
: platformCommands;
|
|
1178
1227
|
});
|
|
1179
1228
|
}
|
|
1180
1229
|
|
|
@@ -1223,22 +1272,31 @@ function rustArtifactSteps(plan: RustReleasePlan): JobStep[] {
|
|
|
1223
1272
|
];
|
|
1224
1273
|
}
|
|
1225
1274
|
|
|
1226
|
-
function rustBuildJob(plan: RustReleasePlan): Job {
|
|
1227
|
-
const bindingCommands = rustBindingCommands(plan);
|
|
1228
|
-
const binaryCommands = rustBinaryCommands(plan);
|
|
1275
|
+
function rustBuildJob(plan: RustReleasePlan, independentSetup?: readonly JobStep[]): Job {
|
|
1276
|
+
const bindingCommands = rustBindingCommands(plan, Boolean(independentSetup));
|
|
1277
|
+
const binaryCommands = rustBinaryCommands(plan, Boolean(independentSetup));
|
|
1229
1278
|
return {
|
|
1230
|
-
if:
|
|
1279
|
+
if: independentSetup
|
|
1280
|
+
? "${{ needs.release-plan.outputs.rust_targets != '[]' && (github.event_name == 'push' || inputs.stage != 'docs') }}"
|
|
1281
|
+
: "${{ github.event_name == 'push' || inputs.stage == 'all' }}",
|
|
1231
1282
|
name: "${{ matrix.node }}",
|
|
1232
|
-
needs: ["verify-context"],
|
|
1283
|
+
needs: [independentSetup ? "release-plan" : "verify-context"],
|
|
1233
1284
|
runsOn: ["${{ matrix.runner }}"],
|
|
1234
1285
|
permissions: { contents: JobPermission.READ },
|
|
1235
|
-
env: {
|
|
1286
|
+
env: {
|
|
1287
|
+
...RUST_CACHE_ENV,
|
|
1288
|
+
...(independentSetup ? { BUN_VERSION } : {}),
|
|
1289
|
+
},
|
|
1236
1290
|
strategy: {
|
|
1237
1291
|
failFast: false,
|
|
1238
|
-
matrix: {
|
|
1292
|
+
matrix: {
|
|
1293
|
+
include: independentSetup
|
|
1294
|
+
? ("${{ fromJSON(needs.release-plan.outputs.rust_targets) }}" as never)
|
|
1295
|
+
: [...plan.targets],
|
|
1296
|
+
},
|
|
1239
1297
|
},
|
|
1240
1298
|
steps: [
|
|
1241
|
-
...releaseSourceSteps(),
|
|
1299
|
+
...(independentSetup ?? releaseSourceSteps()),
|
|
1242
1300
|
...(plan.hasPythonBindings ? [{ name: "Setup uv", uses: "astral-sh/setup-uv@v7" }] : []),
|
|
1243
1301
|
{
|
|
1244
1302
|
name: "Setup Rust",
|
|
@@ -1280,9 +1338,16 @@ function rustBuildJob(plan: RustReleasePlan): Job {
|
|
|
1280
1338
|
},
|
|
1281
1339
|
run: timedBash(
|
|
1282
1340
|
"rust_workspace",
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1341
|
+
independentSetup
|
|
1342
|
+
? [
|
|
1343
|
+
"mapfile -t PACKAGES < <(jq -r '.[]' <<<'${{ toJSON(matrix.packages) }}')",
|
|
1344
|
+
"PACKAGE_ARGS=()",
|
|
1345
|
+
'for PACKAGE in "${PACKAGES[@]}"; do PACKAGE_ARGS+=(--package "$PACKAGE"); done',
|
|
1346
|
+
`cargo build --release "\${PACKAGE_ARGS[@]}"${plan.usesCargoLock ? " --locked" : ""} --target "\${{ matrix.cargo }}"`,
|
|
1347
|
+
].join("\n")
|
|
1348
|
+
: `cargo build --release --workspace${plan.usesCargoLock ? " --locked" : ""} --target "\${{ matrix.cargo }}"${
|
|
1349
|
+
plan.hasReleaseExclusions ? " ${{ matrix.cargoExcludes }}" : ""
|
|
1350
|
+
}`,
|
|
1286
1351
|
),
|
|
1287
1352
|
},
|
|
1288
1353
|
...(bindingCommands.length
|
|
@@ -1290,7 +1355,7 @@ function rustBuildJob(plan: RustReleasePlan): Job {
|
|
|
1290
1355
|
{
|
|
1291
1356
|
name: "Package UniFFI outputs",
|
|
1292
1357
|
shell: "bash",
|
|
1293
|
-
env: { VERSION: RELEASE_VERSION },
|
|
1358
|
+
...(independentSetup ? {} : { env: { VERSION: RELEASE_VERSION } }),
|
|
1294
1359
|
run: timedBash("uniffi_packaging", bindingCommands.join("\n")),
|
|
1295
1360
|
},
|
|
1296
1361
|
]
|
|
@@ -1339,6 +1404,86 @@ function rustCargoPublishJob(plan: RustReleasePlan, local: boolean): Job {
|
|
|
1339
1404
|
};
|
|
1340
1405
|
}
|
|
1341
1406
|
|
|
1407
|
+
function independentRustCargoPublishJob(
|
|
1408
|
+
project: DBXToolsJavaScriptProject,
|
|
1409
|
+
plan: RustReleasePlan,
|
|
1410
|
+
): Job {
|
|
1411
|
+
const commands = plan.publicCrates.map((crate) =>
|
|
1412
|
+
[
|
|
1413
|
+
`VERSION="$(jq -r --arg package "${crate}" '.rustPackages[] | select(.identity == $package) | .version' dist/release-plan.json)"`,
|
|
1414
|
+
'if [ -n "$VERSION" ]; then',
|
|
1415
|
+
` if cargo info "${crate}@$VERSION" >/dev/null 2>&1; then`,
|
|
1416
|
+
` echo "skip published ${crate}@$VERSION"`,
|
|
1417
|
+
" else",
|
|
1418
|
+
` cargo publish --package "${crate}" --registry crates-io --no-verify`,
|
|
1419
|
+
" fi",
|
|
1420
|
+
"fi",
|
|
1421
|
+
].join("\n"),
|
|
1422
|
+
);
|
|
1423
|
+
return {
|
|
1424
|
+
if: plan.hasTargetOutputs
|
|
1425
|
+
? "${{ always() && needs.release-plan.outputs.rust == 'true' && needs.rust-build.result != 'failure' && needs.rust-build.result != 'cancelled' && (github.event_name == 'push' || inputs.stage == 'all' || inputs.stage == 'rust') }}"
|
|
1426
|
+
: "${{ needs.release-plan.outputs.rust == 'true' && (github.event_name == 'push' || inputs.stage == 'all' || inputs.stage == 'rust') }}",
|
|
1427
|
+
needs: ["release-plan", ...(plan.hasTargetOutputs ? ["rust-build"] : [])],
|
|
1428
|
+
runsOn: ["ubuntu-latest"],
|
|
1429
|
+
permissions: { contents: JobPermission.READ },
|
|
1430
|
+
env: { BUN_VERSION },
|
|
1431
|
+
steps: [
|
|
1432
|
+
...independentReleaseSetupSteps(project),
|
|
1433
|
+
{
|
|
1434
|
+
name: "Setup Rust",
|
|
1435
|
+
uses: `dtolnay/rust-toolchain@${plan.releaseRustVersion}`,
|
|
1436
|
+
},
|
|
1437
|
+
{
|
|
1438
|
+
name: "Publish affected Cargo crates",
|
|
1439
|
+
env: { CARGO_REGISTRY_TOKEN: "${{ secrets.CARGO_REGISTRY_TOKEN }}" },
|
|
1440
|
+
run: commands.join("\n"),
|
|
1441
|
+
},
|
|
1442
|
+
],
|
|
1443
|
+
};
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
function independentRustGitHubReleaseJob(
|
|
1447
|
+
project: DBXToolsJavaScriptProject,
|
|
1448
|
+
plan: RustReleasePlan,
|
|
1449
|
+
): Job {
|
|
1450
|
+
return {
|
|
1451
|
+
if: "${{ needs.release-plan.outputs.github == 'true' && (github.event_name == 'push' || inputs.stage == 'all' || inputs.stage == 'github') }}",
|
|
1452
|
+
needs: ["release-plan", "rust-build"],
|
|
1453
|
+
runsOn: ["ubuntu-latest"],
|
|
1454
|
+
permissions: { contents: JobPermission.WRITE },
|
|
1455
|
+
env: { BUN_VERSION },
|
|
1456
|
+
steps: [
|
|
1457
|
+
...independentReleaseSetupSteps(project),
|
|
1458
|
+
{
|
|
1459
|
+
name: "Download release binaries",
|
|
1460
|
+
uses: "actions/download-artifact@v8",
|
|
1461
|
+
with: {
|
|
1462
|
+
pattern: "*-binary",
|
|
1463
|
+
path: "dist/rust-release",
|
|
1464
|
+
"merge-multiple": true,
|
|
1465
|
+
},
|
|
1466
|
+
},
|
|
1467
|
+
{
|
|
1468
|
+
name: "Upload affected GitHub release assets",
|
|
1469
|
+
env: { GH_TOKEN: "${{ github.token }}" },
|
|
1470
|
+
shell: "bash",
|
|
1471
|
+
run: plan.releaseBinaries
|
|
1472
|
+
.map((binary) => {
|
|
1473
|
+
const unit = defaultReleaseUnitId("rust", binary.crate);
|
|
1474
|
+
return [
|
|
1475
|
+
`VERSION="$(jq -r --arg unit "${unit}" '.units[] | select(.id == $unit) | .newVersion' dist/release-plan.json)"`,
|
|
1476
|
+
'if [ -n "$VERSION" ]; then',
|
|
1477
|
+
` gh release upload "${unit}-v$VERSION" dist/rust-release/${binary.binary}-* --clobber`,
|
|
1478
|
+
"fi",
|
|
1479
|
+
].join("\n");
|
|
1480
|
+
})
|
|
1481
|
+
.join("\n"),
|
|
1482
|
+
},
|
|
1483
|
+
],
|
|
1484
|
+
};
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1342
1487
|
function rustGitHubReleaseJob(): Job {
|
|
1343
1488
|
return {
|
|
1344
1489
|
if: "${{ github.event_name == 'push' }}",
|
|
@@ -1371,6 +1516,70 @@ function rustGitHubReleaseJob(): Job {
|
|
|
1371
1516
|
};
|
|
1372
1517
|
}
|
|
1373
1518
|
|
|
1519
|
+
function independentRustNativeNpmPublishJob(project: DBXToolsJavaScriptProject): Job {
|
|
1520
|
+
return {
|
|
1521
|
+
if: "${{ needs.release-plan.outputs.node == 'true' && (github.event_name == 'push' || inputs.stage == 'all' || inputs.stage == 'node') }}",
|
|
1522
|
+
needs: ["release-plan", "rust-build"],
|
|
1523
|
+
runsOn: ["ubuntu-latest"],
|
|
1524
|
+
permissions: { contents: JobPermission.READ, idToken: JobPermission.WRITE },
|
|
1525
|
+
timeoutMinutes: 15,
|
|
1526
|
+
env: { BUN_VERSION, CI: "true" },
|
|
1527
|
+
steps: [
|
|
1528
|
+
...independentReleaseSetupSteps(project),
|
|
1529
|
+
{
|
|
1530
|
+
name: "Download native npm packages",
|
|
1531
|
+
uses: "actions/download-artifact@v8",
|
|
1532
|
+
with: {
|
|
1533
|
+
pattern: "*-npm",
|
|
1534
|
+
path: "dist/uniffi/native",
|
|
1535
|
+
"merge-multiple": true,
|
|
1536
|
+
},
|
|
1537
|
+
},
|
|
1538
|
+
{
|
|
1539
|
+
name: "Publish affected native npm packages",
|
|
1540
|
+
env: npmPublishEnvironment(),
|
|
1541
|
+
run: "bun node_modules/@dbx-tools/projen/tasks/publish-npm.ts --directory dist/uniffi/native",
|
|
1542
|
+
},
|
|
1543
|
+
],
|
|
1544
|
+
};
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
function independentRustNodeFacadePublishJob(
|
|
1548
|
+
project: DBXToolsJavaScriptProject,
|
|
1549
|
+
bindings: readonly RustBindingMapping[],
|
|
1550
|
+
): Job {
|
|
1551
|
+
return {
|
|
1552
|
+
if: "${{ needs.release-plan.outputs.node == 'true' && (github.event_name == 'push' || inputs.stage == 'all' || inputs.stage == 'node') }}",
|
|
1553
|
+
needs: ["release-plan", "publish-node", "publish-native-npm"],
|
|
1554
|
+
runsOn: ["ubuntu-latest"],
|
|
1555
|
+
permissions: { contents: JobPermission.READ, idToken: JobPermission.WRITE },
|
|
1556
|
+
timeoutMinutes: 30,
|
|
1557
|
+
env: { BUN_VERSION, CI: "true" },
|
|
1558
|
+
steps: [
|
|
1559
|
+
...independentReleaseSetupSteps(project),
|
|
1560
|
+
{
|
|
1561
|
+
name: "Build and publish affected UniFFI npm facades",
|
|
1562
|
+
env: npmPublishEnvironment(),
|
|
1563
|
+
shell: "bash",
|
|
1564
|
+
run: bindings
|
|
1565
|
+
.flatMap((binding) => {
|
|
1566
|
+
if (!binding.node || !binding.nodePackage) return [];
|
|
1567
|
+
const unit = defaultReleaseUnitId("rust", binding.crate);
|
|
1568
|
+
const output = `dist/uniffi/facades/${binding.crate}`;
|
|
1569
|
+
return [
|
|
1570
|
+
`VERSION="$(jq -r --arg unit "${unit}" '.units[] | select(.id == $unit) | .newVersion' dist/release-plan.json)"`,
|
|
1571
|
+
'if [ -n "$VERSION" ]; then',
|
|
1572
|
+
` node .projen/uniffi-release.mjs facade --node "${binding.node}" --node-package "${binding.nodePackage}" --node-triple "linux-x64-gnu" --version "$VERSION" --output "${output}"`,
|
|
1573
|
+
` bun node_modules/@dbx-tools/projen/tasks/publish-npm.ts --directory "${output}/npm-facade" --version "$VERSION"`,
|
|
1574
|
+
"fi",
|
|
1575
|
+
];
|
|
1576
|
+
})
|
|
1577
|
+
.join("\n"),
|
|
1578
|
+
},
|
|
1579
|
+
],
|
|
1580
|
+
};
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1374
1583
|
function rustNativeNpmPublishJob(project: DBXToolsJavaScriptProject): Job {
|
|
1375
1584
|
return {
|
|
1376
1585
|
if: "${{ always() && needs.verify-context.result == 'success' && needs.rust-build.result != 'failure' && needs.rust-build.result != 'cancelled' && (github.event_name == 'push' || inputs.stage == 'all' || inputs.stage == 'node') }}",
|
|
@@ -1446,6 +1655,60 @@ function rustNodeFacadePublishJob(
|
|
|
1446
1655
|
};
|
|
1447
1656
|
}
|
|
1448
1657
|
|
|
1658
|
+
function rustReleaseDependencies(
|
|
1659
|
+
root: DBXToolsJavaScriptProject,
|
|
1660
|
+
project: DBXToolsRustProject,
|
|
1661
|
+
packages: readonly DBXToolsRustProject[],
|
|
1662
|
+
dependencies: Readonly<Record<string, CargoDependency>> | undefined,
|
|
1663
|
+
development: boolean,
|
|
1664
|
+
): ReleaseDependencyInput[] {
|
|
1665
|
+
return Object.values(dependencies ?? {}).flatMap((dependency) => {
|
|
1666
|
+
if (typeof dependency === "string" || !dependency.path) return [];
|
|
1667
|
+
const dependencyPath = resolve(project.outdir, dependency.path);
|
|
1668
|
+
const target = packages.find((candidate) => resolve(candidate.outdir) === dependencyPath);
|
|
1669
|
+
if (!target) return [];
|
|
1670
|
+
const configuredRequirement = dependency.version;
|
|
1671
|
+
const requirement = configuredRequirement
|
|
1672
|
+
? /^[0-9]/.test(configuredRequirement)
|
|
1673
|
+
? `^${configuredRequirement}`
|
|
1674
|
+
: configuredRequirement
|
|
1675
|
+
: `^${root.releaseCatalog.versionFor(target)}`;
|
|
1676
|
+
return [
|
|
1677
|
+
{
|
|
1678
|
+
target: target.crateName,
|
|
1679
|
+
kind: development ? ("development" as const) : ("runtime" as const),
|
|
1680
|
+
requirement,
|
|
1681
|
+
propagation: development ? ("never" as const) : ("outside-range" as const),
|
|
1682
|
+
publishOrder: !development,
|
|
1683
|
+
internal: true,
|
|
1684
|
+
},
|
|
1685
|
+
];
|
|
1686
|
+
});
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1689
|
+
function configureIndependentRustVersions(
|
|
1690
|
+
project: DBXToolsJavaScriptProject,
|
|
1691
|
+
packages: readonly DBXToolsRustProject[],
|
|
1692
|
+
): void {
|
|
1693
|
+
for (const pkg of packages) {
|
|
1694
|
+
for (const [section, dependencies] of [
|
|
1695
|
+
["dependencies", pkg.packageOptions.dependencies],
|
|
1696
|
+
["dev-dependencies", pkg.packageOptions.devDependencies],
|
|
1697
|
+
] as const) {
|
|
1698
|
+
for (const [name, dependency] of Object.entries(dependencies ?? {})) {
|
|
1699
|
+
if (typeof dependency === "string" || !dependency.path) continue;
|
|
1700
|
+
const dependencyPath = resolve(pkg.outdir, dependency.path);
|
|
1701
|
+
const target = packages.find((candidate) => resolve(candidate.outdir) === dependencyPath);
|
|
1702
|
+
if (!target) continue;
|
|
1703
|
+
pkg.manifestFile.addOverride(
|
|
1704
|
+
`${section}.${name}.version`,
|
|
1705
|
+
project.releaseCatalog.versionFor(target),
|
|
1706
|
+
);
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1449
1712
|
/** Generated Rust workspace plus convention-derived UniFFI binding packages. */
|
|
1450
1713
|
export class DBXToolsRustWorkspace {
|
|
1451
1714
|
readonly packages: readonly DBXToolsRustProject[];
|
|
@@ -1463,8 +1726,52 @@ export class DBXToolsRustWorkspace {
|
|
|
1463
1726
|
project,
|
|
1464
1727
|
options,
|
|
1465
1728
|
);
|
|
1466
|
-
|
|
1729
|
+
if (isDBXToolsJavaScriptProject()(project)) {
|
|
1730
|
+
for (const pkg of this.packages) {
|
|
1731
|
+
project.releaseCatalog.registerProject(pkg, {
|
|
1732
|
+
language: "rust",
|
|
1733
|
+
identity: pkg.crateName,
|
|
1734
|
+
publish: !pkg.packageOptions.private || pkg.packageOptions.release === true,
|
|
1735
|
+
sourcePaths: [`${relative(project.outdir, pkg.outdir).replaceAll("\\", "/")}/src`],
|
|
1736
|
+
dependencies: [
|
|
1737
|
+
...rustReleaseDependencies(
|
|
1738
|
+
project,
|
|
1739
|
+
pkg,
|
|
1740
|
+
this.packages,
|
|
1741
|
+
pkg.packageOptions.dependencies,
|
|
1742
|
+
false,
|
|
1743
|
+
),
|
|
1744
|
+
...rustReleaseDependencies(
|
|
1745
|
+
project,
|
|
1746
|
+
pkg,
|
|
1747
|
+
this.packages,
|
|
1748
|
+
pkg.packageOptions.devDependencies,
|
|
1749
|
+
true,
|
|
1750
|
+
),
|
|
1751
|
+
],
|
|
1752
|
+
});
|
|
1753
|
+
}
|
|
1754
|
+
if (project.releaseCatalog.mode === "independent") {
|
|
1755
|
+
configureIndependentRustVersions(project, this.packages);
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
this.releaseBinaries = planRustReleaseBinaries(project, this.packages, resolved);
|
|
1467
1759
|
configureRustCliRegistry(project, options.cliRegistryPath, this.releaseBinaries);
|
|
1760
|
+
if (isDBXToolsJavaScriptProject()(project)) {
|
|
1761
|
+
for (const binary of this.releaseBinaries) {
|
|
1762
|
+
project.releaseCatalog.registerArtifact(binary.unit, {
|
|
1763
|
+
id: `${binary.unit}:github-binary`,
|
|
1764
|
+
kind: "github-binary",
|
|
1765
|
+
name: binary.binaryName,
|
|
1766
|
+
generated: true,
|
|
1767
|
+
data: {
|
|
1768
|
+
targets: resolved.nativeTargets.filter((target) =>
|
|
1769
|
+
binary.assets.some((asset) => asset.os === target.os && asset.cpu === target.cpu),
|
|
1770
|
+
),
|
|
1771
|
+
},
|
|
1772
|
+
});
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1468
1775
|
|
|
1469
1776
|
const bindingPlan = planRustBindings(this.packages, packageDependencies, resolved);
|
|
1470
1777
|
validateRustReleaseGraph(this.packages, packageDependencies);
|
|
@@ -1489,6 +1796,43 @@ export class DBXToolsRustWorkspace {
|
|
|
1489
1796
|
project,
|
|
1490
1797
|
planNodeBindingPackages(project, bindingPlan, resolved),
|
|
1491
1798
|
);
|
|
1799
|
+
if (isDBXToolsJavaScriptProject()(project)) {
|
|
1800
|
+
for (const mapping of this.bindingMappings) {
|
|
1801
|
+
const unit = defaultReleaseUnitId("rust", mapping.crate);
|
|
1802
|
+
project.releaseCatalog.addUnit({
|
|
1803
|
+
id: unit,
|
|
1804
|
+
projectPaths: [mapping.rust, mapping.node, mapping.python].filter(
|
|
1805
|
+
(path): path is string => Boolean(path),
|
|
1806
|
+
),
|
|
1807
|
+
});
|
|
1808
|
+
if (mapping.nodePackage) {
|
|
1809
|
+
project.releaseCatalog.registerArtifact(unit, {
|
|
1810
|
+
id: `${unit}:npm-facade`,
|
|
1811
|
+
kind: "npm",
|
|
1812
|
+
name: mapping.nodePackage,
|
|
1813
|
+
path: mapping.node,
|
|
1814
|
+
generated: true,
|
|
1815
|
+
});
|
|
1816
|
+
project.releaseCatalog.registerArtifact(unit, {
|
|
1817
|
+
id: `${unit}:npm-native`,
|
|
1818
|
+
kind: "npm",
|
|
1819
|
+
name: `${mapping.nodePackage}-native`,
|
|
1820
|
+
generated: true,
|
|
1821
|
+
data: { targets: resolved.nativeTargets },
|
|
1822
|
+
});
|
|
1823
|
+
}
|
|
1824
|
+
if (mapping.pythonPackage) {
|
|
1825
|
+
project.releaseCatalog.registerArtifact(unit, {
|
|
1826
|
+
id: `${unit}:python-wheel`,
|
|
1827
|
+
kind: "pypi",
|
|
1828
|
+
name: mapping.pythonPackage,
|
|
1829
|
+
path: mapping.python,
|
|
1830
|
+
generated: true,
|
|
1831
|
+
data: { targets: resolved.nativeTargets },
|
|
1832
|
+
});
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1492
1836
|
configureRustWorkspaceFiles(project, this.packages, options, resolved);
|
|
1493
1837
|
configureRustWorkspaceTasks(project);
|
|
1494
1838
|
if (releaseEnabled) {
|
|
@@ -1508,6 +1852,29 @@ export class DBXToolsRustWorkspace {
|
|
|
1508
1852
|
throw new Error("Rust release requires the root dbx-tools release mode");
|
|
1509
1853
|
}
|
|
1510
1854
|
configureRustReleaseTask(project, plan);
|
|
1855
|
+
if (project.releaseCatalog.mode === "independent") {
|
|
1856
|
+
if (plan.hasTargetOutputs && plan.targets.length) {
|
|
1857
|
+
workflow.addJob("rust-build", rustBuildJob(plan, independentReleaseSetupSteps(project)));
|
|
1858
|
+
}
|
|
1859
|
+
if (plan.publicCrates.length) {
|
|
1860
|
+
workflow.addJob("publish-cargo", independentRustCargoPublishJob(project, plan));
|
|
1861
|
+
registerIndependentPublicationJob(workflow, "publish-cargo");
|
|
1862
|
+
}
|
|
1863
|
+
if (plan.releaseBinaries.length) {
|
|
1864
|
+
workflow.addJob("publish-github-release", independentRustGitHubReleaseJob(project, plan));
|
|
1865
|
+
registerIndependentPublicationJob(workflow, "publish-github-release");
|
|
1866
|
+
}
|
|
1867
|
+
if (plan.nodeBindings.length && hasNodeRelease(project)) {
|
|
1868
|
+
workflow.addJob("publish-native-npm", independentRustNativeNpmPublishJob(project));
|
|
1869
|
+
registerIndependentPublicationJob(workflow, "publish-native-npm");
|
|
1870
|
+
workflow.addJob(
|
|
1871
|
+
"publish-node-facades",
|
|
1872
|
+
independentRustNodeFacadePublishJob(project, plan.nodeBindings),
|
|
1873
|
+
);
|
|
1874
|
+
registerIndependentPublicationJob(workflow, "publish-node-facades");
|
|
1875
|
+
}
|
|
1876
|
+
return;
|
|
1877
|
+
}
|
|
1511
1878
|
if (plan.hasTargetOutputs && plan.targets.length) {
|
|
1512
1879
|
workflow.addJob("rust-build", rustBuildJob(plan));
|
|
1513
1880
|
}
|