@dbx-tools/projen 0.6.163 → 0.6.174
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 +56 -41
- package/index.ts +2 -1
- package/package.json +4 -5
- package/src/barrels.ts +134 -34
- package/src/project-js.ts +19 -22
- package/src/project-py.ts +83 -21
- package/src/project-rs.ts +175 -309
- package/src/release.ts +109 -4
- package/src/uniffi.ts +45 -0
- package/tasks/bump.ts +12 -2
- package/tasks/publish-uniffi-local.ts +3 -4
- package/tasks/publish.ts +22 -13
- package/tasks/rust.ts +17 -3
- package/tasks/uniffi-release.mjs +242 -29
- package/tasks/uniffi.ts +101 -55
package/src/project-py.ts
CHANGED
|
@@ -7,8 +7,8 @@ import { GithubWorkflow } from "projen/lib/github";
|
|
|
7
7
|
import { JobPermission } from "projen/lib/github/workflows-model";
|
|
8
8
|
import { parse, stringify } from "smol-toml";
|
|
9
9
|
import { projectReleaseBranch, projectRepositoryUrl } from "./project-js.ts";
|
|
10
|
-
import type { DBXToolsProject, DBXToolsProjectOptions } from "./project.ts";
|
|
11
10
|
import { isDBXToolsJavaScriptProject } from "./project-predicate.ts";
|
|
11
|
+
import type { DBXToolsProject, DBXToolsProjectOptions } from "./project.ts";
|
|
12
12
|
import { DOWNSTREAM_RELEASE_EVENT, RELEASE_TAG, releaseSourceSteps } from "./release-dispatch.ts";
|
|
13
13
|
import { readWorkspaceVersion } from "./workspace-version.ts";
|
|
14
14
|
|
|
@@ -29,8 +29,8 @@ export interface PythonPackageOptions extends DBXToolsProjectOptions {
|
|
|
29
29
|
/** Workspace package directories rendered as standalone Git dependencies. */
|
|
30
30
|
readonly internalDependencies?: readonly string[];
|
|
31
31
|
readonly scripts?: Readonly<Record<string, string>>;
|
|
32
|
-
/**
|
|
33
|
-
readonly
|
|
32
|
+
/** Publish this package through the Rust UniFFI release flow instead of the Python workflow. */
|
|
33
|
+
readonly uniffi?: boolean;
|
|
34
34
|
/** Generated source files excluded from strict static analysis. Package-relative. */
|
|
35
35
|
readonly generatedSources?: readonly string[];
|
|
36
36
|
/** Trusted publisher used outside the standard Python release workflow. */
|
|
@@ -75,6 +75,7 @@ interface PythonPublication {
|
|
|
75
75
|
readonly environment: string;
|
|
76
76
|
readonly workflowName: string;
|
|
77
77
|
readonly artifacts?: string;
|
|
78
|
+
readonly dependencies?: readonly string[];
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
/** Options for {@link DBXToolsPythonWorkspace}. */
|
|
@@ -214,8 +215,8 @@ export class DBXToolsPythonProject extends python.PythonProject implements DBXTo
|
|
|
214
215
|
if (pkg.scripts) {
|
|
215
216
|
this.uv.file.addOverride("project.scripts", pkg.scripts);
|
|
216
217
|
}
|
|
217
|
-
if (pkg.
|
|
218
|
-
this.uv.file.addOverride("tool.
|
|
218
|
+
if (pkg.uniffi !== undefined) {
|
|
219
|
+
this.uv.file.addOverride("tool.dbx_tools.config.uniffi", pkg.uniffi);
|
|
219
220
|
}
|
|
220
221
|
formatPyproject(this.uv.file);
|
|
221
222
|
this.uv.file.readonly = true;
|
|
@@ -319,7 +320,7 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
319
320
|
projectVscode(project)?.settings.addSetting("python.defaultInterpreterPath", interpreterPath);
|
|
320
321
|
}
|
|
321
322
|
|
|
322
|
-
if (options.release && this.packages.
|
|
323
|
+
if (options.release && this.packages.length > 0) {
|
|
323
324
|
if (isDBXToolsJavaScriptProject()(project)) {
|
|
324
325
|
project.dbxToolsConfig.pythonReleaseWorkflow =
|
|
325
326
|
releaseOptions.workflowName ?? "python-release";
|
|
@@ -428,7 +429,10 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
428
429
|
private addReleaseWorkflow(project: javascript.NodeProject, options: PythonReleaseOptions): void {
|
|
429
430
|
if (!project.github) return;
|
|
430
431
|
const publications = this.publications(options);
|
|
431
|
-
|
|
432
|
+
const uniffiPublications = this.uniffiPublications(options);
|
|
433
|
+
const allPublications = [...publications, ...uniffiPublications];
|
|
434
|
+
if (allPublications.length === 0) return;
|
|
435
|
+
const usesRustArtifacts = uniffiPublications.length > 0;
|
|
432
436
|
const workflowName = options.workflowName ?? "python-release";
|
|
433
437
|
const workflow = new GithubWorkflow(project.github, workflowName, {
|
|
434
438
|
limitConcurrency: true,
|
|
@@ -436,7 +440,7 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
436
440
|
});
|
|
437
441
|
workflow.file?.addOverride("permissions", {
|
|
438
442
|
contents: "read",
|
|
439
|
-
...(options.upstreamWorkflow ? { actions: "read" } : {}),
|
|
443
|
+
...(options.upstreamWorkflow || usesRustArtifacts ? { actions: "read" } : {}),
|
|
440
444
|
});
|
|
441
445
|
const upstreamWorkflow = options.upstreamWorkflow;
|
|
442
446
|
const branchDispatch = upstreamWorkflow === undefined && isDBXToolsJavaScriptProject()(project);
|
|
@@ -487,7 +491,7 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
487
491
|
runsOn: ["ubuntu-latest"],
|
|
488
492
|
permissions: {
|
|
489
493
|
contents: JobPermission.READ,
|
|
490
|
-
...(upstreamWorkflow ? { actions: JobPermission.READ } : {}),
|
|
494
|
+
...(upstreamWorkflow || usesRustArtifacts ? { actions: JobPermission.READ } : {}),
|
|
491
495
|
},
|
|
492
496
|
timeoutMinutes: 20,
|
|
493
497
|
steps: [
|
|
@@ -555,6 +559,35 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
555
559
|
]
|
|
556
560
|
: []),
|
|
557
561
|
{ name: "Setup uv", uses: "astral-sh/setup-uv@v7" },
|
|
562
|
+
...(usesRustArtifacts
|
|
563
|
+
? [
|
|
564
|
+
{
|
|
565
|
+
name: "Require Rust artifact handoff",
|
|
566
|
+
if: "${{ github.event_name == 'repository_dispatch' || github.event_name == 'workflow_run' }}",
|
|
567
|
+
shell: "bash",
|
|
568
|
+
env: {
|
|
569
|
+
RUST_RUN_ID:
|
|
570
|
+
"${{ github.event_name == 'repository_dispatch' && github.event.client_payload.rust_run_id || github.event.workflow_run.id }}",
|
|
571
|
+
RUST_RUN_ATTEMPT:
|
|
572
|
+
"${{ github.event_name == 'repository_dispatch' && github.event.client_payload.rust_run_attempt || github.event.workflow_run.run_attempt }}",
|
|
573
|
+
},
|
|
574
|
+
run: ['test -n "$RUST_RUN_ID"', 'test -n "$RUST_RUN_ATTEMPT"'].join("\n"),
|
|
575
|
+
},
|
|
576
|
+
]
|
|
577
|
+
: []),
|
|
578
|
+
...uniffiPublications.map((publication) => ({
|
|
579
|
+
name: `Download ${publication.distribution} native wheels`,
|
|
580
|
+
if: "${{ github.event_name == 'repository_dispatch' || github.event_name == 'workflow_run' }}",
|
|
581
|
+
uses: "actions/download-artifact@v8",
|
|
582
|
+
with: {
|
|
583
|
+
pattern: `${publication.distribution}--*--python-wheel`,
|
|
584
|
+
path: `dist/${publication.directory}`,
|
|
585
|
+
"merge-multiple": true,
|
|
586
|
+
"run-id":
|
|
587
|
+
"${{ github.event_name == 'repository_dispatch' && github.event.client_payload.rust_run_id || github.event.workflow_run.id }}",
|
|
588
|
+
"github-token": "${{ github.token }}",
|
|
589
|
+
},
|
|
590
|
+
})),
|
|
558
591
|
{
|
|
559
592
|
name: "Stamp workspace versions",
|
|
560
593
|
env: {
|
|
@@ -594,8 +627,15 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
594
627
|
{
|
|
595
628
|
name: "Validate distributions",
|
|
596
629
|
run: [
|
|
597
|
-
|
|
598
|
-
|
|
630
|
+
...publications.map(
|
|
631
|
+
(publication) =>
|
|
632
|
+
`test "$(find dist/${publication.directory} -maxdepth 1 -type f \\( -name '*.whl' -o -name '*.tar.gz' \\) | wc -l | tr -d ' ')" -eq 2`,
|
|
633
|
+
),
|
|
634
|
+
...uniffiPublications.map(
|
|
635
|
+
(publication) =>
|
|
636
|
+
`if [ "$GITHUB_EVENT_NAME" = "repository_dispatch" ] || [ "$GITHUB_EVENT_NAME" = "workflow_run" ]; then find dist/${publication.directory} -maxdepth 1 -name '*.whl' -print -quit | grep -q .; fi`,
|
|
637
|
+
),
|
|
638
|
+
"find dist -type f \\( -name '*.whl' -o -name '*.tar.gz' \\) -print0 | xargs -0 uvx twine check",
|
|
599
639
|
].join("\n"),
|
|
600
640
|
},
|
|
601
641
|
{
|
|
@@ -610,12 +650,15 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
610
650
|
},
|
|
611
651
|
],
|
|
612
652
|
});
|
|
613
|
-
for (const publication of
|
|
653
|
+
for (const publication of allPublications) {
|
|
614
654
|
workflow.addJob(`publish-${publication.directory}`, {
|
|
615
655
|
if: branchDispatch
|
|
616
656
|
? "${{ github.event_name == 'repository_dispatch' }}"
|
|
617
657
|
: "${{ github.event_name == 'push' || github.event_name == 'workflow_run' }}",
|
|
618
|
-
needs: [
|
|
658
|
+
needs: [
|
|
659
|
+
"build",
|
|
660
|
+
...(publication.dependencies ?? []).map((dependency) => `publish-${dependency}`),
|
|
661
|
+
],
|
|
619
662
|
environment: {
|
|
620
663
|
name: publication.environment,
|
|
621
664
|
url:
|
|
@@ -643,7 +686,7 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
643
686
|
|
|
644
687
|
private publications(options: PythonReleaseOptions): readonly PythonPublication[] {
|
|
645
688
|
return this.packages
|
|
646
|
-
.filter((pkg) =>
|
|
689
|
+
.filter((pkg) => pkg.packageOptions.uniffi !== true)
|
|
647
690
|
.map((pkg) => ({
|
|
648
691
|
directory: pkg.packageOptions.directory,
|
|
649
692
|
distribution: pkg.packageOptions.name,
|
|
@@ -653,6 +696,22 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
653
696
|
}));
|
|
654
697
|
}
|
|
655
698
|
|
|
699
|
+
private uniffiPublications(options: PythonReleaseOptions): readonly PythonPublication[] {
|
|
700
|
+
return this.packages
|
|
701
|
+
.filter((pkg) => pkg.packageOptions.uniffi === true)
|
|
702
|
+
.map((pkg) => ({
|
|
703
|
+
directory: pkg.packageOptions.directory,
|
|
704
|
+
distribution: pkg.packageOptions.name,
|
|
705
|
+
environment:
|
|
706
|
+
pkg.packageOptions.trustedPublisher?.environment ??
|
|
707
|
+
options.environments?.[pkg.packageOptions.name] ??
|
|
708
|
+
`pypi-${pkg.packageOptions.name}`,
|
|
709
|
+
workflowName: options.workflowName ?? "python-release",
|
|
710
|
+
artifacts: pkg.packageOptions.trustedPublisher?.artifacts,
|
|
711
|
+
dependencies: pkg.packageOptions.internalDependencies,
|
|
712
|
+
}));
|
|
713
|
+
}
|
|
714
|
+
|
|
656
715
|
private trustedPublisherPublications(
|
|
657
716
|
options: PythonReleaseOptions,
|
|
658
717
|
): readonly PythonPublication[] {
|
|
@@ -683,7 +742,10 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
683
742
|
const linesBeforeAuthentication = [
|
|
684
743
|
"# PyPI Trusted Publisher Setup Instructions",
|
|
685
744
|
"",
|
|
686
|
-
"Use
|
|
745
|
+
"Use the system browser to audit and configure the PyPI trusted publishers below.",
|
|
746
|
+
"Do not use an in-app browser or embedded webview.",
|
|
747
|
+
"Do not visit GitHub or use the GitHub API or CLI. Every required GitHub owner, repository, workflow, environment, and branch value is provided below and is authoritative.",
|
|
748
|
+
"Use only PyPI pages for this task.",
|
|
687
749
|
"",
|
|
688
750
|
"## Audit and confirmation",
|
|
689
751
|
"",
|
|
@@ -691,7 +753,7 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
691
753
|
"",
|
|
692
754
|
"- Confirm that the active PyPI account can administer the listed projects and pending publishers.",
|
|
693
755
|
"- Start at https://pypi.org/manage/projects/ and determine which listed projects exist.",
|
|
694
|
-
"-
|
|
756
|
+
"- On PyPI, inspect every existing GitHub Actions publisher for each project and compare its owner, repository name, workflow name, and environment name with the desired values below.",
|
|
695
757
|
"- Identify duplicate and mismatched trusted publishers that must be replaced by removing the publisher entry and adding the correct one.",
|
|
696
758
|
"- For projects that do not exist, identify the pending publisher that must be created.",
|
|
697
759
|
"- Report the active account and a proposed reconciliation plan grouped by publishers that will be left unchanged, updated, replaced, created, or removed.",
|
|
@@ -700,9 +762,9 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
700
762
|
"",
|
|
701
763
|
"## GitHub environment policy",
|
|
702
764
|
"",
|
|
703
|
-
`-
|
|
704
|
-
"-
|
|
705
|
-
"-
|
|
765
|
+
`- The supplied branch policy value is ${releaseBranch}.`,
|
|
766
|
+
"- Do not inspect or configure GitHub environments during this task.",
|
|
767
|
+
"- GitHub environment administration is a separate task; use the supplied values only when comparing PyPI publisher entries.",
|
|
706
768
|
"",
|
|
707
769
|
"## Authentication",
|
|
708
770
|
"",
|
|
@@ -714,7 +776,7 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
714
776
|
"",
|
|
715
777
|
"## Efficient browser workflow",
|
|
716
778
|
"",
|
|
717
|
-
"- Reuse
|
|
779
|
+
"- Reuse an existing PyPI tab in the system browser when available.",
|
|
718
780
|
"- For an existing project, open its publisher page directly at https://pypi.org/manage/project/<project-name>/settings/publishing/.",
|
|
719
781
|
"- For a project that does not exist, use the pending-publisher page at https://pypi.org/manage/account/publishing/.",
|
|
720
782
|
"- Treat the publisher table shown after submission as authoritative confirmation of success, even if the navigation header unexpectedly appears signed out.",
|
|
@@ -769,7 +831,7 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
769
831
|
],
|
|
770
832
|
});
|
|
771
833
|
project.root.addTask("pypiTrustedPublisherInstructions", {
|
|
772
|
-
description: "Print browser
|
|
834
|
+
description: "Print system-browser instructions for PyPI trusted publishers",
|
|
773
835
|
exec: `node ${helper}`,
|
|
774
836
|
receiveArgs: true,
|
|
775
837
|
});
|