@dbx-tools/projen 0.6.153 → 0.6.160
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 +53 -29
- package/index.ts +2 -0
- package/package.json +4 -4
- package/src/pnpm-workspace.ts +8 -1
- package/src/project-js.ts +64 -5
- package/src/project-py.ts +221 -42
- package/src/project-rs.ts +382 -92
- package/src/release-dispatch.ts +36 -0
- package/src/release.ts +187 -17
- package/tasks/bump.ts +21 -3
- package/tasks/uniffi-release.mjs +14 -2
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 {
|
|
@@ -140,12 +159,18 @@ const RUST_CACHE_ENV = {
|
|
|
140
159
|
SCCACHE_GHA_ENABLED: "true",
|
|
141
160
|
} as const;
|
|
142
161
|
const UBRN_VERSION = "0.31.0-5";
|
|
162
|
+
const RELEASE_PLATFORMS_ENV = "DBX_TOOLS_RELEASE_PLATFORMS";
|
|
143
163
|
|
|
144
|
-
function rustCacheSteps(sharedKey: string): readonly Record<string, unknown>[] {
|
|
164
|
+
function rustCacheSteps(sharedKey: string, idPrefix = ""): readonly Record<string, unknown>[] {
|
|
145
165
|
return [
|
|
146
|
-
{
|
|
166
|
+
{
|
|
167
|
+
name: "Setup sccache",
|
|
168
|
+
id: `${idPrefix}sccache`,
|
|
169
|
+
uses: "mozilla-actions/sccache-action@v0.0.11",
|
|
170
|
+
},
|
|
147
171
|
{
|
|
148
172
|
name: "Cache Cargo registry",
|
|
173
|
+
id: `${idPrefix}cargo_cache`,
|
|
149
174
|
uses: "Swatinem/rust-cache@v2.9.2",
|
|
150
175
|
with: {
|
|
151
176
|
"cache-targets": false,
|
|
@@ -157,13 +182,23 @@ function rustCacheSteps(sharedKey: string): readonly Record<string, unknown>[] {
|
|
|
157
182
|
];
|
|
158
183
|
}
|
|
159
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
|
+
|
|
160
193
|
function releaseTargets(options: DBXToolsRustWorkspaceOptions): readonly UniFFIReleaseTarget[] {
|
|
161
194
|
if (options.releaseTargets && options.releasePlatforms) {
|
|
162
195
|
throw new Error("releaseTargets and releasePlatforms are mutually exclusive");
|
|
163
196
|
}
|
|
164
197
|
if (options.releaseTargets) return options.releaseTargets;
|
|
165
|
-
|
|
166
|
-
|
|
198
|
+
const releasePlatforms =
|
|
199
|
+
options.releasePlatforms ?? releasePlatformsFromEnvironment(process.env[RELEASE_PLATFORMS_ENV]);
|
|
200
|
+
if (!releasePlatforms) return UNIFFI_RELEASE_TARGETS;
|
|
201
|
+
return releasePlatforms.map((platform) => {
|
|
167
202
|
const target = UNIFFI_RELEASE_TARGETS.find(
|
|
168
203
|
(candidate) => candidate.os === platform.os && candidate.cpu === platform.cpu,
|
|
169
204
|
);
|
|
@@ -173,6 +208,23 @@ function releaseTargets(options: DBXToolsRustWorkspaceOptions): readonly UniFFIR
|
|
|
173
208
|
});
|
|
174
209
|
}
|
|
175
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
|
+
|
|
176
228
|
function uniffiReleaseTaskSource(): string {
|
|
177
229
|
const sourceDirectory = dirname(fileURLToPath(import.meta.url));
|
|
178
230
|
const candidates = [
|
|
@@ -192,6 +244,7 @@ export interface RustBindingMapping {
|
|
|
192
244
|
readonly python?: string;
|
|
193
245
|
readonly nodePackage?: string;
|
|
194
246
|
readonly pythonPackage?: string;
|
|
247
|
+
readonly pythonModule?: string;
|
|
195
248
|
readonly facadeTarget?: boolean;
|
|
196
249
|
}
|
|
197
250
|
|
|
@@ -200,6 +253,7 @@ export interface RustWorkspaceMapping {
|
|
|
200
253
|
readonly root: string;
|
|
201
254
|
readonly crates: readonly string[];
|
|
202
255
|
readonly bindings: readonly RustBindingMapping[];
|
|
256
|
+
readonly releaseWorkflow?: string;
|
|
203
257
|
}
|
|
204
258
|
|
|
205
259
|
function rustSources(directory: string): string[] {
|
|
@@ -374,10 +428,18 @@ export class DBXToolsRustWorkspace {
|
|
|
374
428
|
constructor(project: javascript.NodeProject, options: DBXToolsRustWorkspaceOptions) {
|
|
375
429
|
const root = options.root ?? "packages/rs";
|
|
376
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("-", "_");
|
|
377
439
|
const packageOptions = options.packages ?? {};
|
|
378
440
|
this.packages = discoverRustCrates(resolve(project.outdir, root)).map(
|
|
379
441
|
(directory) =>
|
|
380
|
-
new DBXToolsRustProject(project, root,
|
|
442
|
+
new DBXToolsRustProject(project, root, scope, {
|
|
381
443
|
directory,
|
|
382
444
|
...packageOptions[directory],
|
|
383
445
|
}),
|
|
@@ -393,44 +455,69 @@ export class DBXToolsRustWorkspace {
|
|
|
393
455
|
...(targets.includes("node")
|
|
394
456
|
? {
|
|
395
457
|
node: `${nodeRoot}/${pkg.packageOptions.directory}`,
|
|
396
|
-
nodePackage: `@${
|
|
458
|
+
nodePackage: `@${scope}/${packageName}`,
|
|
397
459
|
}
|
|
398
460
|
: {}),
|
|
399
461
|
...(targets.includes("python")
|
|
400
462
|
? {
|
|
401
463
|
python: `${options.pythonRoot ?? "packages/py"}/${pkg.packageOptions.directory}`,
|
|
402
464
|
pythonPackage: pkg.crateName,
|
|
465
|
+
pythonModule: pythonModuleName(pythonModulePrefix, pkg.packageOptions.directory),
|
|
403
466
|
}
|
|
404
467
|
: {}),
|
|
405
468
|
};
|
|
406
469
|
});
|
|
470
|
+
const releaseEnabled =
|
|
471
|
+
(options.release ?? true) &&
|
|
472
|
+
(this.bindingMappings.length > 0 ||
|
|
473
|
+
this.packages.some((pkg) => pkg.packageOptions.release || !pkg.packageOptions.private));
|
|
407
474
|
this.workspaceMapping = {
|
|
408
475
|
root,
|
|
409
476
|
crates: this.packages.map((pkg) => `${root}/${pkg.packageOptions.directory}`),
|
|
410
477
|
bindings: this.bindingMappings,
|
|
478
|
+
...(releaseEnabled ? { releaseWorkflow: options.releaseWorkflowName ?? "rust-release" } : {}),
|
|
411
479
|
};
|
|
412
|
-
if (
|
|
413
|
-
|
|
480
|
+
if (dbxToolsProject) {
|
|
481
|
+
dbxToolsProject.dbxToolsConfig.rust = this.workspaceMapping;
|
|
414
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
|
+
);
|
|
415
501
|
this.pythonPackages = bindings
|
|
416
502
|
.filter((pkg) => (pkg.packageOptions.bindings ?? ["node", "python"]).includes("python"))
|
|
417
|
-
.map((pkg) =>
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
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
|
+
});
|
|
434
521
|
|
|
435
522
|
const existing = new Map(
|
|
436
523
|
project.subprojects.map((child) => [relative(project.outdir, child.outdir), child]),
|
|
@@ -448,12 +535,12 @@ export class DBXToolsRustWorkspace {
|
|
|
448
535
|
: new DBXToolsTypeScriptProject({
|
|
449
536
|
parent: project,
|
|
450
537
|
outdir: memberPath,
|
|
451
|
-
name: `@${
|
|
538
|
+
name: `@${scope}/${directory.toLowerCase().replace(/[^a-z0-9-]+/g, "-")}`,
|
|
452
539
|
tags: ["node"],
|
|
453
540
|
});
|
|
454
541
|
node.package.addField(
|
|
455
542
|
"name",
|
|
456
|
-
`@${
|
|
543
|
+
`@${scope}/${directory.toLowerCase().replace(/[^a-z0-9-]+/g, "-")}`,
|
|
457
544
|
);
|
|
458
545
|
node.package.addField("private", true);
|
|
459
546
|
node.package.file.addDeletionOverride("publishConfig");
|
|
@@ -464,7 +551,7 @@ export class DBXToolsRustWorkspace {
|
|
|
464
551
|
"optionalDependencies",
|
|
465
552
|
Object.fromEntries(
|
|
466
553
|
nativeTargets.map((target) => [
|
|
467
|
-
`@${
|
|
554
|
+
`@${scope}/${directory}-${target.node}`,
|
|
468
555
|
readWorkspaceVersion(project.outdir),
|
|
469
556
|
]),
|
|
470
557
|
),
|
|
@@ -499,7 +586,7 @@ export class DBXToolsRustWorkspace {
|
|
|
499
586
|
edition: options.edition ?? "2021",
|
|
500
587
|
"rust-version": options.rustVersion ?? "1.82",
|
|
501
588
|
license: options.license ?? "Apache-2.0",
|
|
502
|
-
repository
|
|
589
|
+
repository,
|
|
503
590
|
},
|
|
504
591
|
...(options.workspaceDependencies
|
|
505
592
|
? {
|
|
@@ -535,11 +622,7 @@ export class DBXToolsRustWorkspace {
|
|
|
535
622
|
]),
|
|
536
623
|
].join(" && "),
|
|
537
624
|
});
|
|
538
|
-
if (
|
|
539
|
-
(options.release ?? true) &&
|
|
540
|
-
(this.bindingMappings.length > 0 ||
|
|
541
|
-
this.packages.some((pkg) => pkg.packageOptions.release || !pkg.packageOptions.private))
|
|
542
|
-
) {
|
|
625
|
+
if (releaseEnabled) {
|
|
543
626
|
this.addReleaseWorkflow(project, options, releaseTargets(options));
|
|
544
627
|
}
|
|
545
628
|
}
|
|
@@ -550,6 +633,15 @@ export class DBXToolsRustWorkspace {
|
|
|
550
633
|
targets: readonly UniFFIReleaseTarget[],
|
|
551
634
|
): void {
|
|
552
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);
|
|
553
645
|
const bindings = this.bindingMappings.map((binding) => ({
|
|
554
646
|
...binding,
|
|
555
647
|
node: binding.node ?? "",
|
|
@@ -571,7 +663,11 @@ export class DBXToolsRustWorkspace {
|
|
|
571
663
|
}));
|
|
572
664
|
const hasNodeBindings = bindings.some((binding) => binding.node);
|
|
573
665
|
const hasPythonBindings = bindings.some((binding) => binding.python);
|
|
574
|
-
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
|
+
}
|
|
575
671
|
const releaseTask = ".projen/uniffi-release.mjs";
|
|
576
672
|
if (bindings.length) {
|
|
577
673
|
new TextFile(project, releaseTask, {
|
|
@@ -598,7 +694,7 @@ export class DBXToolsRustWorkspace {
|
|
|
598
694
|
'--cpu "${{ matrix.target.cpu }}"',
|
|
599
695
|
'--libc "${{ matrix.target.libc }}"',
|
|
600
696
|
'--facade "${{ matrix.target.facade }}"',
|
|
601
|
-
|
|
697
|
+
`--version "\${VERSION#${releaseTagPrefix}}"`,
|
|
602
698
|
`--output "dist/release/${binding.crate}/\${{ matrix.target.node }}"`,
|
|
603
699
|
"--skip-build",
|
|
604
700
|
].join(" \\\n "),
|
|
@@ -662,14 +758,18 @@ export class DBXToolsRustWorkspace {
|
|
|
662
758
|
];
|
|
663
759
|
const buildJob = {
|
|
664
760
|
name: "${{ matrix.target.node }}",
|
|
761
|
+
needs: ["verify-context"],
|
|
665
762
|
"runs-on": "${{ matrix.target.runner }}",
|
|
666
|
-
env:
|
|
763
|
+
env: {
|
|
764
|
+
...RUST_CACHE_ENV,
|
|
765
|
+
SCCACHE_GHA_VERSION: `release-\${{ matrix.target.cargo }}-rust-${releaseRustVersion}`,
|
|
766
|
+
},
|
|
667
767
|
strategy: {
|
|
668
768
|
"fail-fast": false,
|
|
669
769
|
matrix: { include: targetMatrix },
|
|
670
770
|
},
|
|
671
771
|
steps: [
|
|
672
|
-
|
|
772
|
+
...releaseSourceSteps(),
|
|
673
773
|
...(hasNodeBindings
|
|
674
774
|
? [
|
|
675
775
|
{
|
|
@@ -682,28 +782,56 @@ export class DBXToolsRustWorkspace {
|
|
|
682
782
|
...(hasPythonBindings ? [{ name: "Setup uv", uses: "astral-sh/setup-uv@v7" }] : []),
|
|
683
783
|
{
|
|
684
784
|
name: "Setup Rust",
|
|
685
|
-
uses:
|
|
785
|
+
uses: `dtolnay/rust-toolchain@${releaseRustVersion}`,
|
|
686
786
|
with: { targets: "${{ matrix.target.cargo }}" },
|
|
687
787
|
},
|
|
688
|
-
...rustCacheSteps(
|
|
788
|
+
...rustCacheSteps(`release-\${{ matrix.target.cargo }}-rust-${releaseRustVersion}`),
|
|
689
789
|
...(hasNodeBindings
|
|
690
790
|
? [
|
|
691
791
|
{
|
|
692
792
|
name: "Cache UBRN generator",
|
|
793
|
+
id: "ubrn_cache",
|
|
794
|
+
if: "${{ vars.CACHE_UBRN_TARGET == 'true' }}",
|
|
693
795
|
uses: "actions/cache@v5",
|
|
694
796
|
with: {
|
|
695
797
|
path: "target/ubrn",
|
|
696
|
-
key: `ubrn-\${{ runner.os }}-\${{ runner.arch }}-${UBRN_VERSION}`,
|
|
798
|
+
key: `ubrn-\${{ runner.os }}-\${{ runner.arch }}-rust-${ubrnRustVersion}-${UBRN_VERSION}`,
|
|
697
799
|
},
|
|
698
800
|
},
|
|
699
801
|
]
|
|
700
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
|
+
},
|
|
701
821
|
{
|
|
702
822
|
name: "Install Linux native dependencies",
|
|
703
823
|
if: "${{ matrix.target.os == 'linux' }}",
|
|
704
824
|
run: "sudo apt-get update && sudo apt-get install --yes libdbus-1-dev pkg-config",
|
|
705
825
|
},
|
|
706
|
-
...(hasNodeBindings
|
|
826
|
+
...(hasNodeBindings
|
|
827
|
+
? [
|
|
828
|
+
{
|
|
829
|
+
name: "Install Node tooling",
|
|
830
|
+
shell: "bash",
|
|
831
|
+
run: timedBash("node_tooling", "bun install"),
|
|
832
|
+
},
|
|
833
|
+
]
|
|
834
|
+
: []),
|
|
707
835
|
...(hasNodeBindings
|
|
708
836
|
? [
|
|
709
837
|
{
|
|
@@ -711,13 +839,21 @@ export class DBXToolsRustWorkspace {
|
|
|
711
839
|
env: {
|
|
712
840
|
CARGO_TARGET_DIR: "${{ github.workspace }}/target/ubrn",
|
|
713
841
|
},
|
|
714
|
-
|
|
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
|
+
),
|
|
715
847
|
},
|
|
716
848
|
]
|
|
717
849
|
: []),
|
|
718
850
|
{
|
|
719
851
|
name: "Build Rust outputs",
|
|
720
|
-
|
|
852
|
+
shell: "bash",
|
|
853
|
+
run: timedBash(
|
|
854
|
+
"rust_workspace",
|
|
855
|
+
'cargo build --release --workspace --target "${{ matrix.target.cargo }}"',
|
|
856
|
+
),
|
|
721
857
|
},
|
|
722
858
|
...(bindingCommands.length
|
|
723
859
|
? [
|
|
@@ -725,15 +861,14 @@ export class DBXToolsRustWorkspace {
|
|
|
725
861
|
name: "Package UniFFI outputs",
|
|
726
862
|
shell: "bash",
|
|
727
863
|
env: {
|
|
728
|
-
VERSION:
|
|
729
|
-
"${{ github.event_name == 'push' && github.ref_name || inputs.version }}",
|
|
864
|
+
VERSION: RELEASE_TAG,
|
|
730
865
|
...(hasNodeBindings
|
|
731
866
|
? {
|
|
732
867
|
CARGO_TARGET_DIR: "${{ github.workspace }}/target/ubrn",
|
|
733
868
|
}
|
|
734
869
|
: {}),
|
|
735
870
|
},
|
|
736
|
-
run: bindingCommands.join("\n"),
|
|
871
|
+
run: timedBash("uniffi_packaging", bindingCommands.join("\n")),
|
|
737
872
|
},
|
|
738
873
|
]
|
|
739
874
|
: []),
|
|
@@ -742,18 +877,24 @@ export class DBXToolsRustWorkspace {
|
|
|
742
877
|
{
|
|
743
878
|
name: "Package release binaries",
|
|
744
879
|
shell: "bash",
|
|
745
|
-
run: binaryCommands.join("\n"),
|
|
880
|
+
run: timedBash("binary_packaging", binaryCommands.join("\n")),
|
|
746
881
|
},
|
|
747
882
|
]
|
|
748
883
|
: []),
|
|
749
884
|
...artifactSteps,
|
|
885
|
+
{
|
|
886
|
+
name: "Log sccache statistics",
|
|
887
|
+
if: "${{ always() }}",
|
|
888
|
+
shell: "bash",
|
|
889
|
+
run: '"${SCCACHE_PATH}" --show-stats',
|
|
890
|
+
},
|
|
750
891
|
],
|
|
751
892
|
};
|
|
752
893
|
const bindingPublishJobs = Object.fromEntries(
|
|
753
894
|
bindings.map((binding) => [
|
|
754
895
|
`publish-${binding.crate}`,
|
|
755
896
|
{
|
|
756
|
-
if: "${{ github.event_name == '
|
|
897
|
+
if: "${{ github.event_name == 'repository_dispatch' }}",
|
|
757
898
|
needs: ["build"],
|
|
758
899
|
"runs-on": "ubuntu-latest",
|
|
759
900
|
permissions: {
|
|
@@ -820,36 +961,86 @@ export class DBXToolsRustWorkspace {
|
|
|
820
961
|
},
|
|
821
962
|
]),
|
|
822
963
|
);
|
|
823
|
-
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
|
+
];
|
|
824
970
|
new YamlFile(project, `.github/workflows/${workflowName}.yml`, {
|
|
825
971
|
obj: {
|
|
826
972
|
name: workflowName,
|
|
973
|
+
"run-name": `${workflowName} ${RELEASE_TAG}`,
|
|
827
974
|
on: {
|
|
828
|
-
|
|
975
|
+
repository_dispatch: {
|
|
976
|
+
types: [RUST_RELEASE_EVENT],
|
|
977
|
+
},
|
|
829
978
|
workflow_dispatch: {
|
|
830
979
|
inputs: {
|
|
831
|
-
|
|
832
|
-
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",
|
|
833
987
|
type: "string",
|
|
834
|
-
|
|
988
|
+
required: true,
|
|
835
989
|
},
|
|
836
990
|
},
|
|
837
991
|
},
|
|
838
992
|
},
|
|
839
993
|
permissions: { contents: "read" },
|
|
840
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
|
+
},
|
|
841
1029
|
...(hasTargetOutputs && targetMatrix.length ? { build: buildJob } : {}),
|
|
842
1030
|
...bindingPublishJobs,
|
|
843
1031
|
...(publicCrates.length
|
|
844
1032
|
? {
|
|
845
1033
|
"publish-cargo": {
|
|
846
|
-
if: "${{ github.event_name == '
|
|
847
|
-
|
|
1034
|
+
if: "${{ github.event_name == 'repository_dispatch' }}",
|
|
1035
|
+
needs: ["build"],
|
|
848
1036
|
"runs-on": "ubuntu-latest",
|
|
849
1037
|
permissions: { contents: "read" },
|
|
850
1038
|
steps: [
|
|
851
|
-
|
|
852
|
-
{
|
|
1039
|
+
...releaseSourceSteps(),
|
|
1040
|
+
{
|
|
1041
|
+
name: "Setup Rust",
|
|
1042
|
+
uses: `dtolnay/rust-toolchain@${releaseRustVersion}`,
|
|
1043
|
+
},
|
|
853
1044
|
{
|
|
854
1045
|
name: "Publish public crates",
|
|
855
1046
|
env: { CARGO_REGISTRY_TOKEN: "${{ secrets.CARGO_REGISTRY_TOKEN }}" },
|
|
@@ -864,41 +1055,112 @@ export class DBXToolsRustWorkspace {
|
|
|
864
1055
|
},
|
|
865
1056
|
}
|
|
866
1057
|
: {}),
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
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
|
+
],
|
|
894
1128
|
},
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
|
|
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
|
+
: {}),
|
|
898
1160
|
...(releaseBinaries.length
|
|
899
1161
|
? {
|
|
900
1162
|
"publish-github-release": {
|
|
901
|
-
if: "${{ github.event_name == '
|
|
1163
|
+
if: "${{ github.event_name == 'repository_dispatch' }}",
|
|
902
1164
|
needs: ["build"],
|
|
903
1165
|
"runs-on": "ubuntu-latest",
|
|
904
1166
|
permissions: { contents: "write" },
|
|
@@ -918,12 +1180,40 @@ export class DBXToolsRustWorkspace {
|
|
|
918
1180
|
with: {
|
|
919
1181
|
files: "dist/rust-release/*",
|
|
920
1182
|
"generate-release-notes": true,
|
|
1183
|
+
tag_name: RELEASE_TAG,
|
|
1184
|
+
target_commitish: RELEASE_SHA,
|
|
921
1185
|
},
|
|
922
1186
|
},
|
|
923
1187
|
],
|
|
924
1188
|
},
|
|
925
1189
|
}
|
|
926
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
|
+
},
|
|
927
1217
|
},
|
|
928
1218
|
},
|
|
929
1219
|
});
|