@dbx-tools/projen 0.6.176 → 0.6.179
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 +47 -35
- package/index.ts +3 -3
- package/package.json +4 -4
- package/src/project-js.ts +7 -16
- package/src/project-py.ts +47 -249
- package/src/project-rs.ts +210 -244
- package/src/release-dispatch.ts +9 -11
- package/src/release.ts +313 -631
- package/tasks/publish-npm.ts +197 -0
- package/tasks/publish.ts +38 -1
- package/tasks/stamp-python.ts +13 -0
package/README.md
CHANGED
|
@@ -128,22 +128,36 @@ removing a crate or `setup_scaffolding!()` marker triggers a full synth. Repos
|
|
|
128
128
|
without Rust crates start no Rust watcher. When Rust projects are detected,
|
|
129
129
|
Cargo is required and the focused task fails immediately if it is unavailable.
|
|
130
130
|
|
|
131
|
-
The workspace
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
131
|
+
The workspace generates one `release.yml` workflow for every ecosystem. An
|
|
132
|
+
annotated `v*` tag starts it directly. The context job resolves the tag to a
|
|
133
|
+
commit, requires the tag object to be annotated, and exposes the verified tag,
|
|
134
|
+
commit, and version to every source job. A manual run accepts that same tag and
|
|
135
|
+
commit but requires dry-run mode, so it builds and validates without publishing
|
|
136
|
+
packages or deploying documentation. One `release` concurrency group cancels a
|
|
137
|
+
superseded run.
|
|
138
|
+
|
|
139
|
+
Release generation writes `release.yml` without scanning for or removing other
|
|
140
|
+
workflow files. Consumers explicitly delete exact workflow files they no longer
|
|
141
|
+
want.
|
|
142
|
+
|
|
143
|
+
Failed-job reruns consume successful Rust artifacts from the same workflow run.
|
|
144
|
+
For a separate recovery run, choose `node`, `python`, or `docs` instead of
|
|
145
|
+
`all`. Node and Python recovery can supply the prior `release.yml` run ID; the
|
|
146
|
+
workflow verifies that run used the commit selected by the annotated release
|
|
147
|
+
tag before downloading its artifacts. Dispatch the workflow with the release
|
|
148
|
+
tag as its Git ref so environment tag policies still apply. Manual recovery
|
|
149
|
+
defaults to dry-run and publishes only when `dry_run` is cleared. npm retries skip an exact version only
|
|
150
|
+
after the local archive integrity and repository identity match registry
|
|
151
|
+
metadata. PyPI retries enable Twine's hash-aware existing-file behavior, which
|
|
152
|
+
skips matching files and fails when an existing filename has different content.
|
|
153
|
+
|
|
154
|
+
The Rust matrix has one row per target. Each row installs native dependencies,
|
|
155
|
+
restores Cargo and sccache once, builds the Cargo workspace once, then packages
|
|
156
|
+
every discovered output from that shared build. Rust rows prepare native npm
|
|
157
|
+
archives and Python wheels; they do not install Bun or UBRN and do not build
|
|
158
|
+
Node facades. A binary-only row therefore installs no language package tool.
|
|
159
|
+
`rustVersion` remains the MSRV recorded in package manifests, while
|
|
160
|
+
`releaseRustVersion` independently defaults release compilation to `stable`.
|
|
147
161
|
Stable Windows rows verify and use the hosted runner's installed Rust toolchain
|
|
148
162
|
and select `rust-lld` for the workspace build. Cargo registry caches
|
|
149
163
|
and the `SCCACHE_GHA_VERSION` namespace stay stable per target/toolchain across
|
|
@@ -152,10 +166,9 @@ are written to each build log. Python generation executes the already-built
|
|
|
152
166
|
`target/<triple>/release/<crate>-uniffi-bindgen` directly. Artifact packaging therefore
|
|
153
167
|
does no Rust compilation after the main workspace build.
|
|
154
168
|
|
|
155
|
-
Artifacts identify their crate, target, and type.
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
with the tag and SHA. It never publishes npm or PyPI packages.
|
|
169
|
+
Artifacts identify their crate, target, and type. Rust jobs publish non-private
|
|
170
|
+
Cargo crates with `cargo publish --no-verify` and upload requested binary assets
|
|
171
|
+
to the GitHub release. Rust jobs never publish npm or PyPI packages.
|
|
159
172
|
|
|
160
173
|
Set `LOCAL_CARGO_REGISTRY` to a named Cargo registry such as a loopback
|
|
161
174
|
[Kellnr](https://kellnr.io/) instance and provide `LOCAL_CARGO_TOKEN`. Public
|
|
@@ -170,21 +183,20 @@ environment parsing in a consumer.
|
|
|
170
183
|
|
|
171
184
|
Public UniFFI facades are marked with `dbxToolsConfig.uniffi = true` in Node
|
|
172
185
|
manifests and `[tool.dbx_tools.config] uniffi = true` in Python manifests. The
|
|
173
|
-
Node
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
its
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
verifies.
|
|
186
|
+
Node jobs consume same-run artifacts, publish native archives first with npm
|
|
187
|
+
provenance, compile and publish normal workspace packages including the Projen
|
|
188
|
+
engine, then build facades from committed generated TypeScript without UBRN and
|
|
189
|
+
publish them in binding dependency order. Local Verdaccio publication does not
|
|
190
|
+
enable provenance. Set the `UNIFFI_FACADE_SMOKE` repository variable to `true`
|
|
191
|
+
to run the optional nonblocking registry install and import check after facade
|
|
192
|
+
publication. Python combines same-run platform wheels with standard wheel and
|
|
193
|
+
source builds, then publishes each distribution through its own PyPI
|
|
194
|
+
trusted-publisher environment. Binding publishers wait for their dependencies.
|
|
195
|
+
Trusted-publisher instructions name `release.yml` and the release tag policy.
|
|
196
|
+
The docs jobs generate README and TypeScript API content and deploy GitHub Pages
|
|
197
|
+
from the same workflow. When a conventional Node binding path already belongs
|
|
198
|
+
to a root subproject, Rust mapping reuses that project and adds binding
|
|
199
|
+
dependencies and metadata to its existing manifest.
|
|
188
200
|
|
|
189
201
|
## Customize Packages With Mixins
|
|
190
202
|
|
package/index.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Hand edits are overwritten on the next watch; this file is read-only.
|
|
4
4
|
|
|
5
5
|
export const PACKAGE_IDENTIFIER = "@dbx-tools/projen";
|
|
6
|
-
export const PACKAGE_VERSION = "0.6.
|
|
6
|
+
export const PACKAGE_VERSION = "0.6.178";
|
|
7
7
|
export * as barrels from "./src/barrels.ts";
|
|
8
8
|
export * as bunApp from "./src/bun-app.ts";
|
|
9
9
|
export * as bunWorkflow from "./src/bun-workflow.ts";
|
|
@@ -54,8 +54,8 @@ export { RustReleaseOs, RustReleaseCpu, UNIFFI_RELEASE_TARGETS, DBXToolsRustProj
|
|
|
54
54
|
export type { CargoDependencyOptions, CargoDependency, RustPackageOptions, DBXToolsRustWorkspaceOptions, RustReleasePlatform, UniFFIReleaseTarget, RustBindingMapping, RustWorkspaceMapping } from "./src/project-rs.ts";
|
|
55
55
|
export { COMPILED_DIR, COMPILED_COMPILER_OPTIONS } from "./src/publish.ts";
|
|
56
56
|
export { DBXToolsRelease } from "./src/release.ts";
|
|
57
|
-
export type {
|
|
58
|
-
export {
|
|
57
|
+
export type { ReleaseStage, ReleaseDocsOptions, DBXToolsReleaseOptions } from "./src/release.ts";
|
|
58
|
+
export { RELEASE_TAG, RELEASE_SHA, RELEASE_VERSION } from "./src/release-dispatch.ts";
|
|
59
59
|
export { AGNOSTIC_COMPILER_OPTIONS, PACKAGE_TAG_MIXINS } from "./src/tags.ts";
|
|
60
60
|
export type { PackageTag } from "./src/tags.ts";
|
|
61
61
|
export { DBXToolsRootTsconfig } from "./src/tsconfig.ts";
|
package/package.json
CHANGED
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@clack/prompts": "^1.7.0",
|
|
28
|
-
"@dbx-tools/core": "0.6.
|
|
29
|
-
"@dbx-tools/path": "0.6.
|
|
30
|
-
"@dbx-tools/shared-core": "0.6.
|
|
28
|
+
"@dbx-tools/core": "0.6.179",
|
|
29
|
+
"@dbx-tools/path": "0.6.179",
|
|
30
|
+
"@dbx-tools/shared-core": "0.6.179",
|
|
31
31
|
"commander": "^15.0.0",
|
|
32
32
|
"concurrently": "^10.0.3",
|
|
33
33
|
"constructs": "^10.6.0",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
},
|
|
48
48
|
"main": "index.ts",
|
|
49
49
|
"license": "Apache-2.0",
|
|
50
|
-
"version": "0.6.
|
|
50
|
+
"version": "0.6.179",
|
|
51
51
|
"types": "index.ts",
|
|
52
52
|
"type": "module",
|
|
53
53
|
"exports": {
|
package/src/project-js.ts
CHANGED
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
import { PnpmWorkspaceState, type DBXToolsPNPMWorkspaceOptions } from "./pnpm-workspace.ts";
|
|
41
41
|
import type { DBXToolsProject, DBXToolsProjectOptions as CommonProjectOptions } from "./project.ts";
|
|
42
42
|
import { applyCompiledPublish } from "./publish.ts";
|
|
43
|
-
import { DBXToolsRelease, type
|
|
43
|
+
import { DBXToolsRelease, type ReleaseDocsOptions } from "./release.ts";
|
|
44
44
|
import { AGNOSTIC_COMPILER_OPTIONS, PACKAGE_TAG_MIXINS, type PackageTag } from "./tags.ts";
|
|
45
45
|
import { DBXToolsRootTsconfig } from "./tsconfig.ts";
|
|
46
46
|
import { DBXToolsVsCode } from "./vscode.ts";
|
|
@@ -549,18 +549,10 @@ export interface DBXToolsJavaScriptProjectOptions
|
|
|
549
549
|
* (alongside `.projenrc.ts`). Repo-relative, e.g. `".example.projenrc.ts"`.
|
|
550
550
|
*/
|
|
551
551
|
readonly syncResynthPaths?: readonly string[];
|
|
552
|
-
/**
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
* repo subdirectory but releases on its own tag prefix (e.g. the
|
|
557
|
-
* `@dbx-tools/projen` engine in `projen/`, tagged `projen-v*`).
|
|
558
|
-
*/
|
|
559
|
-
readonly standaloneReleases?: readonly StandaloneRelease[];
|
|
560
|
-
/** Workflow that must finish successfully before the main Node release runs. */
|
|
561
|
-
readonly releaseUpstreamWorkflow?: string;
|
|
562
|
-
/** Main Node release workflow name. Defaults to `node-release`. */
|
|
563
|
-
readonly nodeReleaseWorkflowName?: string | false;
|
|
552
|
+
/** GitHub Pages documentation included in the unified release workflow. */
|
|
553
|
+
readonly releaseDocs?: ReleaseDocsOptions;
|
|
554
|
+
/** Set to `false` to omit normal npm workspace publication. */
|
|
555
|
+
readonly nodeRelease?: boolean;
|
|
564
556
|
/**
|
|
565
557
|
* Extra workspace member paths (repo-relative, POSIX) to list in the workspace
|
|
566
558
|
* config ALONGSIDE the discovered `packageRoots` members - for a package that
|
|
@@ -1264,9 +1256,8 @@ function initProject(
|
|
|
1264
1256
|
// authors. Independent of projen's own `release` component.
|
|
1265
1257
|
new DBXToolsRelease(project as DBXToolsNodeProject, {
|
|
1266
1258
|
tagPrefix: options.releaseTagPrefix,
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
workflowName: options.nodeReleaseWorkflowName ?? options.releaseWorkflowName,
|
|
1259
|
+
nodeRelease: options.nodeRelease,
|
|
1260
|
+
docs: options.releaseDocs,
|
|
1270
1261
|
});
|
|
1271
1262
|
}
|
|
1272
1263
|
|
package/src/project-py.ts
CHANGED
|
@@ -3,13 +3,20 @@ import { project as coreProject } from "@dbx-tools/core";
|
|
|
3
3
|
import { string } from "@dbx-tools/shared-core";
|
|
4
4
|
import { Component, TextFile, type Project, javascript, python, vscode } from "projen";
|
|
5
5
|
import type { IResolver } from "projen/lib/file";
|
|
6
|
-
import { GithubWorkflow } from "projen/lib/github";
|
|
7
6
|
import { JobPermission } from "projen/lib/github/workflows-model";
|
|
8
7
|
import { parse, stringify } from "smol-toml";
|
|
9
|
-
import {
|
|
8
|
+
import { BUN_VERSION, bunCacheRestoreSteps, bunCacheSaveStep } from "./bun-workflow.ts";
|
|
9
|
+
import { projectRepositoryUrl } from "./project-js.ts";
|
|
10
10
|
import { isDBXToolsJavaScriptProject } from "./project-predicate.ts";
|
|
11
11
|
import type { DBXToolsProject, DBXToolsProjectOptions } from "./project.ts";
|
|
12
|
-
import {
|
|
12
|
+
import { RELEASE_VERSION, releaseSourceSteps } from "./release-dispatch.ts";
|
|
13
|
+
import {
|
|
14
|
+
releaseArtifactSteps,
|
|
15
|
+
releasePublishCondition,
|
|
16
|
+
releaseStageCondition,
|
|
17
|
+
releaseTagPattern,
|
|
18
|
+
releaseWorkflow,
|
|
19
|
+
} from "./release.ts";
|
|
13
20
|
import { readWorkspaceVersion } from "./workspace-version.ts";
|
|
14
21
|
|
|
15
22
|
/** Git location used by direct `#subdirectory=` package dependencies. */
|
|
@@ -44,7 +51,6 @@ interface ResolvedPythonPackageOptions extends PythonPackageOptions {
|
|
|
44
51
|
|
|
45
52
|
/** GitHub Actions publisher for a Python package released by another workflow. */
|
|
46
53
|
export interface PythonTrustedPublisherOptions {
|
|
47
|
-
readonly workflowName: string;
|
|
48
54
|
readonly environment: string;
|
|
49
55
|
readonly artifacts?: string;
|
|
50
56
|
}
|
|
@@ -61,9 +67,6 @@ export interface DBXToolsPythonProjectOptions extends DBXToolsProjectOptions {
|
|
|
61
67
|
|
|
62
68
|
/** Python release workflow configuration. */
|
|
63
69
|
export interface PythonReleaseOptions {
|
|
64
|
-
readonly workflowName?: string;
|
|
65
|
-
/** Run after this workflow completes successfully instead of directly on tags. */
|
|
66
|
-
readonly upstreamWorkflow?: string;
|
|
67
70
|
/** GitHub environment by Python distribution name. Defaults to `pypi-<name>`. */
|
|
68
71
|
readonly environments?: Readonly<Record<string, string>>;
|
|
69
72
|
readonly environmentUrl?: string;
|
|
@@ -73,7 +76,6 @@ interface PythonPublication {
|
|
|
73
76
|
readonly directory: string;
|
|
74
77
|
readonly distribution: string;
|
|
75
78
|
readonly environment: string;
|
|
76
|
-
readonly workflowName: string;
|
|
77
79
|
readonly artifacts?: string;
|
|
78
80
|
readonly dependencies?: readonly string[];
|
|
79
81
|
}
|
|
@@ -321,10 +323,6 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
321
323
|
}
|
|
322
324
|
|
|
323
325
|
if (options.release && this.packages.length > 0) {
|
|
324
|
-
if (isDBXToolsJavaScriptProject()(project)) {
|
|
325
|
-
project.dbxToolsConfig.pythonReleaseWorkflow =
|
|
326
|
-
releaseOptions.workflowName ?? "python-release";
|
|
327
|
-
}
|
|
328
326
|
this.addReleaseWorkflow(project, releaseOptions);
|
|
329
327
|
}
|
|
330
328
|
}
|
|
@@ -427,193 +425,40 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
427
425
|
}
|
|
428
426
|
|
|
429
427
|
private addReleaseWorkflow(project: javascript.NodeProject, options: PythonReleaseOptions): void {
|
|
430
|
-
if (!project.github) return;
|
|
428
|
+
if (!project.github || !isDBXToolsJavaScriptProject()(project)) return;
|
|
431
429
|
const publications = this.publications(options);
|
|
432
430
|
const uniffiPublications = this.uniffiPublications(options);
|
|
433
431
|
const allPublications = [...publications, ...uniffiPublications];
|
|
434
432
|
if (allPublications.length === 0) return;
|
|
435
433
|
const usesRustArtifacts = uniffiPublications.length > 0;
|
|
436
|
-
const
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
contents: "read",
|
|
443
|
-
...(options.upstreamWorkflow || usesRustArtifacts ? { actions: "read" } : {}),
|
|
444
|
-
});
|
|
445
|
-
const upstreamWorkflow = options.upstreamWorkflow;
|
|
446
|
-
const branchDispatch = upstreamWorkflow === undefined && isDBXToolsJavaScriptProject()(project);
|
|
447
|
-
if (upstreamWorkflow) {
|
|
448
|
-
workflow.file?.addOverride("on.workflow_run", {
|
|
449
|
-
workflows: [upstreamWorkflow],
|
|
450
|
-
types: ["completed"],
|
|
451
|
-
});
|
|
452
|
-
workflow.on({ workflowDispatch: {} });
|
|
453
|
-
} else if (branchDispatch) {
|
|
454
|
-
workflow.file?.addOverride("on.repository_dispatch", {
|
|
455
|
-
types: [DOWNSTREAM_RELEASE_EVENT],
|
|
456
|
-
});
|
|
457
|
-
workflow.on({ workflowDispatch: {} });
|
|
458
|
-
} else {
|
|
459
|
-
workflow.on({ push: { tags: ["v*"] }, workflowDispatch: {} });
|
|
460
|
-
}
|
|
461
|
-
workflow.file?.addOverride("on.workflow_dispatch", {
|
|
462
|
-
inputs: {
|
|
463
|
-
...(branchDispatch
|
|
464
|
-
? {
|
|
465
|
-
release_tag: {
|
|
466
|
-
description: "Release tag to package during a dry run",
|
|
467
|
-
type: "string",
|
|
468
|
-
required: true,
|
|
469
|
-
},
|
|
470
|
-
expected_sha: {
|
|
471
|
-
description: "Commit the release tag must reference",
|
|
472
|
-
type: "string",
|
|
473
|
-
required: true,
|
|
474
|
-
},
|
|
475
|
-
}
|
|
476
|
-
: {
|
|
477
|
-
version: {
|
|
478
|
-
description: "Python package version to build",
|
|
479
|
-
type: "string",
|
|
480
|
-
required: true,
|
|
481
|
-
},
|
|
482
|
-
}),
|
|
483
|
-
},
|
|
484
|
-
});
|
|
485
|
-
workflow.addJob("build", {
|
|
486
|
-
...(upstreamWorkflow
|
|
487
|
-
? {
|
|
488
|
-
if: "${{ github.event_name != 'workflow_run' || (github.event.workflow_run.conclusion == 'success' && (github.event.workflow_run.event == 'push' || github.event.workflow_run.event == 'repository_dispatch')) }}",
|
|
489
|
-
}
|
|
490
|
-
: {}),
|
|
434
|
+
const workflow = releaseWorkflow(project);
|
|
435
|
+
workflow.addJob("build-python", {
|
|
436
|
+
if: usesRustArtifacts
|
|
437
|
+
? "${{ 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 == 'python') }}"
|
|
438
|
+
: releaseStageCondition("python"),
|
|
439
|
+
needs: ["verify-context", ...(usesRustArtifacts ? ["rust-build"] : [])],
|
|
491
440
|
runsOn: ["ubuntu-latest"],
|
|
492
|
-
permissions: {
|
|
493
|
-
contents: JobPermission.READ,
|
|
494
|
-
...(upstreamWorkflow || usesRustArtifacts ? { actions: JobPermission.READ } : {}),
|
|
495
|
-
},
|
|
441
|
+
permissions: { actions: JobPermission.READ, contents: JobPermission.READ },
|
|
496
442
|
timeoutMinutes: 20,
|
|
443
|
+
env: { BUN_VERSION },
|
|
497
444
|
steps: [
|
|
498
|
-
...(
|
|
499
|
-
|
|
500
|
-
{
|
|
501
|
-
name: "Download release metadata",
|
|
502
|
-
if: "${{ github.event_name == 'workflow_run' && github.event.workflow_run.event == 'repository_dispatch' }}",
|
|
503
|
-
uses: "actions/download-artifact@v8",
|
|
504
|
-
with: {
|
|
505
|
-
name: "release-metadata",
|
|
506
|
-
path: ".release",
|
|
507
|
-
"run-id": "${{ github.event.workflow_run.id }}",
|
|
508
|
-
"github-token": "${{ github.token }}",
|
|
509
|
-
},
|
|
510
|
-
},
|
|
511
|
-
{
|
|
512
|
-
name: "Read release metadata",
|
|
513
|
-
id: "release_metadata",
|
|
514
|
-
if: "${{ github.event_name == 'workflow_run' && github.event.workflow_run.event == 'repository_dispatch' }}",
|
|
515
|
-
shell: "bash",
|
|
516
|
-
run: [
|
|
517
|
-
'RELEASE_TAG="$(cat .release/tag)"',
|
|
518
|
-
'EXPECTED_SHA="$(cat .release/sha)"',
|
|
519
|
-
'test -n "$RELEASE_TAG"',
|
|
520
|
-
'test -n "$EXPECTED_SHA"',
|
|
521
|
-
'echo "release_tag=$RELEASE_TAG" >> "$GITHUB_OUTPUT"',
|
|
522
|
-
'echo "expected_sha=$EXPECTED_SHA" >> "$GITHUB_OUTPUT"',
|
|
523
|
-
].join("\n"),
|
|
524
|
-
},
|
|
525
|
-
]
|
|
526
|
-
: []),
|
|
527
|
-
...(branchDispatch
|
|
528
|
-
? releaseSourceSteps()
|
|
529
|
-
: [
|
|
530
|
-
{
|
|
531
|
-
name: "Checkout",
|
|
532
|
-
uses: "actions/checkout@v6",
|
|
533
|
-
with: {
|
|
534
|
-
"fetch-depth": 0,
|
|
535
|
-
...(upstreamWorkflow
|
|
536
|
-
? {
|
|
537
|
-
ref: "${{ github.event_name == 'workflow_run' && github.event.workflow_run.event == 'repository_dispatch' && steps.release_metadata.outputs.expected_sha || github.event_name == 'workflow_run' && github.event.workflow_run.head_sha || github.sha }}",
|
|
538
|
-
}
|
|
539
|
-
: {}),
|
|
540
|
-
},
|
|
541
|
-
},
|
|
542
|
-
]),
|
|
543
|
-
...(upstreamWorkflow
|
|
544
|
-
? [
|
|
545
|
-
{
|
|
546
|
-
name: "Verify release source",
|
|
547
|
-
if: "${{ github.event_name == 'workflow_run' && github.event.workflow_run.event == 'repository_dispatch' }}",
|
|
548
|
-
shell: "bash",
|
|
549
|
-
env: {
|
|
550
|
-
RELEASE_TAG: "${{ steps.release_metadata.outputs.release_tag }}",
|
|
551
|
-
EXPECTED_SHA: "${{ steps.release_metadata.outputs.expected_sha }}",
|
|
552
|
-
},
|
|
553
|
-
run: [
|
|
554
|
-
'git fetch --force origin "+refs/tags/$RELEASE_TAG:refs/tags/$RELEASE_TAG"',
|
|
555
|
-
'test "$(git rev-parse "$RELEASE_TAG^{commit}")" = "$EXPECTED_SHA"',
|
|
556
|
-
'test "$(git rev-parse HEAD)" = "$EXPECTED_SHA"',
|
|
557
|
-
].join("\n"),
|
|
558
|
-
},
|
|
559
|
-
]
|
|
560
|
-
: []),
|
|
445
|
+
...releaseSourceSteps(),
|
|
446
|
+
...bunCacheRestoreSteps(project),
|
|
561
447
|
{ name: "Setup uv", uses: "astral-sh/setup-uv@v7" },
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
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: {
|
|
448
|
+
{ name: "Install release helpers", run: "bun install" },
|
|
449
|
+
bunCacheSaveStep(),
|
|
450
|
+
...uniffiPublications.flatMap((publication) =>
|
|
451
|
+
releaseArtifactSteps({
|
|
452
|
+
currentName: `Download ${publication.distribution} native wheels`,
|
|
453
|
+
recoveredName: `Download recovered ${publication.distribution} native wheels`,
|
|
583
454
|
pattern: `${publication.distribution}--*--python-wheel`,
|
|
584
455
|
path: `dist/${publication.directory}`,
|
|
585
|
-
|
|
586
|
-
|
|
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
|
-
})),
|
|
456
|
+
}),
|
|
457
|
+
),
|
|
591
458
|
{
|
|
592
459
|
name: "Stamp workspace versions",
|
|
593
|
-
env: {
|
|
594
|
-
|
|
595
|
-
? RELEASE_TAG
|
|
596
|
-
: "${{ github.event_name == 'push' && github.ref_name || github.event_name == 'workflow_run' && github.event.workflow_run.event == 'repository_dispatch' && steps.release_metadata.outputs.release_tag || inputs.version }}",
|
|
597
|
-
},
|
|
598
|
-
run: upstreamWorkflow
|
|
599
|
-
? [
|
|
600
|
-
'if [ "$GITHUB_EVENT_NAME" = "workflow_run" ]; then',
|
|
601
|
-
' if [ "${{ github.event.workflow_run.event }}" != "repository_dispatch" ]; then',
|
|
602
|
-
' VERSION="$(git tag --points-at HEAD --list "v*" | sort -V | tail -1)"',
|
|
603
|
-
" fi",
|
|
604
|
-
' test -n "$VERSION"',
|
|
605
|
-
"fi",
|
|
606
|
-
this.renderVersionStampScript(),
|
|
607
|
-
"mkdir -p .release",
|
|
608
|
-
'printf "%s\\n" "$VERSION" > .release/tag',
|
|
609
|
-
"git rev-parse HEAD > .release/sha",
|
|
610
|
-
].join("\n")
|
|
611
|
-
: [
|
|
612
|
-
this.renderVersionStampScript(),
|
|
613
|
-
"mkdir -p .release",
|
|
614
|
-
'printf "%s\\n" "$VERSION" > .release/tag',
|
|
615
|
-
"git rev-parse HEAD > .release/sha",
|
|
616
|
-
].join("\n"),
|
|
460
|
+
env: { VERSION: RELEASE_VERSION },
|
|
461
|
+
run: `bun node_modules/@dbx-tools/projen/tasks/stamp-python.ts "$VERSION" --root ${quote(this.repository.root)}`,
|
|
617
462
|
},
|
|
618
463
|
{
|
|
619
464
|
name: "Build distributions",
|
|
@@ -633,7 +478,7 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
633
478
|
),
|
|
634
479
|
...uniffiPublications.map(
|
|
635
480
|
(publication) =>
|
|
636
|
-
`
|
|
481
|
+
`find dist/${publication.directory} -maxdepth 1 -name '*.whl' -print -quit | grep -q .`,
|
|
637
482
|
),
|
|
638
483
|
"find dist -type f \\( -name '*.whl' -o -name '*.tar.gz' \\) -print0 | xargs -0 uvx twine check",
|
|
639
484
|
].join("\n"),
|
|
@@ -641,23 +486,17 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
641
486
|
{
|
|
642
487
|
name: "Upload distributions",
|
|
643
488
|
uses: "actions/upload-artifact@v7",
|
|
644
|
-
with: { name: "python-distributions", path: "dist" },
|
|
645
|
-
},
|
|
646
|
-
{
|
|
647
|
-
name: "Upload release metadata",
|
|
648
|
-
uses: "actions/upload-artifact@v7",
|
|
649
|
-
with: { name: "release-metadata", path: ".release" },
|
|
489
|
+
with: { name: "python-distributions", path: "dist", "retention-days": 7 },
|
|
650
490
|
},
|
|
651
491
|
],
|
|
652
492
|
});
|
|
653
493
|
for (const publication of allPublications) {
|
|
654
|
-
workflow.addJob(`publish-${publication.directory}`, {
|
|
655
|
-
if:
|
|
656
|
-
? "${{ github.event_name == 'repository_dispatch' }}"
|
|
657
|
-
: "${{ github.event_name == 'push' || github.event_name == 'workflow_run' }}",
|
|
494
|
+
workflow.addJob(`publish-pypi-${publication.directory}`, {
|
|
495
|
+
if: releasePublishCondition("python"),
|
|
658
496
|
needs: [
|
|
659
|
-
"
|
|
660
|
-
|
|
497
|
+
"verify-context",
|
|
498
|
+
"build-python",
|
|
499
|
+
...(publication.dependencies ?? []).map((dependency) => `publish-pypi-${dependency}`),
|
|
661
500
|
],
|
|
662
501
|
environment: {
|
|
663
502
|
name: publication.environment,
|
|
@@ -677,7 +516,10 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
677
516
|
{
|
|
678
517
|
name: `Publish ${publication.distribution} to PyPI`,
|
|
679
518
|
uses: "pypa/gh-action-pypi-publish@release/v1",
|
|
680
|
-
with: {
|
|
519
|
+
with: {
|
|
520
|
+
"packages-dir": `dist/${publication.directory}`,
|
|
521
|
+
"skip-existing": true,
|
|
522
|
+
},
|
|
681
523
|
},
|
|
682
524
|
],
|
|
683
525
|
});
|
|
@@ -692,7 +534,6 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
692
534
|
distribution: pkg.packageOptions.name,
|
|
693
535
|
environment:
|
|
694
536
|
options.environments?.[pkg.packageOptions.name] ?? `pypi-${pkg.packageOptions.name}`,
|
|
695
|
-
workflowName: options.workflowName ?? "python-release",
|
|
696
537
|
}));
|
|
697
538
|
}
|
|
698
539
|
|
|
@@ -706,7 +547,6 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
706
547
|
pkg.packageOptions.trustedPublisher?.environment ??
|
|
707
548
|
options.environments?.[pkg.packageOptions.name] ??
|
|
708
549
|
`pypi-${pkg.packageOptions.name}`,
|
|
709
|
-
workflowName: options.workflowName ?? "python-release",
|
|
710
550
|
artifacts: pkg.packageOptions.trustedPublisher?.artifacts,
|
|
711
551
|
dependencies: pkg.packageOptions.internalDependencies,
|
|
712
552
|
}));
|
|
@@ -725,7 +565,6 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
725
565
|
directory: pkg.packageOptions.directory,
|
|
726
566
|
distribution: pkg.packageOptions.name,
|
|
727
567
|
environment: publisher.environment,
|
|
728
|
-
workflowName: publisher.workflowName,
|
|
729
568
|
artifacts: publisher.artifacts,
|
|
730
569
|
});
|
|
731
570
|
}
|
|
@@ -738,13 +577,13 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
738
577
|
): void {
|
|
739
578
|
const repository = this.githubRepository();
|
|
740
579
|
const publications = this.trustedPublisherPublications(options);
|
|
741
|
-
const
|
|
580
|
+
const releaseTags = isDBXToolsJavaScriptProject()(project) ? releaseTagPattern(project) : "v*";
|
|
742
581
|
const linesBeforeAuthentication = [
|
|
743
582
|
"# PyPI Trusted Publisher Setup Instructions",
|
|
744
583
|
"",
|
|
745
584
|
"Use the system browser to audit and configure the PyPI trusted publishers below.",
|
|
746
585
|
"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
|
|
586
|
+
"Do not visit GitHub or use the GitHub API or CLI. Every required GitHub owner, repository, workflow, environment, and tag value is provided below and is authoritative.",
|
|
748
587
|
"Use only PyPI pages for this task.",
|
|
749
588
|
"",
|
|
750
589
|
"## Audit and confirmation",
|
|
@@ -762,7 +601,7 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
762
601
|
"",
|
|
763
602
|
"## GitHub environment policy",
|
|
764
603
|
"",
|
|
765
|
-
`- The supplied
|
|
604
|
+
`- The supplied tag policy value is ${releaseTags}.`,
|
|
766
605
|
"- Do not inspect or configure GitHub environments during this task.",
|
|
767
606
|
"- GitHub environment administration is a separate task; use the supplied values only when comparing PyPI publisher entries.",
|
|
768
607
|
"",
|
|
@@ -797,14 +636,13 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
797
636
|
"Publisher type: GitHub Actions",
|
|
798
637
|
"",
|
|
799
638
|
...publications.flatMap((publication) => {
|
|
800
|
-
const workflowName = `${publication.workflowName}.yml`;
|
|
801
639
|
return [
|
|
802
640
|
`## ${publication.distribution}`,
|
|
803
641
|
`- Owner: ${repository.owner}`,
|
|
804
642
|
`- Repository name: ${repository.name}`,
|
|
805
|
-
|
|
643
|
+
"- Workflow name: release.yml",
|
|
806
644
|
`- Environment name: ${publication.environment}`,
|
|
807
|
-
`- GitHub environment
|
|
645
|
+
`- GitHub environment tag: ${releaseTags}`,
|
|
808
646
|
...(publication.artifacts ? [`- Artifacts: ${publication.artifacts}`] : []),
|
|
809
647
|
"",
|
|
810
648
|
];
|
|
@@ -846,44 +684,4 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
846
684
|
}
|
|
847
685
|
return { owner: match[1], name: match[2] };
|
|
848
686
|
}
|
|
849
|
-
|
|
850
|
-
private renderVersionStampScript(): string {
|
|
851
|
-
return [
|
|
852
|
-
`chmod -R u+w ${this.repository.root}`,
|
|
853
|
-
"python - <<'PY'",
|
|
854
|
-
"from pathlib import Path",
|
|
855
|
-
"import os",
|
|
856
|
-
"import re",
|
|
857
|
-
"",
|
|
858
|
-
'version = os.environ["VERSION"].removeprefix("v")',
|
|
859
|
-
`package_files = sorted(Path(${quote(this.repository.root)}).glob("*/pyproject.toml"))`,
|
|
860
|
-
"packages = {}",
|
|
861
|
-
"for path in package_files:",
|
|
862
|
-
' source = path.read_text(encoding="utf-8")',
|
|
863
|
-
' name = re.search(r\'^name = "([^"]+)"$\', source, re.MULTILINE)',
|
|
864
|
-
" if name is None:",
|
|
865
|
-
' raise ValueError(f"Missing project name in {path}")',
|
|
866
|
-
" packages[name.group(1)] = path.parent.name",
|
|
867
|
-
"",
|
|
868
|
-
"for path in package_files:",
|
|
869
|
-
' source = path.read_text(encoding="utf-8")',
|
|
870
|
-
" source, count = re.subn(",
|
|
871
|
-
' r\'^version = "[^"]+"$\',',
|
|
872
|
-
" f'version = \"{version}\"',",
|
|
873
|
-
" source,",
|
|
874
|
-
" count=1,",
|
|
875
|
-
" flags=re.MULTILINE,",
|
|
876
|
-
" )",
|
|
877
|
-
" if count != 1:",
|
|
878
|
-
' raise ValueError(f"Expected one project version in {path}")',
|
|
879
|
-
" for name, directory in packages.items():",
|
|
880
|
-
" source = re.sub(",
|
|
881
|
-
` rf'{re.escape(name)} @ git\\+[^" ]+#subdirectory=${this.repository.root}/{re.escape(directory)}',`,
|
|
882
|
-
' f"{name}=={version}",',
|
|
883
|
-
" source,",
|
|
884
|
-
" )",
|
|
885
|
-
' path.write_text(source, encoding="utf-8")',
|
|
886
|
-
"PY",
|
|
887
|
-
].join("\n");
|
|
888
|
-
}
|
|
889
687
|
}
|