@dbx-tools/projen 0.6.228 → 0.6.230
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 +54 -85
- package/index.ts +9 -1
- package/package.json +8 -5
- package/src/openapi.ts +9 -1
- package/src/project-js.ts +65 -10
- package/src/project-py.ts +133 -4
- package/src/project-rs.ts +392 -25
- package/src/release-catalog.ts +832 -0
- package/src/release-dispatch.ts +3 -2
- package/src/release-plan.ts +236 -0
- package/src/release-please.ts +242 -0
- package/src/release.ts +385 -0
- package/tasks/publish-npm.ts +4 -4
- package/tasks/publish-python.ts +56 -14
- package/tasks/publish.ts +60 -30
- package/tasks/release-bootstrap.ts +59 -0
- package/tasks/release-plan.ts +89 -0
- package/tasks/release-please.ts +163 -0
- package/tasks/release-summary-units.ts +44 -0
- package/tasks/release-summary.ts +33 -7
- package/tasks/uniffi-python.d.ts +5 -0
- package/tasks/uniffi-python.js +21 -2
- package/tasks/uniffi-release.mjs +8 -3
- package/tasks/version-check.ts +43 -15
package/README.md
CHANGED
|
@@ -173,30 +173,26 @@ a host Rust build. Regenerate bindings through the focused watcher or explicit
|
|
|
173
173
|
task while changing a UniFFI API. Release preparation runs Cargo workspace tests
|
|
174
174
|
without invoking UBRN.
|
|
175
175
|
|
|
176
|
-
The workspace generates one `release.yml` workflow for every ecosystem.
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
packages or deploying documentation. One non-cancelling `release` concurrency
|
|
184
|
-
group serializes publication.
|
|
176
|
+
The workspace generates one `release.yml` workflow for every ecosystem.
|
|
177
|
+
Independent mode runs Release Please on default-branch pushes. It owns the
|
|
178
|
+
combined release PR, per-component semantic increments, component-qualified
|
|
179
|
+
tags, and GitHub Releases. A Projen reconciliation pass reads the reviewed
|
|
180
|
+
manifest, regenerates every owned version surface, validates a clean second
|
|
181
|
+
synthesis, and commits component-qualified release notes to the release PR.
|
|
182
|
+
One non-cancelling `release` concurrency group serializes publication.
|
|
185
183
|
|
|
186
184
|
Release generation writes `release.yml` without scanning for or removing other
|
|
187
185
|
workflow files. Consumers explicitly delete exact workflow files they no longer
|
|
188
186
|
want.
|
|
189
187
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
metadata. PyPI retries enable Twine's hash-aware existing-file behavior, which
|
|
199
|
-
skips matching files and fails when an existing filename has different content.
|
|
188
|
+
The release-plan job compares the previous and reviewed release-unit graphs and
|
|
189
|
+
selects only changed units, required dependents, packages, native targets,
|
|
190
|
+
assets, and docs. A Node-only release allocates no Rust runner. Manual recovery
|
|
191
|
+
names one component, reviewed version, and publication stage; it reconstructs
|
|
192
|
+
that component's plan without changing any other version. npm retries compare
|
|
193
|
+
archive content and repository identity, PyPI uses hash-aware existing-file
|
|
194
|
+
behavior, Cargo checks existing versions, and GitHub assets upload to the
|
|
195
|
+
component release.
|
|
200
196
|
|
|
201
197
|
The Rust matrix has one row per target. Each row installs native dependencies,
|
|
202
198
|
builds the Cargo workspace once, then packages every discovered output from
|
|
@@ -415,6 +411,8 @@ file contract as the CLI.
|
|
|
415
411
|
- `barrels` / `moduleExports` - public entrypoint generation.
|
|
416
412
|
- `codegen` - `.d.ts` to zod schema generation.
|
|
417
413
|
- `openapi` - tsoa/OpenAPI package generation.
|
|
414
|
+
- `releaseCatalog` / `releasePlan` / `releasePlease` - cross-language ownership,
|
|
415
|
+
affected planning, and Release Please graph propagation.
|
|
418
416
|
- `bunApp` / `tsconfig` / `vscode` - generated support files/components.
|
|
419
417
|
- `generated` / `clean` / `watch` / `scaffold` - read-only file stamping,
|
|
420
418
|
cleanup, watchers, and synth orchestration.
|
|
@@ -433,51 +431,28 @@ Every repo-wide task lives on the root, and the root's `compile` / `test`
|
|
|
433
431
|
delegate with `bun run --filter '*'` rather than emitting a step per member - so
|
|
434
432
|
a new package is covered without a re-synth. Work from the root:
|
|
435
433
|
|
|
436
|
-
| Task
|
|
437
|
-
|
|
|
438
|
-
| `bun run build`
|
|
439
|
-
| `bun run compile`
|
|
440
|
-
| `bun run test`
|
|
441
|
-
| `bun run sync`
|
|
442
|
-
| `bun run barrels`
|
|
443
|
-
| `bun run
|
|
444
|
-
| `bun run
|
|
445
|
-
| `bun run
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
release
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
After validation, release preparation optionally generates an immutable
|
|
459
|
-
`docs/releases/v<version>.md`. It tries the installed Cursor agent first, then
|
|
460
|
-
Codex, then Claude, all in non-interactive read-only modes against bounded Git
|
|
461
|
-
context. An unavailable, unauthenticated, failed, or empty provider falls
|
|
462
|
-
through to the next; if none works, release preparation continues without a
|
|
463
|
-
summary. The same file is included in the release PR and prepended to GitHub's
|
|
464
|
-
generated release notes, so repository and GitHub views share one source.
|
|
465
|
-
|
|
466
|
-
npm
|
|
467
|
-
uses `npm config get registry` and publishes to a local Verdaccio automatically.
|
|
468
|
-
Publishable JavaScript members compile once
|
|
469
|
-
from the root in parallel, then upload through a bounded pool without rerunning
|
|
470
|
-
their `prepack` tasks. Python prefers uv's default index and only
|
|
471
|
-
treats a loopback `.../+simple/` URL as writable devpi; a read-only cache such as
|
|
472
|
-
proxpi (`.../index/`) is deliberately ignored. The task stamps every Python
|
|
473
|
-
member and its sibling dependencies to the release version, builds the workspace
|
|
474
|
-
with uv, then runs `devpi upload --from-dir` against the derived writable index.
|
|
475
|
-
The npm and Python mirrors run concurrently because they touch disjoint package
|
|
476
|
-
trees. Devpi client authentication remains in its normal `~/.devpi` state.
|
|
477
|
-
|
|
478
|
-
Use `--local-registry false` or `--local-pypi false` to disable either local
|
|
479
|
-
publish. An explicit `--local-pypi http://localhost:3141/user/index/` overrides
|
|
480
|
-
auto-detection; `--python-root` defaults to `packages/py`.
|
|
434
|
+
| Task | What it does |
|
|
435
|
+
| --------------------------- | ----------------------------------------------------- |
|
|
436
|
+
| `bun run build` | synth + workspace compile and tests |
|
|
437
|
+
| `bun run compile` | `tsc --build` in each member, in parallel |
|
|
438
|
+
| `bun run test` | `eslint` once, then each member's tests |
|
|
439
|
+
| `bun run sync` | re-synth (`--watch` to keep synthing) |
|
|
440
|
+
| `bun run barrels` | regenerate the read-only `index.ts` barrels |
|
|
441
|
+
| `bun run release:bootstrap` | initialize writable Release Please state once |
|
|
442
|
+
| `bun run release:plan` | emit the affected component and publication plan |
|
|
443
|
+
| `bun run version:check` | verify every package against its owning release unit |
|
|
444
|
+
| `bun run release` | refresh Release Please PRs, tags, and GitHub Releases |
|
|
445
|
+
|
|
446
|
+
`release` runs the pinned Release Please library with the generated
|
|
447
|
+
cross-language graph plugin. Direct changes retain their conventional semantic
|
|
448
|
+
increment, while required dependents receive patches. The combined release PR
|
|
449
|
+
is reconciled by Projen before review. Merging it creates component tags and
|
|
450
|
+
GitHub Releases, then the affected plan selects publication jobs.
|
|
451
|
+
|
|
452
|
+
Each changed component receives
|
|
453
|
+
`docs/releases/<component>-v<version>.md`. Summary generation tries Cursor,
|
|
454
|
+
Codex, and Claude in order, logs provider events, and falls back to Git. The
|
|
455
|
+
committed file becomes that component's GitHub Release body.
|
|
481
456
|
|
|
482
457
|
The GitHub PR workflow runs the explicit `pr:validate` task through Projen's
|
|
483
458
|
public `BuildWorkflow` `buildTask` option. That task runs synth plus the
|
|
@@ -486,13 +461,10 @@ preparation has already run Rust tests, workspace type-checking, and local
|
|
|
486
461
|
package preflight before opening the PR. JavaScript behavior tests remain an
|
|
487
462
|
explicit developer task.
|
|
488
463
|
|
|
489
|
-
The
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
publishes native artifacts and Cargo crates, Python publishes standard
|
|
494
|
-
distributions, Node publishes standard workspace packages, and docs deploys
|
|
495
|
-
after publication. A stage with no corresponding outputs is omitted.
|
|
464
|
+
The generated workflow runs Release Please on the configured branch. A merged
|
|
465
|
+
release PR produces an affected plan, then selected Rust, Python, Node, GitHub
|
|
466
|
+
asset, and docs jobs run behind a publication barrier. A stage with no selected
|
|
467
|
+
outputs is skipped before runner allocation.
|
|
496
468
|
|
|
497
469
|
Members intentionally keep only the tasks that something OTHER than a human
|
|
498
470
|
invokes, so there is no second place to run the same thing:
|
|
@@ -519,17 +491,14 @@ from the root instead.
|
|
|
519
491
|
|
|
520
492
|
## Versioning
|
|
521
493
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
side effects. `bun run release` invokes it while preparing the reviewed release
|
|
534
|
-
PR. The remote is consulted only on `bump` and on one-time creation of a missing
|
|
535
|
-
`VERSION` file, never on an ordinary synth.
|
|
494
|
+
`DBXToolsReleaseCatalog` is the language-neutral version seam. It generates
|
|
495
|
+
`.projen/release-units.json` from attached projects, explicit external members,
|
|
496
|
+
UniFFI families, and binary assets. Independent mode reads component versions
|
|
497
|
+
from `.release-please-manifest.json`; fixed mode reads `VERSION`.
|
|
498
|
+
|
|
499
|
+
Every unit has `.release-units/<component>/source.json`, generated from
|
|
500
|
+
release-affecting inputs. Release Please owns the adjacent `version.txt` and
|
|
501
|
+
`CHANGELOG.md`. Real package manifests remain Projen-owned and reproduce the
|
|
502
|
+
reviewed manifest exactly. `versioningMode: "fixed"` remains the default for
|
|
503
|
+
consumers during migration; `versioningMode: "independent"` enables the
|
|
504
|
+
Release Please and affected-workflow surface.
|
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.230";
|
|
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";
|
|
@@ -24,8 +24,11 @@ export * as projectPy from "./src/project-py.ts";
|
|
|
24
24
|
export * as projectRs from "./src/project-rs.ts";
|
|
25
25
|
export * as publish from "./src/publish.ts";
|
|
26
26
|
export * as release from "./src/release.ts";
|
|
27
|
+
export * as releaseCatalog from "./src/release-catalog.ts";
|
|
27
28
|
export * as releaseDispatch from "./src/release-dispatch.ts";
|
|
28
29
|
export * as releaseGithub from "./src/release-github.ts";
|
|
30
|
+
export * as releasePlan from "./src/release-plan.ts";
|
|
31
|
+
export * as releasePlease from "./src/release-please.ts";
|
|
29
32
|
export * as scaffold from "./src/scaffold.ts";
|
|
30
33
|
export * as tags from "./src/tags.ts";
|
|
31
34
|
export * as tsconfig from "./src/tsconfig.ts";
|
|
@@ -56,9 +59,14 @@ export type { CargoDependencyOptions, CargoDependency, RustCliOptions, RustPacka
|
|
|
56
59
|
export { COMPILED_DIR, COMPILED_COMPILER_OPTIONS } from "./src/publish.ts";
|
|
57
60
|
export { DBXToolsRelease } from "./src/release.ts";
|
|
58
61
|
export type { ReleaseStage, ReleaseDocsOptions, ReleaseSummaryOptions, DBXToolsReleaseOptions } from "./src/release.ts";
|
|
62
|
+
export { DBXToolsReleaseCatalog } from "./src/release-catalog.ts";
|
|
63
|
+
export type { DBXToolsVersioningMode, ReleaseProjectLanguage, ReleaseArtifactKind, ReleaseEdgeKind, ReleasePropagation, ReleaseUnitRule, DBXToolsReleaseCatalogOptions, ReleaseDependencyInput, ReleaseProjectRegistration, ExternalReleaseProjectRegistration, ReleaseArtifactRegistration, ReleaseProjectNode, ReleaseArtifact, ReleaseDependencyEdge, ReleaseUnit, ReleaseUnitGraph } from "./src/release-catalog.ts";
|
|
59
64
|
export { RELEASE_TAG, RELEASE_SHA, RELEASE_VERSION, RELEASE_SUMMARY_DIRECTORY, RELEASE_SUMMARY_PROVIDER_NAMES, RELEASE_SUMMARY_FILE } from "./src/release-dispatch.ts";
|
|
60
65
|
export type { ReleaseSummaryProviderName } from "./src/release-dispatch.ts";
|
|
61
66
|
export type { GithubRepositoryIdentity } from "./src/release-github.ts";
|
|
67
|
+
export type { ReleaseReason, PlannedReleaseUnit, PlannedPackage, PlannedArtifact, PlannedRustTarget, ReleasePlan } from "./src/release-plan.ts";
|
|
68
|
+
export { ReleaseUnitWorkspacePlugin } from "./src/release-please.ts";
|
|
69
|
+
export type { ReleaseUnitWorkspacePluginOptions } from "./src/release-please.ts";
|
|
62
70
|
export { AGNOSTIC_COMPILER_OPTIONS, PACKAGE_TAG_MIXINS } from "./src/tags.ts";
|
|
63
71
|
export type { PackageTag } from "./src/tags.ts";
|
|
64
72
|
export { DBXToolsRootTsconfig } from "./src/tsconfig.ts";
|
package/package.json
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@types/node": "^24.6.0",
|
|
21
|
+
"@types/semver": "^7.7.1",
|
|
21
22
|
"constructs": "^10.0.0",
|
|
22
23
|
"projen": "^0.101.6",
|
|
23
24
|
"tsoa": "^6.6.0",
|
|
@@ -25,9 +26,9 @@
|
|
|
25
26
|
},
|
|
26
27
|
"dependencies": {
|
|
27
28
|
"@clack/prompts": "^1.7.0",
|
|
28
|
-
"@dbx-tools/core": "0.6.
|
|
29
|
-
"@dbx-tools/path": "0.6.
|
|
30
|
-
"@dbx-tools/shared-core": "0.6.
|
|
29
|
+
"@dbx-tools/core": "^0.6.229",
|
|
30
|
+
"@dbx-tools/path": "^0.6.229",
|
|
31
|
+
"@dbx-tools/shared-core": "^0.6.229",
|
|
31
32
|
"commander": "^15.0.0",
|
|
32
33
|
"concurrently": "^10.0.3",
|
|
33
34
|
"constructs": "^10.6.0",
|
|
@@ -35,7 +36,9 @@
|
|
|
35
36
|
"openapi-typescript": "^7.13.0",
|
|
36
37
|
"oxc-parser": "^0.90.0",
|
|
37
38
|
"projen": "^0.101.16",
|
|
38
|
-
"
|
|
39
|
+
"release-please": "17.11.2",
|
|
40
|
+
"semver": "^7.7.3",
|
|
41
|
+
"smol-toml": "1.8.0",
|
|
39
42
|
"ts-to-zod": "^5.1.0",
|
|
40
43
|
"yaml": "^2.9.0"
|
|
41
44
|
},
|
|
@@ -47,7 +50,7 @@
|
|
|
47
50
|
},
|
|
48
51
|
"main": "index.ts",
|
|
49
52
|
"license": "Apache-2.0",
|
|
50
|
-
"version": "0.6.
|
|
53
|
+
"version": "0.6.230",
|
|
51
54
|
"types": "index.ts",
|
|
52
55
|
"type": "module",
|
|
53
56
|
"exports": {
|
package/src/openapi.ts
CHANGED
|
@@ -48,6 +48,7 @@ import {
|
|
|
48
48
|
toPosix,
|
|
49
49
|
recordedPackages,
|
|
50
50
|
} from "./packages.ts";
|
|
51
|
+
import type { ReleaseUnitGraph } from "./release-catalog.ts";
|
|
51
52
|
import { readWorkspaceVersion } from "./workspace-version.ts";
|
|
52
53
|
|
|
53
54
|
const logger = log.logger("projen:openapi");
|
|
@@ -174,9 +175,16 @@ export async function generateOpenapi(): Promise<string[]> {
|
|
|
174
175
|
skipLibCheck: true,
|
|
175
176
|
};
|
|
176
177
|
|
|
177
|
-
const
|
|
178
|
+
const releaseGraphPath = join(repoRoot, ".projen/release-units.json");
|
|
179
|
+
const releaseGraph = existsSync(releaseGraphPath)
|
|
180
|
+
? (JSON.parse(readFileSync(releaseGraphPath, "utf8")) as ReleaseUnitGraph)
|
|
181
|
+
: undefined;
|
|
178
182
|
const written: string[] = [];
|
|
179
183
|
for (const p of pkgs) {
|
|
184
|
+
const releaseProject = releaseGraph?.projects.find((project) => project.path === p.path);
|
|
185
|
+
const specVersion =
|
|
186
|
+
releaseGraph?.units.find((unit) => unit.id === releaseProject?.unit)?.version ??
|
|
187
|
+
readWorkspaceVersion(repoRoot);
|
|
180
188
|
// The generated package's folder is the source's leaf folder name (`api`), not
|
|
181
189
|
// its npm name - `p.name` is the (possibly-overridden) manifest name.
|
|
182
190
|
const leaf = p.relPath.split("/").pop() ?? p.relPath;
|
package/src/project-js.ts
CHANGED
|
@@ -41,11 +41,18 @@ import {
|
|
|
41
41
|
import { PnpmWorkspaceState, type DBXToolsPNPMWorkspaceOptions } from "./pnpm-workspace.ts";
|
|
42
42
|
import type { DBXToolsProject, DBXToolsProjectOptions as CommonProjectOptions } from "./project.ts";
|
|
43
43
|
import { applyCompiledPublish } from "./publish.ts";
|
|
44
|
+
import {
|
|
45
|
+
DBXToolsReleaseCatalog,
|
|
46
|
+
type DBXToolsVersioningMode,
|
|
47
|
+
type ExternalReleaseProjectRegistration,
|
|
48
|
+
type ReleaseDependencyInput,
|
|
49
|
+
type ReleaseUnitRule,
|
|
50
|
+
} from "./release-catalog.ts";
|
|
44
51
|
import { DBXToolsRelease, type ReleaseDocsOptions, type ReleaseSummaryOptions } from "./release.ts";
|
|
45
52
|
import { AGNOSTIC_COMPILER_OPTIONS, PACKAGE_TAG_MIXINS, type PackageTag } from "./tags.ts";
|
|
46
53
|
import { DBXToolsRootTsconfig } from "./tsconfig.ts";
|
|
47
54
|
import { DBXToolsVsCode } from "./vscode.ts";
|
|
48
|
-
import {
|
|
55
|
+
import { syncWorkspaceManifestVersion } from "./workspace-version.ts";
|
|
49
56
|
|
|
50
57
|
/**
|
|
51
58
|
* The dbx-tools project surface, backed by projen's Node toolchain. A single
|
|
@@ -70,6 +77,8 @@ export interface DBXToolsJavaScriptProject extends DBXToolsProject, javascript.N
|
|
|
70
77
|
vsCode?: DBXToolsVsCode;
|
|
71
78
|
/** Repository outputs excluded from generated workflow dependency-cache hashing. */
|
|
72
79
|
readonly workflowCacheIgnorePaths: readonly string[];
|
|
80
|
+
/** Cross-language release-unit ownership and version lookup. */
|
|
81
|
+
readonly releaseCatalog: DBXToolsReleaseCatalog;
|
|
73
82
|
}
|
|
74
83
|
|
|
75
84
|
/** Parsed npm package identifier: optional scope plus the unscoped package name. */
|
|
@@ -629,6 +638,14 @@ export type DBXToolsJavaScriptProjectOptions = CommonProjectOptions &
|
|
|
629
638
|
readonly nodeRelease?: boolean;
|
|
630
639
|
/** Unified dbx-tools release workflow, or no release surface. Defaults to `dbx-tools`. */
|
|
631
640
|
readonly releaseMode?: DBXToolsReleaseMode;
|
|
641
|
+
/** Package version ownership mode. Defaults to `fixed`. */
|
|
642
|
+
readonly versioningMode?: DBXToolsVersioningMode;
|
|
643
|
+
/** Explicit stable release-unit grouping rules. */
|
|
644
|
+
readonly releaseUnits?: readonly ReleaseUnitRule[];
|
|
645
|
+
/** Commit before the first independent Release Please history. */
|
|
646
|
+
readonly releaseBootstrapSha?: string;
|
|
647
|
+
/** Publishable workspace members synthesized outside the attached project tree. */
|
|
648
|
+
readonly externalReleaseProjects?: readonly ExternalReleaseProjectRegistration[];
|
|
632
649
|
/** Prefix for generated release tags. Defaults to `v`. */
|
|
633
650
|
readonly releaseTagPrefix?: string;
|
|
634
651
|
/** Semantic PR title validation policy. Omitted or `false` disables title validation. */
|
|
@@ -682,6 +699,7 @@ export class DBXToolsNodeProject
|
|
|
682
699
|
readonly extraWorkspaceMembers: readonly string[];
|
|
683
700
|
readonly releaseBranch: string;
|
|
684
701
|
readonly workflowCacheIgnorePaths: readonly string[];
|
|
702
|
+
readonly releaseCatalog: DBXToolsReleaseCatalog;
|
|
685
703
|
private readonly rootInstallOnly: boolean;
|
|
686
704
|
|
|
687
705
|
constructor(options: DBXToolsJavaScriptProjectOptions = {}) {
|
|
@@ -708,9 +726,14 @@ export class DBXToolsNodeProject
|
|
|
708
726
|
// component, but the file is still required by the Databricks Apps platform
|
|
709
727
|
// (its build phase installs with pnpm and reads catalog + `allowBuilds`).
|
|
710
728
|
pnpmWorkspace.attachWorkspaceFile(this);
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
729
|
+
this.releaseCatalog = new DBXToolsReleaseCatalog(this, {
|
|
730
|
+
mode: options.versioningMode,
|
|
731
|
+
units: options.releaseUnits,
|
|
732
|
+
externalProjects: options.externalReleaseProjects,
|
|
733
|
+
bootstrapSha: options.releaseBootstrapSha,
|
|
734
|
+
});
|
|
735
|
+
registerJavaScriptReleaseProject(this);
|
|
736
|
+
this.package.addField("version", () => this.releaseCatalog.versionFor(this));
|
|
714
737
|
this.scope = scope;
|
|
715
738
|
this.extraWorkspaceMembers = options.extraWorkspaceMembers ?? [];
|
|
716
739
|
this.releaseBranch = options.defaultReleaseBranch ?? "main";
|
|
@@ -795,6 +818,7 @@ export class DBXToolsTypeScriptProject
|
|
|
795
818
|
readonly extraWorkspaceMembers: readonly string[];
|
|
796
819
|
readonly releaseBranch: string;
|
|
797
820
|
readonly workflowCacheIgnorePaths: readonly string[];
|
|
821
|
+
readonly releaseCatalog: DBXToolsReleaseCatalog;
|
|
798
822
|
private readonly rootInstallOnly: boolean;
|
|
799
823
|
|
|
800
824
|
constructor(options: DBXToolsTypeScriptProjectOptions) {
|
|
@@ -837,6 +861,16 @@ export class DBXToolsTypeScriptProject
|
|
|
837
861
|
this.releaseBranch = options.defaultReleaseBranch ?? "main";
|
|
838
862
|
this.workflowCacheIgnorePaths = options.workflowCacheIgnorePaths ?? [];
|
|
839
863
|
this.rootInstallOnly = options.rootInstallOnly !== false;
|
|
864
|
+
this.releaseCatalog =
|
|
865
|
+
parent &&
|
|
866
|
+
(parent instanceof DBXToolsNodeProject || parent instanceof DBXToolsTypeScriptProject)
|
|
867
|
+
? parent.releaseCatalog
|
|
868
|
+
: new DBXToolsReleaseCatalog(this, {
|
|
869
|
+
mode: options.versioningMode,
|
|
870
|
+
units: options.releaseUnits,
|
|
871
|
+
externalProjects: options.externalReleaseProjects,
|
|
872
|
+
bootstrapSha: options.releaseBootstrapSha,
|
|
873
|
+
});
|
|
840
874
|
// Pairs with `jsx` in SHARED_COMPILER_OPTIONS: projen's default `include` is
|
|
841
875
|
// `src/**/*.ts` only, which silently omits a `.tsx` file from the program
|
|
842
876
|
// instead of failing, so authoring a React component would otherwise need
|
|
@@ -852,10 +886,8 @@ export class DBXToolsTypeScriptProject
|
|
|
852
886
|
".": "./index.ts",
|
|
853
887
|
"./package.json": "./package.json",
|
|
854
888
|
});
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
// discovered member and this project itself for a standalone compiling root.
|
|
858
|
-
this.package.addField("version", readWorkspaceVersion(this.root.outdir));
|
|
889
|
+
this.package.addField("version", () => this.releaseCatalog.versionFor(this));
|
|
890
|
+
registerJavaScriptReleaseProject(this);
|
|
859
891
|
addPackageFiles(this, "index.ts", "src");
|
|
860
892
|
// `bun test` intercepts `node:test` (the suites keep using node:test) and
|
|
861
893
|
// runs it with bun's own fast runner. The native no-tests option is portable
|
|
@@ -878,6 +910,27 @@ export class DBXToolsTypeScriptProject
|
|
|
878
910
|
}
|
|
879
911
|
}
|
|
880
912
|
|
|
913
|
+
function registerJavaScriptReleaseProject(project: DBXToolsJavaScriptProject): void {
|
|
914
|
+
const projectPath = toPosix(relative(project.root.outdir, project.outdir));
|
|
915
|
+
project.releaseCatalog.registerProject(project, {
|
|
916
|
+
language: "javascript",
|
|
917
|
+
identity: () => String(project.package.manifest.name ?? project.name),
|
|
918
|
+
publish: () => project.package.manifest.private !== true,
|
|
919
|
+
sourcePaths: ["src", "bin", "tasks"].map((path) =>
|
|
920
|
+
projectPath ? `${projectPath}/${path}` : path,
|
|
921
|
+
),
|
|
922
|
+
dependencies: () =>
|
|
923
|
+
project.deps.all.map<ReleaseDependencyInput>((dependency) => ({
|
|
924
|
+
target: dependency.name,
|
|
925
|
+
kind:
|
|
926
|
+
dependency.type === "devenv" || dependency.type === "override"
|
|
927
|
+
? "development"
|
|
928
|
+
: dependency.type,
|
|
929
|
+
...(dependency.version ? { requirement: dependency.version } : {}),
|
|
930
|
+
})),
|
|
931
|
+
});
|
|
932
|
+
}
|
|
933
|
+
|
|
881
934
|
function configureBuildWorkflow(
|
|
882
935
|
project: DBXToolsNodeProject | DBXToolsTypeScriptProject,
|
|
883
936
|
options: DBXToolsJavaScriptProjectOptions,
|
|
@@ -951,9 +1004,11 @@ function resolveRootWorkspace(
|
|
|
951
1004
|
extraWorkspaceMembers: readonly string[],
|
|
952
1005
|
): void {
|
|
953
1006
|
if (project.parent) return;
|
|
954
|
-
const version = readWorkspaceVersion(project.outdir);
|
|
955
1007
|
for (const member of extraWorkspaceMembers) {
|
|
956
|
-
syncWorkspaceManifestVersion(
|
|
1008
|
+
syncWorkspaceManifestVersion(
|
|
1009
|
+
join(project.outdir, member, "package.json"),
|
|
1010
|
+
project.releaseCatalog.versionForPath(member),
|
|
1011
|
+
);
|
|
957
1012
|
}
|
|
958
1013
|
project.pnpmWorkspace?.resolveMembers(project, extraWorkspaceMembers);
|
|
959
1014
|
}
|
package/src/project-py.ts
CHANGED
|
@@ -9,6 +9,8 @@ import { isDBXToolsJavaScriptProject } from "./project-predicate.ts";
|
|
|
9
9
|
import type { DBXToolsProject, DBXToolsProjectOptions } from "./project.ts";
|
|
10
10
|
import { RELEASE_VERSION, releaseSourceSteps } from "./release-dispatch.ts";
|
|
11
11
|
import {
|
|
12
|
+
independentReleaseSetupSteps,
|
|
13
|
+
registerIndependentPublicationJob,
|
|
12
14
|
releaseArtifactSteps,
|
|
13
15
|
releasePublishCondition,
|
|
14
16
|
releaseStageCondition,
|
|
@@ -128,6 +130,14 @@ export function pythonModuleName(scope: string, directory: string): string {
|
|
|
128
130
|
return [scope, ...directory.split("/")].map((part) => part.replaceAll("-", "_")).join(".");
|
|
129
131
|
}
|
|
130
132
|
|
|
133
|
+
/** Published requirement for one internal Python dependency. */
|
|
134
|
+
export function pythonReleaseRequirement(version: string, exact = false): string {
|
|
135
|
+
if (exact) return `==${version}`;
|
|
136
|
+
const [major, minor] = version.split(".").map(Number);
|
|
137
|
+
const upper = major === 0 ? `0.${minor + 1}.0` : `${major + 1}.0.0`;
|
|
138
|
+
return `>=${version},<${upper}`;
|
|
139
|
+
}
|
|
140
|
+
|
|
131
141
|
function projectVscode(project: Project): vscode.VsCode | undefined {
|
|
132
142
|
return (project as Project & { readonly vscode?: vscode.VsCode }).vscode;
|
|
133
143
|
}
|
|
@@ -264,9 +274,10 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
264
274
|
}));
|
|
265
275
|
const resolvedOptions = { ...options, packages };
|
|
266
276
|
this.requiresPython = options.requiresPython ?? ">=3.10";
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
277
|
+
this.version =
|
|
278
|
+
isDBXToolsJavaScriptProject()(project) && project.releaseCatalog.mode === "independent"
|
|
279
|
+
? "0.0.0"
|
|
280
|
+
: readWorkspaceVersion(project.outdir);
|
|
270
281
|
this.file = this.emitWorkspace(project, resolvedOptions, scope);
|
|
271
282
|
this.packages = packages.map(
|
|
272
283
|
(pkg) =>
|
|
@@ -275,9 +286,45 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
275
286
|
package: pkg,
|
|
276
287
|
repository: this.repository,
|
|
277
288
|
requiresPython: this.requiresPython,
|
|
278
|
-
version:
|
|
289
|
+
version: isDBXToolsJavaScriptProject()(project)
|
|
290
|
+
? project.releaseCatalog.versionForRegistration(
|
|
291
|
+
"python",
|
|
292
|
+
pkg.name,
|
|
293
|
+
pythonPackagePath(this.repository, pkg.directory),
|
|
294
|
+
)
|
|
295
|
+
: this.version,
|
|
279
296
|
}),
|
|
280
297
|
);
|
|
298
|
+
if (isDBXToolsJavaScriptProject()(project)) {
|
|
299
|
+
for (const pkg of this.packages) {
|
|
300
|
+
project.releaseCatalog.registerProject(pkg, {
|
|
301
|
+
language: "python",
|
|
302
|
+
identity: pkg.packageOptions.name,
|
|
303
|
+
sourcePaths: [`${pythonPackagePath(this.repository, pkg.packageOptions.directory)}/src`],
|
|
304
|
+
dependencies: (pkg.packageOptions.internalDependencies ?? []).map((directory) => {
|
|
305
|
+
const dependency = packagesByDirectory.get(directory);
|
|
306
|
+
if (!dependency) {
|
|
307
|
+
throw new Error(
|
|
308
|
+
`Python package ${pkg.packageOptions.directory} references unknown internal package ${directory}`,
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
const version = project.releaseCatalog.versionForRegistration(
|
|
312
|
+
"python",
|
|
313
|
+
dependency.name,
|
|
314
|
+
pythonPackagePath(this.repository, dependency.directory),
|
|
315
|
+
);
|
|
316
|
+
return {
|
|
317
|
+
target: dependency.name,
|
|
318
|
+
kind: "runtime" as const,
|
|
319
|
+
requirement: pythonReleaseRequirement(version, dependency.uniffi === true),
|
|
320
|
+
propagation: "outside-range" as const,
|
|
321
|
+
publishOrder: true,
|
|
322
|
+
internal: true,
|
|
323
|
+
};
|
|
324
|
+
}),
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
}
|
|
281
328
|
for (const pkg of this.packages) {
|
|
282
329
|
const pyproject = `/${pythonPackagePath(this.repository, pkg.packageOptions.directory)}/pyproject.toml`;
|
|
283
330
|
project.gitignore.include(pyproject);
|
|
@@ -415,6 +462,88 @@ export class DBXToolsPythonWorkspace extends Component {
|
|
|
415
462
|
if (!workflow) {
|
|
416
463
|
throw new Error("Python release requires the root dbx-tools release mode");
|
|
417
464
|
}
|
|
465
|
+
if (project.releaseCatalog.mode === "independent") {
|
|
466
|
+
workflow.addJob("build-python", {
|
|
467
|
+
if: usesRustArtifacts
|
|
468
|
+
? "${{ always() && needs.release-plan.outputs.python == 'true' && needs.rust-build.result != 'failure' && needs.rust-build.result != 'cancelled' && (github.event_name == 'push' || inputs.stage == 'all' || inputs.stage == 'python') }}"
|
|
469
|
+
: "${{ needs.release-plan.outputs.python == 'true' && (github.event_name == 'push' || inputs.stage == 'all' || inputs.stage == 'python') }}",
|
|
470
|
+
needs: ["release-plan", ...(usesRustArtifacts ? ["rust-build"] : [])],
|
|
471
|
+
runsOn: ["ubuntu-latest"],
|
|
472
|
+
permissions: { actions: JobPermission.READ, contents: JobPermission.READ },
|
|
473
|
+
timeoutMinutes: 20,
|
|
474
|
+
env: { BUN_VERSION },
|
|
475
|
+
steps: [
|
|
476
|
+
...independentReleaseSetupSteps(project),
|
|
477
|
+
{ name: "Setup uv", uses: "astral-sh/setup-uv@v7" },
|
|
478
|
+
...uniffiPublications.map((publication) => ({
|
|
479
|
+
name: `Download ${publication.distribution} native wheels`,
|
|
480
|
+
uses: "actions/download-artifact@v8",
|
|
481
|
+
with: {
|
|
482
|
+
pattern: `${publication.distribution}--*--python-wheel`,
|
|
483
|
+
path: `dist/${publication.directory}`,
|
|
484
|
+
"merge-multiple": true,
|
|
485
|
+
},
|
|
486
|
+
})),
|
|
487
|
+
{
|
|
488
|
+
name: "Build affected distributions",
|
|
489
|
+
shell: "bash",
|
|
490
|
+
run: publications
|
|
491
|
+
.map(
|
|
492
|
+
(publication) =>
|
|
493
|
+
`if jq -e --arg package ${quote(publication.distribution)} '.pythonPackages[] | select(.identity == $package)' dist/release-plan.json >/dev/null; then uv build --package ${quote(publication.distribution)} --out-dir dist/${publication.directory}; fi`,
|
|
494
|
+
)
|
|
495
|
+
.join("\n"),
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
name: "Validate affected distributions",
|
|
499
|
+
run: "find dist -type f \\( -name '*.whl' -o -name '*.tar.gz' \\) -print0 | xargs -0 uvx twine check",
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
name: "Upload distributions",
|
|
503
|
+
uses: "actions/upload-artifact@v7",
|
|
504
|
+
with: { name: "python-distributions", path: "dist", "retention-days": 7 },
|
|
505
|
+
},
|
|
506
|
+
],
|
|
507
|
+
});
|
|
508
|
+
for (const publication of allPublications) {
|
|
509
|
+
const dependencyJobs = (publication.dependencies ?? []).map(
|
|
510
|
+
(dependency) => `publish-pypi-${dependency}`,
|
|
511
|
+
);
|
|
512
|
+
const dependencyCondition = dependencyJobs
|
|
513
|
+
.map((job) => `needs.${job}.result != 'failure' && needs.${job}.result != 'cancelled'`)
|
|
514
|
+
.join(" && ");
|
|
515
|
+
workflow.addJob(`publish-pypi-${publication.directory}`, {
|
|
516
|
+
if: `\${{ always() && needs.build-python.result == 'success' && contains(needs.release-plan.outputs.python_packages, '"identity":"${publication.distribution}"') && (github.event_name == 'push' || inputs.stage == 'all' || inputs.stage == 'python')${dependencyCondition ? ` && ${dependencyCondition}` : ""} }}`,
|
|
517
|
+
needs: ["release-plan", "build-python", ...dependencyJobs],
|
|
518
|
+
environment: {
|
|
519
|
+
name: publication.environment,
|
|
520
|
+
url:
|
|
521
|
+
options.environmentUrl ??
|
|
522
|
+
`https://pypi.org/project/${publication.distribution.replaceAll("_", "-")}/`,
|
|
523
|
+
},
|
|
524
|
+
runsOn: ["ubuntu-latest"],
|
|
525
|
+
permissions: { idToken: JobPermission.WRITE },
|
|
526
|
+
timeoutMinutes: 10,
|
|
527
|
+
steps: [
|
|
528
|
+
{
|
|
529
|
+
name: "Download distributions",
|
|
530
|
+
uses: "actions/download-artifact@v8",
|
|
531
|
+
with: { name: "python-distributions", path: "dist" },
|
|
532
|
+
},
|
|
533
|
+
{
|
|
534
|
+
name: `Publish ${publication.distribution} to PyPI`,
|
|
535
|
+
uses: "pypa/gh-action-pypi-publish@release/v1",
|
|
536
|
+
with: {
|
|
537
|
+
"packages-dir": `dist/${publication.directory}`,
|
|
538
|
+
"skip-existing": true,
|
|
539
|
+
},
|
|
540
|
+
},
|
|
541
|
+
],
|
|
542
|
+
});
|
|
543
|
+
registerIndependentPublicationJob(workflow, `publish-pypi-${publication.directory}`);
|
|
544
|
+
}
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
418
547
|
workflow.addJob("build-python", {
|
|
419
548
|
if: usesRustArtifacts
|
|
420
549
|
? "${{ 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') }}"
|