@dbx-tools/projen 0.6.152 → 0.6.158
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 +80 -37
- package/index.ts +2 -0
- package/package.json +4 -4
- package/src/pnpm-workspace.ts +8 -1
- package/src/project-js.ts +67 -7
- package/src/project-py.ts +221 -42
- package/src/project-rs.ts +412 -98
- package/src/release-dispatch.ts +36 -0
- package/src/release.ts +187 -17
- package/tasks/bump.ts +21 -3
- package/tasks/uniffi-release.mjs +16 -24
- package/tasks/uniffi.ts +2 -1
package/src/project-rs.ts
CHANGED
|
@@ -2,11 +2,23 @@
|
|
|
2
2
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
3
3
|
import { dirname, join, relative, resolve } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { project as coreProject } from "@dbx-tools/core";
|
|
5
6
|
import { string } from "@dbx-tools/shared-core";
|
|
6
7
|
import { Project, TextFile, YamlFile, javascript } from "projen";
|
|
7
8
|
import type { DBXToolsProject } from "./project.ts";
|
|
8
|
-
import {
|
|
9
|
-
|
|
9
|
+
import {
|
|
10
|
+
DBXToolsTypeScriptProject,
|
|
11
|
+
projectReleaseBranch,
|
|
12
|
+
projectRepositoryUrl,
|
|
13
|
+
} from "./project-js.ts";
|
|
14
|
+
import { pythonModuleName, type PythonPackageOptions } from "./project-py.ts";
|
|
15
|
+
import {
|
|
16
|
+
DOWNSTREAM_RELEASE_EVENT,
|
|
17
|
+
RELEASE_SHA,
|
|
18
|
+
RELEASE_TAG,
|
|
19
|
+
RUST_RELEASE_EVENT,
|
|
20
|
+
releaseSourceSteps,
|
|
21
|
+
} from "./release-dispatch.ts";
|
|
10
22
|
import { readWorkspaceVersion } from "./workspace-version.ts";
|
|
11
23
|
import { isDBXToolsJavaScriptProject } from "./project-predicate.ts";
|
|
12
24
|
|
|
@@ -42,9 +54,14 @@ export interface RustPackageOptions {
|
|
|
42
54
|
|
|
43
55
|
export interface DBXToolsRustWorkspaceOptions {
|
|
44
56
|
readonly root?: string;
|
|
45
|
-
readonly scope
|
|
57
|
+
readonly scope?: string;
|
|
46
58
|
readonly edition?: string;
|
|
59
|
+
/** Minimum supported Rust version recorded in Cargo manifests. */
|
|
47
60
|
readonly rustVersion?: string;
|
|
61
|
+
/** Rust toolchain used by release builds. Defaults to `stable`. */
|
|
62
|
+
readonly releaseRustVersion?: string;
|
|
63
|
+
/** Rust toolchain used to compile the host-side UBRN generator. Defaults to releaseRustVersion. */
|
|
64
|
+
readonly ubrnRustVersion?: string;
|
|
48
65
|
readonly license?: string;
|
|
49
66
|
readonly repository?: string;
|
|
50
67
|
readonly workspaceDependencies?: Readonly<Record<string, CargoDependency>>;
|
|
@@ -61,6 +78,8 @@ export interface DBXToolsRustWorkspaceOptions {
|
|
|
61
78
|
readonly releasePlatforms?: readonly RustReleasePlatform[];
|
|
62
79
|
/** Workflow name used by downstream release stages. Defaults to `rust-release`. */
|
|
63
80
|
readonly releaseWorkflowName?: string;
|
|
81
|
+
/** Tag prefix dispatched into the branch-scoped release workflow. Defaults to `v`. */
|
|
82
|
+
readonly releaseTagPrefix?: string;
|
|
64
83
|
}
|
|
65
84
|
|
|
66
85
|
export enum RustReleaseOs {
|
|
@@ -139,12 +158,19 @@ const RUST_CACHE_ENV = {
|
|
|
139
158
|
RUSTC_WRAPPER: "sccache",
|
|
140
159
|
SCCACHE_GHA_ENABLED: "true",
|
|
141
160
|
} as const;
|
|
161
|
+
const UBRN_VERSION = "0.31.0-5";
|
|
162
|
+
const RELEASE_PLATFORMS_ENV = "DBX_TOOLS_RELEASE_PLATFORMS";
|
|
142
163
|
|
|
143
|
-
function rustCacheSteps(sharedKey: string): readonly Record<string, unknown>[] {
|
|
164
|
+
function rustCacheSteps(sharedKey: string, idPrefix = ""): readonly Record<string, unknown>[] {
|
|
144
165
|
return [
|
|
145
|
-
{
|
|
166
|
+
{
|
|
167
|
+
name: "Setup sccache",
|
|
168
|
+
id: `${idPrefix}sccache`,
|
|
169
|
+
uses: "mozilla-actions/sccache-action@v0.0.11",
|
|
170
|
+
},
|
|
146
171
|
{
|
|
147
172
|
name: "Cache Cargo registry",
|
|
173
|
+
id: `${idPrefix}cargo_cache`,
|
|
148
174
|
uses: "Swatinem/rust-cache@v2.9.2",
|
|
149
175
|
with: {
|
|
150
176
|
"cache-targets": false,
|
|
@@ -156,13 +182,23 @@ function rustCacheSteps(sharedKey: string): readonly Record<string, unknown>[] {
|
|
|
156
182
|
];
|
|
157
183
|
}
|
|
158
184
|
|
|
185
|
+
function timedBash(phase: string, command: string): string {
|
|
186
|
+
return [
|
|
187
|
+
"SECONDS=0",
|
|
188
|
+
`trap 'status=$?; echo "phase=${phase} duration_seconds=$SECONDS status=$status"; exit "$status"' EXIT`,
|
|
189
|
+
command,
|
|
190
|
+
].join("\n");
|
|
191
|
+
}
|
|
192
|
+
|
|
159
193
|
function releaseTargets(options: DBXToolsRustWorkspaceOptions): readonly UniFFIReleaseTarget[] {
|
|
160
194
|
if (options.releaseTargets && options.releasePlatforms) {
|
|
161
195
|
throw new Error("releaseTargets and releasePlatforms are mutually exclusive");
|
|
162
196
|
}
|
|
163
197
|
if (options.releaseTargets) return options.releaseTargets;
|
|
164
|
-
|
|
165
|
-
|
|
198
|
+
const releasePlatforms =
|
|
199
|
+
options.releasePlatforms ?? releasePlatformsFromEnvironment(process.env[RELEASE_PLATFORMS_ENV]);
|
|
200
|
+
if (!releasePlatforms) return UNIFFI_RELEASE_TARGETS;
|
|
201
|
+
return releasePlatforms.map((platform) => {
|
|
166
202
|
const target = UNIFFI_RELEASE_TARGETS.find(
|
|
167
203
|
(candidate) => candidate.os === platform.os && candidate.cpu === platform.cpu,
|
|
168
204
|
);
|
|
@@ -172,6 +208,23 @@ function releaseTargets(options: DBXToolsRustWorkspaceOptions): readonly UniFFIR
|
|
|
172
208
|
});
|
|
173
209
|
}
|
|
174
210
|
|
|
211
|
+
function releasePlatformsFromEnvironment(
|
|
212
|
+
value: string | undefined,
|
|
213
|
+
): RustReleasePlatform[] | undefined {
|
|
214
|
+
if (!value?.trim()) return undefined;
|
|
215
|
+
return value.split(",").map((entry) => {
|
|
216
|
+
const [os, cpu, ...extra] = entry.split(":").map((part) => part.trim());
|
|
217
|
+
if (
|
|
218
|
+
extra.length ||
|
|
219
|
+
!Object.values(RustReleaseOs).includes(os as RustReleaseOs) ||
|
|
220
|
+
!Object.values(RustReleaseCpu).includes(cpu as RustReleaseCpu)
|
|
221
|
+
) {
|
|
222
|
+
throw new Error(`Invalid ${RELEASE_PLATFORMS_ENV} entry: ${entry}`);
|
|
223
|
+
}
|
|
224
|
+
return { os: os as RustReleaseOs, cpu: cpu as RustReleaseCpu };
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
175
228
|
function uniffiReleaseTaskSource(): string {
|
|
176
229
|
const sourceDirectory = dirname(fileURLToPath(import.meta.url));
|
|
177
230
|
const candidates = [
|
|
@@ -191,6 +244,7 @@ export interface RustBindingMapping {
|
|
|
191
244
|
readonly python?: string;
|
|
192
245
|
readonly nodePackage?: string;
|
|
193
246
|
readonly pythonPackage?: string;
|
|
247
|
+
readonly pythonModule?: string;
|
|
194
248
|
readonly facadeTarget?: boolean;
|
|
195
249
|
}
|
|
196
250
|
|
|
@@ -199,6 +253,7 @@ export interface RustWorkspaceMapping {
|
|
|
199
253
|
readonly root: string;
|
|
200
254
|
readonly crates: readonly string[];
|
|
201
255
|
readonly bindings: readonly RustBindingMapping[];
|
|
256
|
+
readonly releaseWorkflow?: string;
|
|
202
257
|
}
|
|
203
258
|
|
|
204
259
|
function rustSources(directory: string): string[] {
|
|
@@ -373,10 +428,18 @@ export class DBXToolsRustWorkspace {
|
|
|
373
428
|
constructor(project: javascript.NodeProject, options: DBXToolsRustWorkspaceOptions) {
|
|
374
429
|
const root = options.root ?? "packages/rs";
|
|
375
430
|
const nodeRoot = options.nodeRoot ?? "packages/js/node";
|
|
431
|
+
const dbxToolsProject = isDBXToolsJavaScriptProject()(project) ? project : undefined;
|
|
432
|
+
const scope = string.toSlug(options.scope ?? dbxToolsProject?.scope ?? project.name);
|
|
433
|
+
const repository =
|
|
434
|
+
options.repository ??
|
|
435
|
+
projectRepositoryUrl(project) ??
|
|
436
|
+
coreProject.repositoryUrl(project.outdir) ??
|
|
437
|
+
"";
|
|
438
|
+
const pythonModulePrefix = options.pythonModulePrefix ?? scope.replaceAll("-", "_");
|
|
376
439
|
const packageOptions = options.packages ?? {};
|
|
377
440
|
this.packages = discoverRustCrates(resolve(project.outdir, root)).map(
|
|
378
441
|
(directory) =>
|
|
379
|
-
new DBXToolsRustProject(project, root,
|
|
442
|
+
new DBXToolsRustProject(project, root, scope, {
|
|
380
443
|
directory,
|
|
381
444
|
...packageOptions[directory],
|
|
382
445
|
}),
|
|
@@ -392,44 +455,69 @@ export class DBXToolsRustWorkspace {
|
|
|
392
455
|
...(targets.includes("node")
|
|
393
456
|
? {
|
|
394
457
|
node: `${nodeRoot}/${pkg.packageOptions.directory}`,
|
|
395
|
-
nodePackage: `@${
|
|
458
|
+
nodePackage: `@${scope}/${packageName}`,
|
|
396
459
|
}
|
|
397
460
|
: {}),
|
|
398
461
|
...(targets.includes("python")
|
|
399
462
|
? {
|
|
400
463
|
python: `${options.pythonRoot ?? "packages/py"}/${pkg.packageOptions.directory}`,
|
|
401
464
|
pythonPackage: pkg.crateName,
|
|
465
|
+
pythonModule: pythonModuleName(pythonModulePrefix, pkg.packageOptions.directory),
|
|
402
466
|
}
|
|
403
467
|
: {}),
|
|
404
468
|
};
|
|
405
469
|
});
|
|
470
|
+
const releaseEnabled =
|
|
471
|
+
(options.release ?? true) &&
|
|
472
|
+
(this.bindingMappings.length > 0 ||
|
|
473
|
+
this.packages.some((pkg) => pkg.packageOptions.release || !pkg.packageOptions.private));
|
|
406
474
|
this.workspaceMapping = {
|
|
407
475
|
root,
|
|
408
476
|
crates: this.packages.map((pkg) => `${root}/${pkg.packageOptions.directory}`),
|
|
409
477
|
bindings: this.bindingMappings,
|
|
478
|
+
...(releaseEnabled ? { releaseWorkflow: options.releaseWorkflowName ?? "rust-release" } : {}),
|
|
410
479
|
};
|
|
411
|
-
if (
|
|
412
|
-
|
|
480
|
+
if (dbxToolsProject) {
|
|
481
|
+
dbxToolsProject.dbxToolsConfig.rust = this.workspaceMapping;
|
|
413
482
|
}
|
|
483
|
+
project.gitignore.addPatterns(
|
|
484
|
+
"target/",
|
|
485
|
+
...this.bindingMappings.flatMap((binding) => [
|
|
486
|
+
...(binding.node
|
|
487
|
+
? [
|
|
488
|
+
`${binding.node}/src/bindings.ts`,
|
|
489
|
+
`${binding.node}/src/_bindings*.ts`,
|
|
490
|
+
`${binding.node}/src/*${binding.crate.replaceAll("-", "_")}.*`,
|
|
491
|
+
]
|
|
492
|
+
: []),
|
|
493
|
+
...(binding.python && binding.pythonModule
|
|
494
|
+
? [
|
|
495
|
+
`${binding.python}/src/${binding.pythonModule.replaceAll(".", "/")}/bindings.py`,
|
|
496
|
+
`${binding.python}/src/${binding.pythonModule.replaceAll(".", "/")}/*${binding.crate.replaceAll("-", "_")}.*`,
|
|
497
|
+
]
|
|
498
|
+
: []),
|
|
499
|
+
]),
|
|
500
|
+
);
|
|
414
501
|
this.pythonPackages = bindings
|
|
415
502
|
.filter((pkg) => (pkg.packageOptions.bindings ?? ["node", "python"]).includes("python"))
|
|
416
|
-
.map((pkg) =>
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
503
|
+
.map((pkg) => {
|
|
504
|
+
const module = pythonModuleName(pythonModulePrefix, pkg.packageOptions.directory);
|
|
505
|
+
return {
|
|
506
|
+
directory: pkg.packageOptions.directory,
|
|
507
|
+
name: pkg.crateName,
|
|
508
|
+
module,
|
|
509
|
+
description: `Python bindings for ${pkg.crateName}`,
|
|
510
|
+
private: true,
|
|
511
|
+
generatedSources: [`src/${module.replaceAll(".", "/")}/bindings.py`],
|
|
512
|
+
trustedPublisher: {
|
|
513
|
+
workflowName: options.releaseWorkflowName ?? "rust-release",
|
|
514
|
+
environment: `pypi-${pkg.crateName}`,
|
|
515
|
+
artifacts: `platform-specific wheels for ${releaseTargets(options)
|
|
516
|
+
.map((target) => `${target.os}-${target.cpu}`)
|
|
517
|
+
.join(", ")}; all architectures publish to this one PyPI project`,
|
|
518
|
+
},
|
|
519
|
+
};
|
|
520
|
+
});
|
|
433
521
|
|
|
434
522
|
const existing = new Map(
|
|
435
523
|
project.subprojects.map((child) => [relative(project.outdir, child.outdir), child]),
|
|
@@ -447,12 +535,12 @@ export class DBXToolsRustWorkspace {
|
|
|
447
535
|
: new DBXToolsTypeScriptProject({
|
|
448
536
|
parent: project,
|
|
449
537
|
outdir: memberPath,
|
|
450
|
-
name: `@${
|
|
538
|
+
name: `@${scope}/${directory.toLowerCase().replace(/[^a-z0-9-]+/g, "-")}`,
|
|
451
539
|
tags: ["node"],
|
|
452
540
|
});
|
|
453
541
|
node.package.addField(
|
|
454
542
|
"name",
|
|
455
|
-
`@${
|
|
543
|
+
`@${scope}/${directory.toLowerCase().replace(/[^a-z0-9-]+/g, "-")}`,
|
|
456
544
|
);
|
|
457
545
|
node.package.addField("private", true);
|
|
458
546
|
node.package.file.addDeletionOverride("publishConfig");
|
|
@@ -463,7 +551,7 @@ export class DBXToolsRustWorkspace {
|
|
|
463
551
|
"optionalDependencies",
|
|
464
552
|
Object.fromEntries(
|
|
465
553
|
nativeTargets.map((target) => [
|
|
466
|
-
`@${
|
|
554
|
+
`@${scope}/${directory}-${target.node}`,
|
|
467
555
|
readWorkspaceVersion(project.outdir),
|
|
468
556
|
]),
|
|
469
557
|
),
|
|
@@ -473,7 +561,7 @@ export class DBXToolsRustWorkspace {
|
|
|
473
561
|
if (binding.packageOptions.nodeDependencies?.length) {
|
|
474
562
|
node.addDeps(...binding.packageOptions.nodeDependencies);
|
|
475
563
|
}
|
|
476
|
-
node.addDevDeps(
|
|
564
|
+
node.addDevDeps(`uniffi-bindgen-react-native@${UBRN_VERSION}`);
|
|
477
565
|
if (binding.packageOptions.nodeDevDependencies?.length) {
|
|
478
566
|
node.addDevDeps(...binding.packageOptions.nodeDevDependencies);
|
|
479
567
|
}
|
|
@@ -498,7 +586,7 @@ export class DBXToolsRustWorkspace {
|
|
|
498
586
|
edition: options.edition ?? "2021",
|
|
499
587
|
"rust-version": options.rustVersion ?? "1.82",
|
|
500
588
|
license: options.license ?? "Apache-2.0",
|
|
501
|
-
repository
|
|
589
|
+
repository,
|
|
502
590
|
},
|
|
503
591
|
...(options.workspaceDependencies
|
|
504
592
|
? {
|
|
@@ -534,13 +622,7 @@ export class DBXToolsRustWorkspace {
|
|
|
534
622
|
]),
|
|
535
623
|
].join(" && "),
|
|
536
624
|
});
|
|
537
|
-
if (
|
|
538
|
-
(options.release ?? true) &&
|
|
539
|
-
(this.bindingMappings.length > 0 ||
|
|
540
|
-
this.packages.some(
|
|
541
|
-
(pkg) => pkg.packageOptions.release || !pkg.packageOptions.private,
|
|
542
|
-
))
|
|
543
|
-
) {
|
|
625
|
+
if (releaseEnabled) {
|
|
544
626
|
this.addReleaseWorkflow(project, options, releaseTargets(options));
|
|
545
627
|
}
|
|
546
628
|
}
|
|
@@ -551,6 +633,15 @@ export class DBXToolsRustWorkspace {
|
|
|
551
633
|
targets: readonly UniFFIReleaseTarget[],
|
|
552
634
|
): void {
|
|
553
635
|
if (!project.github) return;
|
|
636
|
+
const workflowName = options.releaseWorkflowName ?? "rust-release";
|
|
637
|
+
const releaseTagPrefix = options.releaseTagPrefix ?? "v";
|
|
638
|
+
const releaseRustVersion = options.releaseRustVersion ?? "stable";
|
|
639
|
+
const ubrnRustVersion = options.ubrnRustVersion ?? releaseRustVersion;
|
|
640
|
+
const ubrnToolchainInstall =
|
|
641
|
+
ubrnRustVersion === releaseRustVersion
|
|
642
|
+
? ""
|
|
643
|
+
: `rustup toolchain install ${ubrnRustVersion} --profile minimal\n`;
|
|
644
|
+
const releaseBranch = projectReleaseBranch(project);
|
|
554
645
|
const bindings = this.bindingMappings.map((binding) => ({
|
|
555
646
|
...binding,
|
|
556
647
|
node: binding.node ?? "",
|
|
@@ -572,7 +663,11 @@ export class DBXToolsRustWorkspace {
|
|
|
572
663
|
}));
|
|
573
664
|
const hasNodeBindings = bindings.some((binding) => binding.node);
|
|
574
665
|
const hasPythonBindings = bindings.some((binding) => binding.python);
|
|
575
|
-
const hasTargetOutputs =
|
|
666
|
+
const hasTargetOutputs =
|
|
667
|
+
bindings.length > 0 || releaseBinaries.length > 0 || publicCrates.length > 0;
|
|
668
|
+
if (hasTargetOutputs && targetMatrix.length === 0) {
|
|
669
|
+
throw new Error("Rust release requires at least one target");
|
|
670
|
+
}
|
|
576
671
|
const releaseTask = ".projen/uniffi-release.mjs";
|
|
577
672
|
if (bindings.length) {
|
|
578
673
|
new TextFile(project, releaseTask, {
|
|
@@ -599,7 +694,7 @@ export class DBXToolsRustWorkspace {
|
|
|
599
694
|
'--cpu "${{ matrix.target.cpu }}"',
|
|
600
695
|
'--libc "${{ matrix.target.libc }}"',
|
|
601
696
|
'--facade "${{ matrix.target.facade }}"',
|
|
602
|
-
|
|
697
|
+
`--version "\${VERSION#${releaseTagPrefix}}"`,
|
|
603
698
|
`--output "dist/release/${binding.crate}/\${{ matrix.target.node }}"`,
|
|
604
699
|
"--skip-build",
|
|
605
700
|
].join(" \\\n "),
|
|
@@ -663,14 +758,18 @@ export class DBXToolsRustWorkspace {
|
|
|
663
758
|
];
|
|
664
759
|
const buildJob = {
|
|
665
760
|
name: "${{ matrix.target.node }}",
|
|
761
|
+
needs: ["verify-context"],
|
|
666
762
|
"runs-on": "${{ matrix.target.runner }}",
|
|
667
|
-
env:
|
|
763
|
+
env: {
|
|
764
|
+
...RUST_CACHE_ENV,
|
|
765
|
+
SCCACHE_GHA_VERSION: `release-\${{ matrix.target.cargo }}-rust-${releaseRustVersion}`,
|
|
766
|
+
},
|
|
668
767
|
strategy: {
|
|
669
768
|
"fail-fast": false,
|
|
670
769
|
matrix: { include: targetMatrix },
|
|
671
770
|
},
|
|
672
771
|
steps: [
|
|
673
|
-
|
|
772
|
+
...releaseSourceSteps(),
|
|
674
773
|
...(hasNodeBindings
|
|
675
774
|
? [
|
|
676
775
|
{
|
|
@@ -680,24 +779,81 @@ export class DBXToolsRustWorkspace {
|
|
|
680
779
|
},
|
|
681
780
|
]
|
|
682
781
|
: []),
|
|
683
|
-
...(hasPythonBindings
|
|
684
|
-
? [{ name: "Setup uv", uses: "astral-sh/setup-uv@v7" }]
|
|
685
|
-
: []),
|
|
782
|
+
...(hasPythonBindings ? [{ name: "Setup uv", uses: "astral-sh/setup-uv@v7" }] : []),
|
|
686
783
|
{
|
|
687
784
|
name: "Setup Rust",
|
|
688
|
-
uses:
|
|
785
|
+
uses: `dtolnay/rust-toolchain@${releaseRustVersion}`,
|
|
689
786
|
with: { targets: "${{ matrix.target.cargo }}" },
|
|
690
787
|
},
|
|
691
|
-
...rustCacheSteps(
|
|
788
|
+
...rustCacheSteps(`release-\${{ matrix.target.cargo }}-rust-${releaseRustVersion}`),
|
|
789
|
+
...(hasNodeBindings
|
|
790
|
+
? [
|
|
791
|
+
{
|
|
792
|
+
name: "Cache UBRN generator",
|
|
793
|
+
id: "ubrn_cache",
|
|
794
|
+
if: "${{ vars.CACHE_UBRN_TARGET == 'true' }}",
|
|
795
|
+
uses: "actions/cache@v5",
|
|
796
|
+
with: {
|
|
797
|
+
path: "target/ubrn",
|
|
798
|
+
key: `ubrn-\${{ runner.os }}-\${{ runner.arch }}-rust-${ubrnRustVersion}-${UBRN_VERSION}`,
|
|
799
|
+
},
|
|
800
|
+
},
|
|
801
|
+
]
|
|
802
|
+
: []),
|
|
803
|
+
{
|
|
804
|
+
name: "Log cache configuration",
|
|
805
|
+
shell: "bash",
|
|
806
|
+
run: [
|
|
807
|
+
`echo "cargo_cache_namespace=release-\${{ matrix.target.cargo }}-rust-${releaseRustVersion}"`,
|
|
808
|
+
'echo "cargo_cache_hit=${{ steps.cargo_cache.outputs.cache-hit }}"',
|
|
809
|
+
'echo "sccache_scope=${{ github.ref }}"',
|
|
810
|
+
'echo "sccache_namespace=${SCCACHE_GHA_VERSION}"',
|
|
811
|
+
`echo "ubrn_rust_toolchain=${ubrnRustVersion}"`,
|
|
812
|
+
...(hasNodeBindings
|
|
813
|
+
? [
|
|
814
|
+
"echo \"ubrn_target_cache_enabled=${{ vars.CACHE_UBRN_TARGET == 'true' }}\"",
|
|
815
|
+
`echo "ubrn_target_cache_key=ubrn-\${{ runner.os }}-\${{ runner.arch }}-rust-${ubrnRustVersion}-${UBRN_VERSION}"`,
|
|
816
|
+
'echo "ubrn_target_cache_hit=${{ steps.ubrn_cache.outputs.cache-hit }}"',
|
|
817
|
+
]
|
|
818
|
+
: []),
|
|
819
|
+
].join("\n"),
|
|
820
|
+
},
|
|
692
821
|
{
|
|
693
822
|
name: "Install Linux native dependencies",
|
|
694
823
|
if: "${{ matrix.target.os == 'linux' }}",
|
|
695
824
|
run: "sudo apt-get update && sudo apt-get install --yes libdbus-1-dev pkg-config",
|
|
696
825
|
},
|
|
697
|
-
...(hasNodeBindings
|
|
826
|
+
...(hasNodeBindings
|
|
827
|
+
? [
|
|
828
|
+
{
|
|
829
|
+
name: "Install Node tooling",
|
|
830
|
+
shell: "bash",
|
|
831
|
+
run: timedBash("node_tooling", "bun install"),
|
|
832
|
+
},
|
|
833
|
+
]
|
|
834
|
+
: []),
|
|
835
|
+
...(hasNodeBindings
|
|
836
|
+
? [
|
|
837
|
+
{
|
|
838
|
+
name: "Prepare UBRN generator",
|
|
839
|
+
env: {
|
|
840
|
+
CARGO_TARGET_DIR: "${{ github.workspace }}/target/ubrn",
|
|
841
|
+
},
|
|
842
|
+
shell: "bash",
|
|
843
|
+
run: timedBash(
|
|
844
|
+
"ubrn_generator",
|
|
845
|
+
`${ubrnToolchainInstall}cargo +${ubrnRustVersion} build --manifest-path node_modules/uniffi-bindgen-react-native/crates/ubrn_cli/Cargo.toml`,
|
|
846
|
+
),
|
|
847
|
+
},
|
|
848
|
+
]
|
|
849
|
+
: []),
|
|
698
850
|
{
|
|
699
851
|
name: "Build Rust outputs",
|
|
700
|
-
|
|
852
|
+
shell: "bash",
|
|
853
|
+
run: timedBash(
|
|
854
|
+
"rust_workspace",
|
|
855
|
+
'cargo build --release --workspace --target "${{ matrix.target.cargo }}"',
|
|
856
|
+
),
|
|
701
857
|
},
|
|
702
858
|
...(bindingCommands.length
|
|
703
859
|
? [
|
|
@@ -705,9 +861,14 @@ export class DBXToolsRustWorkspace {
|
|
|
705
861
|
name: "Package UniFFI outputs",
|
|
706
862
|
shell: "bash",
|
|
707
863
|
env: {
|
|
708
|
-
VERSION:
|
|
864
|
+
VERSION: RELEASE_TAG,
|
|
865
|
+
...(hasNodeBindings
|
|
866
|
+
? {
|
|
867
|
+
CARGO_TARGET_DIR: "${{ github.workspace }}/target/ubrn",
|
|
868
|
+
}
|
|
869
|
+
: {}),
|
|
709
870
|
},
|
|
710
|
-
run: bindingCommands.join("\n"),
|
|
871
|
+
run: timedBash("uniffi_packaging", bindingCommands.join("\n")),
|
|
711
872
|
},
|
|
712
873
|
]
|
|
713
874
|
: []),
|
|
@@ -716,27 +877,31 @@ export class DBXToolsRustWorkspace {
|
|
|
716
877
|
{
|
|
717
878
|
name: "Package release binaries",
|
|
718
879
|
shell: "bash",
|
|
719
|
-
run: binaryCommands.join("\n"),
|
|
880
|
+
run: timedBash("binary_packaging", binaryCommands.join("\n")),
|
|
720
881
|
},
|
|
721
882
|
]
|
|
722
883
|
: []),
|
|
723
884
|
...artifactSteps,
|
|
885
|
+
{
|
|
886
|
+
name: "Log sccache statistics",
|
|
887
|
+
if: "${{ always() }}",
|
|
888
|
+
shell: "bash",
|
|
889
|
+
run: '"${SCCACHE_PATH}" --show-stats',
|
|
890
|
+
},
|
|
724
891
|
],
|
|
725
892
|
};
|
|
726
893
|
const bindingPublishJobs = Object.fromEntries(
|
|
727
894
|
bindings.map((binding) => [
|
|
728
895
|
`publish-${binding.crate}`,
|
|
729
896
|
{
|
|
730
|
-
if: "${{ github.event_name == '
|
|
897
|
+
if: "${{ github.event_name == 'repository_dispatch' }}",
|
|
731
898
|
needs: ["build"],
|
|
732
899
|
"runs-on": "ubuntu-latest",
|
|
733
900
|
permissions: {
|
|
734
901
|
contents: "read",
|
|
735
902
|
...(binding.python ? { "id-token": "write" } : {}),
|
|
736
903
|
},
|
|
737
|
-
...(binding.python
|
|
738
|
-
? { environment: { name: `pypi-${binding.crate}` } }
|
|
739
|
-
: {}),
|
|
904
|
+
...(binding.python ? { environment: { name: `pypi-${binding.crate}` } } : {}),
|
|
740
905
|
steps: [
|
|
741
906
|
...(binding.node
|
|
742
907
|
? [
|
|
@@ -796,36 +961,86 @@ export class DBXToolsRustWorkspace {
|
|
|
796
961
|
},
|
|
797
962
|
]),
|
|
798
963
|
);
|
|
799
|
-
const
|
|
964
|
+
const releaseCompletionJobs = [
|
|
965
|
+
"build",
|
|
966
|
+
...bindings.map((binding) => `publish-${binding.crate}`),
|
|
967
|
+
...(publicCrates.length ? ["publish-cargo"] : []),
|
|
968
|
+
...(releaseBinaries.length ? ["publish-github-release"] : []),
|
|
969
|
+
];
|
|
800
970
|
new YamlFile(project, `.github/workflows/${workflowName}.yml`, {
|
|
801
971
|
obj: {
|
|
802
972
|
name: workflowName,
|
|
973
|
+
"run-name": `${workflowName} ${RELEASE_TAG}`,
|
|
803
974
|
on: {
|
|
804
|
-
|
|
975
|
+
repository_dispatch: {
|
|
976
|
+
types: [RUST_RELEASE_EVENT],
|
|
977
|
+
},
|
|
805
978
|
workflow_dispatch: {
|
|
806
979
|
inputs: {
|
|
807
|
-
|
|
808
|
-
description: "
|
|
980
|
+
release_tag: {
|
|
981
|
+
description: "Annotated release tag to build",
|
|
982
|
+
type: "string",
|
|
983
|
+
required: true,
|
|
984
|
+
},
|
|
985
|
+
expected_sha: {
|
|
986
|
+
description: "Commit the release tag must reference",
|
|
809
987
|
type: "string",
|
|
810
|
-
|
|
988
|
+
required: true,
|
|
811
989
|
},
|
|
812
990
|
},
|
|
813
991
|
},
|
|
814
992
|
},
|
|
815
993
|
permissions: { contents: "read" },
|
|
816
994
|
jobs: {
|
|
995
|
+
"verify-context": {
|
|
996
|
+
"runs-on": "ubuntu-latest",
|
|
997
|
+
steps: [
|
|
998
|
+
{
|
|
999
|
+
name: "Require the default branch cache scope",
|
|
1000
|
+
shell: "bash",
|
|
1001
|
+
env: {
|
|
1002
|
+
RELEASE_BRANCH: releaseBranch,
|
|
1003
|
+
},
|
|
1004
|
+
run: 'test "$GITHUB_REF_NAME" = "$RELEASE_BRANCH"',
|
|
1005
|
+
},
|
|
1006
|
+
{
|
|
1007
|
+
name: "Write release metadata",
|
|
1008
|
+
shell: "bash",
|
|
1009
|
+
env: {
|
|
1010
|
+
RELEASE_TAG,
|
|
1011
|
+
EXPECTED_SHA: RELEASE_SHA,
|
|
1012
|
+
},
|
|
1013
|
+
run: [
|
|
1014
|
+
"mkdir -p .release",
|
|
1015
|
+
'printf "%s\\n" "$RELEASE_TAG" > .release/tag',
|
|
1016
|
+
'printf "%s\\n" "$EXPECTED_SHA" > .release/sha',
|
|
1017
|
+
].join("\n"),
|
|
1018
|
+
},
|
|
1019
|
+
{
|
|
1020
|
+
name: "Upload release metadata",
|
|
1021
|
+
uses: "actions/upload-artifact@v7",
|
|
1022
|
+
with: {
|
|
1023
|
+
name: "release-metadata",
|
|
1024
|
+
path: ".release",
|
|
1025
|
+
},
|
|
1026
|
+
},
|
|
1027
|
+
],
|
|
1028
|
+
},
|
|
817
1029
|
...(hasTargetOutputs && targetMatrix.length ? { build: buildJob } : {}),
|
|
818
1030
|
...bindingPublishJobs,
|
|
819
1031
|
...(publicCrates.length
|
|
820
1032
|
? {
|
|
821
1033
|
"publish-cargo": {
|
|
822
|
-
if: "${{ github.event_name == '
|
|
823
|
-
|
|
1034
|
+
if: "${{ github.event_name == 'repository_dispatch' }}",
|
|
1035
|
+
needs: ["build"],
|
|
824
1036
|
"runs-on": "ubuntu-latest",
|
|
825
1037
|
permissions: { contents: "read" },
|
|
826
1038
|
steps: [
|
|
827
|
-
|
|
828
|
-
{
|
|
1039
|
+
...releaseSourceSteps(),
|
|
1040
|
+
{
|
|
1041
|
+
name: "Setup Rust",
|
|
1042
|
+
uses: `dtolnay/rust-toolchain@${releaseRustVersion}`,
|
|
1043
|
+
},
|
|
829
1044
|
{
|
|
830
1045
|
name: "Publish public crates",
|
|
831
1046
|
env: { CARGO_REGISTRY_TOKEN: "${{ secrets.CARGO_REGISTRY_TOKEN }}" },
|
|
@@ -840,41 +1055,112 @@ export class DBXToolsRustWorkspace {
|
|
|
840
1055
|
},
|
|
841
1056
|
}
|
|
842
1057
|
: {}),
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
1058
|
+
...(bindings.length
|
|
1059
|
+
? {
|
|
1060
|
+
"publish-local-bindings": {
|
|
1061
|
+
if: "${{ github.event_name == 'repository_dispatch' && vars.LOCAL_REPOSITORIES == 'true' }}",
|
|
1062
|
+
needs: ["build"],
|
|
1063
|
+
"runs-on": ["self-hosted"],
|
|
1064
|
+
permissions: { contents: "read" },
|
|
1065
|
+
steps: [
|
|
1066
|
+
...(hasNodeBindings
|
|
1067
|
+
? [
|
|
1068
|
+
{
|
|
1069
|
+
name: "Setup Node.js",
|
|
1070
|
+
uses: "actions/setup-node@v6",
|
|
1071
|
+
with: {
|
|
1072
|
+
"registry-url": "${{ vars.LOCAL_NPM_REGISTRY }}",
|
|
1073
|
+
},
|
|
1074
|
+
},
|
|
1075
|
+
{
|
|
1076
|
+
name: "Download native npm packages",
|
|
1077
|
+
uses: "actions/download-artifact@v8",
|
|
1078
|
+
with: {
|
|
1079
|
+
pattern: "*-npm",
|
|
1080
|
+
path: "dist/npm",
|
|
1081
|
+
"merge-multiple": true,
|
|
1082
|
+
},
|
|
1083
|
+
},
|
|
1084
|
+
{
|
|
1085
|
+
name: "Download npm facades",
|
|
1086
|
+
uses: "actions/download-artifact@v8",
|
|
1087
|
+
with: {
|
|
1088
|
+
pattern: "*-npm-facade",
|
|
1089
|
+
path: "dist/npm-facade",
|
|
1090
|
+
"merge-multiple": true,
|
|
1091
|
+
},
|
|
1092
|
+
},
|
|
1093
|
+
{
|
|
1094
|
+
name: "Publish npm packages locally",
|
|
1095
|
+
env: {
|
|
1096
|
+
NODE_AUTH_TOKEN: "${{ secrets.LOCAL_NPM_TOKEN }}",
|
|
1097
|
+
},
|
|
1098
|
+
run: [
|
|
1099
|
+
'for package in dist/npm/*.tgz; do npm publish "$package" --access public; done',
|
|
1100
|
+
'for package in dist/npm-facade/*.tgz; do npm publish "$package" --access public; done',
|
|
1101
|
+
].join("\n"),
|
|
1102
|
+
},
|
|
1103
|
+
]
|
|
1104
|
+
: []),
|
|
1105
|
+
...(hasPythonBindings
|
|
1106
|
+
? [
|
|
1107
|
+
{ name: "Setup uv", uses: "astral-sh/setup-uv@v7" },
|
|
1108
|
+
{
|
|
1109
|
+
name: "Download Python wheels",
|
|
1110
|
+
uses: "actions/download-artifact@v8",
|
|
1111
|
+
with: {
|
|
1112
|
+
pattern: "*-python-wheel",
|
|
1113
|
+
path: "dist/python",
|
|
1114
|
+
"merge-multiple": true,
|
|
1115
|
+
},
|
|
1116
|
+
},
|
|
1117
|
+
{
|
|
1118
|
+
name: "Publish Python wheels locally",
|
|
1119
|
+
env: {
|
|
1120
|
+
UV_PUBLISH_USERNAME: "${{ secrets.LOCAL_PYPI_USERNAME }}",
|
|
1121
|
+
UV_PUBLISH_PASSWORD: "${{ secrets.LOCAL_PYPI_PASSWORD }}",
|
|
1122
|
+
},
|
|
1123
|
+
run: 'uv publish --publish-url "${{ vars.LOCAL_PYPI_PUBLISH_URL }}" dist/python/*.whl',
|
|
1124
|
+
},
|
|
1125
|
+
]
|
|
1126
|
+
: []),
|
|
1127
|
+
],
|
|
870
1128
|
},
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
|
|
1129
|
+
}
|
|
1130
|
+
: {}),
|
|
1131
|
+
...(publicCrates.length
|
|
1132
|
+
? {
|
|
1133
|
+
"publish-local-cargo": {
|
|
1134
|
+
if: "${{ github.event_name == 'repository_dispatch' && vars.LOCAL_REPOSITORIES == 'true' }}",
|
|
1135
|
+
needs: ["build"],
|
|
1136
|
+
"runs-on": ["self-hosted"],
|
|
1137
|
+
permissions: { contents: "read" },
|
|
1138
|
+
steps: [
|
|
1139
|
+
...releaseSourceSteps(),
|
|
1140
|
+
{
|
|
1141
|
+
name: "Setup Rust",
|
|
1142
|
+
uses: `dtolnay/rust-toolchain@${releaseRustVersion}`,
|
|
1143
|
+
},
|
|
1144
|
+
{
|
|
1145
|
+
name: "Publish Cargo crates locally",
|
|
1146
|
+
env: {
|
|
1147
|
+
CARGO_REGISTRY_TOKEN: "${{ secrets.LOCAL_CARGO_TOKEN }}",
|
|
1148
|
+
},
|
|
1149
|
+
run: publicCrates
|
|
1150
|
+
.map(
|
|
1151
|
+
(crate) =>
|
|
1152
|
+
`cargo publish --package "${crate}" --registry "\${{ vars.LOCAL_CARGO_REGISTRY }}" --no-verify`,
|
|
1153
|
+
)
|
|
1154
|
+
.join("\n"),
|
|
1155
|
+
},
|
|
1156
|
+
],
|
|
1157
|
+
},
|
|
1158
|
+
}
|
|
1159
|
+
: {}),
|
|
874
1160
|
...(releaseBinaries.length
|
|
875
1161
|
? {
|
|
876
1162
|
"publish-github-release": {
|
|
877
|
-
if: "${{ github.event_name == '
|
|
1163
|
+
if: "${{ github.event_name == 'repository_dispatch' }}",
|
|
878
1164
|
needs: ["build"],
|
|
879
1165
|
"runs-on": "ubuntu-latest",
|
|
880
1166
|
permissions: { contents: "write" },
|
|
@@ -894,12 +1180,40 @@ export class DBXToolsRustWorkspace {
|
|
|
894
1180
|
with: {
|
|
895
1181
|
files: "dist/rust-release/*",
|
|
896
1182
|
"generate-release-notes": true,
|
|
1183
|
+
tag_name: RELEASE_TAG,
|
|
1184
|
+
target_commitish: RELEASE_SHA,
|
|
897
1185
|
},
|
|
898
1186
|
},
|
|
899
1187
|
],
|
|
900
1188
|
},
|
|
901
1189
|
}
|
|
902
1190
|
: {}),
|
|
1191
|
+
"dispatch-downstream": {
|
|
1192
|
+
if: "${{ github.event_name == 'repository_dispatch' }}",
|
|
1193
|
+
needs: releaseCompletionJobs,
|
|
1194
|
+
"runs-on": "ubuntu-latest",
|
|
1195
|
+
permissions: { contents: "write" },
|
|
1196
|
+
steps: [
|
|
1197
|
+
{
|
|
1198
|
+
name: "Dispatch downstream releases",
|
|
1199
|
+
shell: "bash",
|
|
1200
|
+
env: {
|
|
1201
|
+
GH_TOKEN: "${{ github.token }}",
|
|
1202
|
+
RELEASE_TAG,
|
|
1203
|
+
EXPECTED_SHA: RELEASE_SHA,
|
|
1204
|
+
RELEASE_EVENT: DOWNSTREAM_RELEASE_EVENT,
|
|
1205
|
+
},
|
|
1206
|
+
run: [
|
|
1207
|
+
[
|
|
1208
|
+
'gh api --method POST "repos/$GITHUB_REPOSITORY/dispatches"',
|
|
1209
|
+
'--raw-field event_type="$RELEASE_EVENT"',
|
|
1210
|
+
'--raw-field "client_payload[release_tag]=$RELEASE_TAG"',
|
|
1211
|
+
'--raw-field "client_payload[expected_sha]=$EXPECTED_SHA"',
|
|
1212
|
+
].join(" \\\n "),
|
|
1213
|
+
].join("\n"),
|
|
1214
|
+
},
|
|
1215
|
+
],
|
|
1216
|
+
},
|
|
903
1217
|
},
|
|
904
1218
|
},
|
|
905
1219
|
});
|