@dbx-tools/projen 0.6.153 → 0.6.158
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +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/README.md
CHANGED
|
@@ -61,38 +61,38 @@ headers.
|
|
|
61
61
|
import { project, projectPy } from "@dbx-tools/projen";
|
|
62
62
|
|
|
63
63
|
const root = new project.DBXToolsNodeProject({ name: "my-apps" });
|
|
64
|
-
const repository = {
|
|
65
|
-
url: "https://github.com/example/my-apps.git",
|
|
66
|
-
ref: "main",
|
|
67
|
-
root: "python/packages",
|
|
68
|
-
} as const;
|
|
69
64
|
|
|
70
65
|
new projectPy.DBXToolsPythonWorkspace(root, {
|
|
71
|
-
|
|
66
|
+
root: "python/packages",
|
|
72
67
|
packages: [
|
|
73
68
|
{
|
|
74
69
|
directory: "core",
|
|
75
|
-
name: "my-apps-core",
|
|
76
|
-
module: "my_apps.core",
|
|
77
70
|
description: "Shared Python helpers",
|
|
78
71
|
},
|
|
72
|
+
{
|
|
73
|
+
directory: "service",
|
|
74
|
+
description: "Python service",
|
|
75
|
+
internalDependencies: ["core"],
|
|
76
|
+
},
|
|
79
77
|
],
|
|
80
|
-
interpreterPath: "${workspaceFolder}/python/.venv/bin/python",
|
|
81
78
|
release: true,
|
|
82
79
|
});
|
|
83
80
|
```
|
|
84
81
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
82
|
+
Distribution names and modules come from the parent scope plus each package
|
|
83
|
+
directory. The repository comes from the parent project metadata or Git remote.
|
|
84
|
+
`internalDependencies` renders standalone Git `#subdirectory=` requirements
|
|
85
|
+
without repeating repository coordinates. Pass `repository`, `name`, or
|
|
86
|
+
`module` only to override those conventions. `root.vscode` is projen's existing
|
|
87
|
+
VS Code component; dbx-tools reuses it rather than constructing a second
|
|
88
|
+
`.vscode/settings.json` owner.
|
|
90
89
|
|
|
91
90
|
## Add A Rust Workspace
|
|
92
91
|
|
|
93
|
-
`DBXToolsRustWorkspace` discovers every source-bearing folder under
|
|
94
|
-
`packages/rs
|
|
95
|
-
|
|
92
|
+
`DBXToolsRustWorkspace` discovers every source-bearing folder under its
|
|
93
|
+
configurable `root` (default `packages/rs`), generates its Cargo manifest, and
|
|
94
|
+
derives the crate name and repository from the parent project. A crate containing
|
|
95
|
+
`uniffi::setup_scaffolding!()`
|
|
96
96
|
automatically wires matching private Node and Python binding packages using the
|
|
97
97
|
same capability name. Repository-specific dependencies and features remain
|
|
98
98
|
declarative options in `.projenrc.ts`; generated bindings are built separately
|
|
@@ -105,16 +105,28 @@ without Rust crates start no Rust watcher. When Rust projects are detected,
|
|
|
105
105
|
Cargo is required and the focused task fails immediately if it is unavailable.
|
|
106
106
|
|
|
107
107
|
The workspace also generates a `rust-release` workflow from discovered crates,
|
|
108
|
-
UniFFI bindings, and release-enabled binaries.
|
|
109
|
-
|
|
108
|
+
UniFFI bindings, and release-enabled binaries. The root `release-dispatch`
|
|
109
|
+
workflow resolves the annotated release tag and sends the tag plus commit SHA to
|
|
110
|
+
`rust-release` when Rust is present. The Rust workflow runs in the configured release
|
|
111
|
+
branch cache scope, checks out the supplied SHA, fetches the tag, and requires
|
|
112
|
+
both the tag target and `HEAD` to equal that SHA before building. Its matrix has
|
|
113
|
+
one row per target. Each row installs native dependencies and restores
|
|
114
|
+
Cargo/sccache once,
|
|
110
115
|
builds the Rust workspace once, then packages every discovered output from that
|
|
111
116
|
shared build. Bun and the workspace install are present only when a Node binding
|
|
112
117
|
needs TypeScript generation; uv is present only when a Python wheel is needed.
|
|
113
|
-
A binary-only workspace therefore installs neither.
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
+
A binary-only workspace therefore installs neither. `rustVersion` remains the
|
|
119
|
+
MSRV recorded in package manifests, while `releaseRustVersion` independently
|
|
120
|
+
defaults release compilation to `stable`. UBRN uses that same release toolchain
|
|
121
|
+
unless `ubrnRustVersion` explicitly selects another one.
|
|
122
|
+
|
|
123
|
+
The Node generator's Rust CLI can be cached under one target directory keyed by
|
|
124
|
+
its pinned UBRN version, Rust version, runner OS, and runner architecture. Set
|
|
125
|
+
the repository variable `CACHE_UBRN_TARGET=true` to enable that archive while
|
|
126
|
+
comparing its transfer cost with the default sccache-only path. Cargo registry
|
|
127
|
+
caches and the `SCCACHE_GHA_VERSION` namespace stay stable per target/toolchain
|
|
128
|
+
across version tags. Cache keys, restore results, sccache statistics, and phase
|
|
129
|
+
timings are written to each build log. Python generation executes the already-built
|
|
118
130
|
`target/<triple>/release/uniffi-bindgen` directly. Artifact packaging therefore
|
|
119
131
|
does no Rust compilation after the main workspace build.
|
|
120
132
|
|
|
@@ -125,22 +137,30 @@ Non-private Cargo crates publish from a source-only job with
|
|
|
125
137
|
`cargo publish --no-verify`; GitHub Release uploads likewise consume prebuilt
|
|
126
138
|
binary artifacts without reinstalling a toolchain.
|
|
127
139
|
|
|
128
|
-
Set the repository variable `LOCAL_REPOSITORIES=true` to enable
|
|
129
|
-
self-hosted
|
|
140
|
+
Set the repository variable `LOCAL_REPOSITORIES=true` to enable generated
|
|
141
|
+
self-hosted publication from the prebuilt artifacts. Configure `LOCAL_NPM_REGISTRY` and
|
|
130
142
|
`LOCAL_PYPI_PUBLISH_URL` with their matching `LOCAL_*` credentials. Set
|
|
131
143
|
`LOCAL_CARGO_REGISTRY` to a named Cargo registry such as a loopback
|
|
132
|
-
[Kellnr](https://kellnr.io/) instance and provide `LOCAL_CARGO_TOKEN`.
|
|
133
|
-
|
|
134
|
-
only that native target. Public Cargo crates also publish directly to crates.io
|
|
144
|
+
[Kellnr](https://kellnr.io/) instance and provide `LOCAL_CARGO_TOKEN`. Public
|
|
145
|
+
Cargo crates also publish directly to crates.io
|
|
135
146
|
with `CARGO_REGISTRY_TOKEN`. Override `releaseTargets` only when a consumer has
|
|
136
147
|
additional native runners; ordinary projects inherit the maintained matrix
|
|
137
148
|
automatically. `bun run bump` also accepts repeatable `--os` and `--arch`
|
|
138
149
|
selectors; every selected operating system is crossed with every selected
|
|
139
150
|
architecture. Omit both filters to regenerate the complete maintained matrix.
|
|
151
|
+
`DBX_TOOLS_RELEASE_PLATFORMS` can select the generated matrix without repeating
|
|
152
|
+
environment parsing in a consumer.
|
|
140
153
|
|
|
141
154
|
Private Python binding projects are marked with `[tool.dbx-tools] private =
|
|
142
155
|
true`. They stay out of the standard uv/Python release and docs surfaces;
|
|
143
156
|
`rust-release` publishes their prebuilt native wheels directly.
|
|
157
|
+
After Rust's public artifacts finish, it dispatches the downstream `release`
|
|
158
|
+
event. Python, Node, standalone Node, and docs consume that event independently
|
|
159
|
+
and start together with the same verified tag and SHA. Without Rust,
|
|
160
|
+
`release-dispatch` sends that event immediately. Configure release GitHub
|
|
161
|
+
environments to permit the generated release branch; the trusted-publisher
|
|
162
|
+
instructions list that branch with the workflow and environment identity PyPI
|
|
163
|
+
verifies.
|
|
144
164
|
|
|
145
165
|
## Customize Packages With Mixins
|
|
146
166
|
|
|
@@ -156,6 +176,10 @@ projenProject.applyToProjects(project, { tags: "shared" }, (pkg) => {
|
|
|
156
176
|
project.synth();
|
|
157
177
|
```
|
|
158
178
|
|
|
179
|
+
Use `projectJs.addOptionalPeer(pkg, specifier)` for an optional peer that must
|
|
180
|
+
also resolve during local development. It writes the peer metadata and matching
|
|
181
|
+
development dependency without turning the peer into a runtime dependency.
|
|
182
|
+
|
|
159
183
|
`applyToProjects` AND-s its globs (prefix a glob with `!` to negate) into one
|
|
160
184
|
predicate over the DBXTools child packages, then applies it as a `constructs`
|
|
161
185
|
mixin across the subtree. Filter on the folder (`path`), the tags (`tags`), or
|
package/index.ts
CHANGED
|
@@ -22,6 +22,7 @@ export * as projectPy from "./src/project-py.ts";
|
|
|
22
22
|
export * as projectRs from "./src/project-rs.ts";
|
|
23
23
|
export * as publish from "./src/publish.ts";
|
|
24
24
|
export * as release from "./src/release.ts";
|
|
25
|
+
export * as releaseDispatch from "./src/release-dispatch.ts";
|
|
25
26
|
export * as scaffold from "./src/scaffold.ts";
|
|
26
27
|
export * as tags from "./src/tags.ts";
|
|
27
28
|
export * as tsconfig from "./src/tsconfig.ts";
|
|
@@ -50,6 +51,7 @@ export type { CargoDependencyOptions, CargoDependency, RustPackageOptions, DBXTo
|
|
|
50
51
|
export { COMPILED_DIR, COMPILED_COMPILER_OPTIONS } from "./src/publish.ts";
|
|
51
52
|
export { DBXToolsRelease } from "./src/release.ts";
|
|
52
53
|
export type { StandaloneRelease, DBXToolsReleaseOptions } from "./src/release.ts";
|
|
54
|
+
export { DOWNSTREAM_RELEASE_EVENT, RUST_RELEASE_EVENT, RELEASE_TAG, RELEASE_SHA } from "./src/release-dispatch.ts";
|
|
53
55
|
export { AGNOSTIC_COMPILER_OPTIONS, PACKAGE_TAG_MIXINS } from "./src/tags.ts";
|
|
54
56
|
export type { PackageTag } from "./src/tags.ts";
|
|
55
57
|
export { DBXToolsRootTsconfig } from "./src/tsconfig.ts";
|
package/package.json
CHANGED
|
@@ -26,9 +26,9 @@
|
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@clack/prompts": "^1.7.0",
|
|
29
|
-
"@dbx-tools/core": "0.6.
|
|
30
|
-
"@dbx-tools/path": "0.6.
|
|
31
|
-
"@dbx-tools/shared-core": "0.6.
|
|
29
|
+
"@dbx-tools/core": "0.6.158",
|
|
30
|
+
"@dbx-tools/path": "0.6.158",
|
|
31
|
+
"@dbx-tools/shared-core": "0.6.158",
|
|
32
32
|
"commander": "^15.0.0",
|
|
33
33
|
"concurrently": "^10.0.3",
|
|
34
34
|
"constructs": "^10.6.0",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
},
|
|
49
49
|
"main": "index.ts",
|
|
50
50
|
"license": "Apache-2.0",
|
|
51
|
-
"version": "0.6.
|
|
51
|
+
"version": "0.6.158",
|
|
52
52
|
"types": "index.ts",
|
|
53
53
|
"type": "module",
|
|
54
54
|
"exports": {
|
package/src/pnpm-workspace.ts
CHANGED
|
@@ -101,7 +101,10 @@ const DEFAULT_CATALOG: Catalog = {
|
|
|
101
101
|
* workspace with an "Ignored build scripts" warning on its first install.
|
|
102
102
|
*/
|
|
103
103
|
const DEFAULT_ALLOW_BUILDS: AllowBuilds = {
|
|
104
|
+
"@databricks/appkit": true,
|
|
105
|
+
"@databricks/appkit-ui": true,
|
|
104
106
|
esbuild: true,
|
|
107
|
+
protobufjs: true,
|
|
105
108
|
"unrs-resolver": true,
|
|
106
109
|
// The `bun` npm package (a peer of `bun-plugin-tailwind`) ships a `bun.exe`
|
|
107
110
|
// placeholder and downloads the real platform binary in its postinstall. Left
|
|
@@ -113,6 +116,10 @@ const DEFAULT_ALLOW_BUILDS: AllowBuilds = {
|
|
|
113
116
|
"onnxruntime-node": true,
|
|
114
117
|
};
|
|
115
118
|
|
|
119
|
+
const DEFAULT_OVERRIDES: Readonly<Record<string, string>> = {
|
|
120
|
+
glob: "^13.0.0",
|
|
121
|
+
};
|
|
122
|
+
|
|
116
123
|
/**
|
|
117
124
|
* pnpm settings this engine applies to every workspace, beyond members, catalog,
|
|
118
125
|
* and allowances. Each is stated because pnpm's own default is the weaker choice
|
|
@@ -173,7 +180,7 @@ export class PnpmWorkspaceState {
|
|
|
173
180
|
this.allowBuilds = { ...DEFAULT_ALLOW_BUILDS, ...options.allowBuilds };
|
|
174
181
|
// Seeded even when empty so `addOverride` has a reference projen already
|
|
175
182
|
// captured; projen's `omitEmpty` drops the key while it stays empty.
|
|
176
|
-
this.overrides = { ...options.workspaceYaml?.overrides };
|
|
183
|
+
this.overrides = { ...DEFAULT_OVERRIDES, ...options.workspaceYaml?.overrides };
|
|
177
184
|
this.options = {
|
|
178
185
|
...DEFAULT_WORKSPACE_YAML,
|
|
179
186
|
...options.workspaceYaml,
|
package/src/project-js.ts
CHANGED
|
@@ -236,6 +236,46 @@ export function addExports(pkg: javascript.NodeProject, exports: Record<string,
|
|
|
236
236
|
});
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
+
function dependencyName(spec: string): string {
|
|
240
|
+
if (!spec.startsWith("@")) return spec.split("@", 1)[0]!;
|
|
241
|
+
const versionSeparator = spec.indexOf("@", spec.indexOf("/") + 1);
|
|
242
|
+
return versionSeparator < 0 ? spec : spec.slice(0, versionSeparator);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/** Add an optional peer and make it available while developing the package. */
|
|
246
|
+
export function addOptionalPeer(pkg: javascript.NodeProject, spec: string): void {
|
|
247
|
+
const name = dependencyName(spec);
|
|
248
|
+
const current = object.isRecord(pkg.package.manifest.peerDependenciesMeta)
|
|
249
|
+
? pkg.package.manifest.peerDependenciesMeta
|
|
250
|
+
: {};
|
|
251
|
+
pkg.addPeerDeps(spec);
|
|
252
|
+
pkg.package.addField("peerDependenciesMeta", {
|
|
253
|
+
...current,
|
|
254
|
+
[name]: { optional: true },
|
|
255
|
+
});
|
|
256
|
+
pkg.addDevDeps(spec);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/** Resolve repository metadata already configured on a Node project. */
|
|
260
|
+
export function projectRepositoryUrl(project: javascript.NodeProject): string | undefined {
|
|
261
|
+
const repository = project.package.manifest.repository;
|
|
262
|
+
const configured =
|
|
263
|
+
typeof repository === "string"
|
|
264
|
+
? repository
|
|
265
|
+
: object.isRecord(repository)
|
|
266
|
+
? (string.trimToNull(repository.url) ?? undefined)
|
|
267
|
+
: undefined;
|
|
268
|
+
return configured?.replace(/^git\+/, "").replace(/\.git$/, "");
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/** Resolve the branch release workflows use for a generated project. */
|
|
272
|
+
export function projectReleaseBranch(project: javascript.NodeProject): string {
|
|
273
|
+
return (
|
|
274
|
+
(project as javascript.NodeProject & { readonly releaseBranch?: string }).releaseBranch ??
|
|
275
|
+
"main"
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
|
|
239
279
|
/**
|
|
240
280
|
* MERGE entries onto a package's npm `files` allowlist - the only paths that
|
|
241
281
|
* ship in the published tarball. npm always includes `package.json`, `README`,
|
|
@@ -559,7 +599,8 @@ export class DBXToolsNodeProject
|
|
|
559
599
|
pnpmWorkspace?: PnpmWorkspaceState;
|
|
560
600
|
rootTsconfig?: DBXToolsRootTsconfig;
|
|
561
601
|
vsCode?: DBXToolsVsCode;
|
|
562
|
-
|
|
602
|
+
readonly extraWorkspaceMembers: readonly string[];
|
|
603
|
+
readonly releaseBranch: string;
|
|
563
604
|
private readonly rootInstallOnly: boolean;
|
|
564
605
|
|
|
565
606
|
constructor(options: DBXToolsJavaScriptProjectOptions = {}) {
|
|
@@ -595,6 +636,7 @@ export class DBXToolsNodeProject
|
|
|
595
636
|
this.package.addField("version", readWorkspaceVersion(this.outdir));
|
|
596
637
|
this.scope = scope;
|
|
597
638
|
this.extraWorkspaceMembers = options.extraWorkspaceMembers ?? [];
|
|
639
|
+
this.releaseBranch = options.defaultReleaseBranch ?? "main";
|
|
598
640
|
this.rootInstallOnly = options.rootInstallOnly !== false;
|
|
599
641
|
this.dbxToolsConfig = new DBXToolsConfig(this, options);
|
|
600
642
|
initProject(this, options);
|
|
@@ -773,13 +815,13 @@ class WorkspaceValidationTasks extends Component {
|
|
|
773
815
|
}
|
|
774
816
|
|
|
775
817
|
/**
|
|
776
|
-
*
|
|
818
|
+
* Apply bounded, read-only, supersedable defaults to validation workflows.
|
|
777
819
|
*
|
|
778
820
|
* Projen otherwise leaves jobs at GitHub's six-hour ceiling. Missing workflows
|
|
779
821
|
* are a no-op, so roots that keep the engine defaults (`github`/build workflow
|
|
780
822
|
* off) do not gain new files.
|
|
781
823
|
*/
|
|
782
|
-
class
|
|
824
|
+
class WorkflowDefaults extends Component {
|
|
783
825
|
public override preSynthesize(): void {
|
|
784
826
|
const build = this.project.tryFindObjectFile(".github/workflows/build.yml");
|
|
785
827
|
for (const job of ["build", "self-mutation"]) {
|
|
@@ -788,6 +830,14 @@ class WorkflowTimeouts extends Component {
|
|
|
788
830
|
this.project
|
|
789
831
|
.tryFindObjectFile(".github/workflows/pull-request-lint.yml")
|
|
790
832
|
?.addOverride("jobs.validate.timeout-minutes", 10);
|
|
833
|
+
for (const name of ["build", "pull-request-lint"]) {
|
|
834
|
+
const workflow = this.project.tryFindObjectFile(`.github/workflows/${name}.yml`);
|
|
835
|
+
workflow?.addOverride("permissions", { contents: "read" });
|
|
836
|
+
workflow?.addOverride("concurrency", {
|
|
837
|
+
group: "${{ github.workflow }}-${{ github.ref }}",
|
|
838
|
+
"cancel-in-progress": true,
|
|
839
|
+
});
|
|
840
|
+
}
|
|
791
841
|
}
|
|
792
842
|
}
|
|
793
843
|
|
|
@@ -839,6 +889,10 @@ class PrettierIgnoreGenerated extends Component {
|
|
|
839
889
|
prettier.addIgnorePattern(`${rel}/${module}`);
|
|
840
890
|
}
|
|
841
891
|
}
|
|
892
|
+
const extraMembers = (this.project as DBXToolsNodeProject).extraWorkspaceMembers ?? [];
|
|
893
|
+
for (const member of extraMembers) {
|
|
894
|
+
prettier.addIgnorePattern(`${member}/index.ts`);
|
|
895
|
+
}
|
|
842
896
|
}
|
|
843
897
|
}
|
|
844
898
|
|
|
@@ -1021,7 +1075,7 @@ function initProject(
|
|
|
1021
1075
|
// always apply; the self-dep is added only when the engine is an installed pkg.
|
|
1022
1076
|
const selfDep = engineSelfDependency(project);
|
|
1023
1077
|
if (selfDep) project.addDevDeps(selfDep);
|
|
1024
|
-
project.addDevDeps(...DEV_DEPS_ROOT);
|
|
1078
|
+
project.addDevDeps(...DEV_DEPS_ROOT, "concurrently@catalog:");
|
|
1025
1079
|
configureRootPackage(project);
|
|
1026
1080
|
// Root carries the bare `repository` (no `directory`); children add their subpath.
|
|
1027
1081
|
applyRepository(project, options.repository);
|
|
@@ -1058,6 +1112,11 @@ function initProject(
|
|
|
1058
1112
|
project.annotateGenerated(`/${root}/**/index.ts`);
|
|
1059
1113
|
project.annotateGenerated(`/${root}/openapi/**`);
|
|
1060
1114
|
}
|
|
1115
|
+
const extraWorkspaceMembers =
|
|
1116
|
+
project instanceof DBXToolsNodeProject ? project.extraWorkspaceMembers : [];
|
|
1117
|
+
for (const member of extraWorkspaceMembers) {
|
|
1118
|
+
project.annotateGenerated(`/${member}/index.ts`);
|
|
1119
|
+
}
|
|
1061
1120
|
|
|
1062
1121
|
// ESLint lives ONLY on the root and lints every package. `projectService` resolves
|
|
1063
1122
|
// each file to its own package tsconfig (so type-aware rules work tree-wide), and
|
|
@@ -1178,7 +1237,7 @@ function initProject(
|
|
|
1178
1237
|
}
|
|
1179
1238
|
|
|
1180
1239
|
new WorkspaceValidationTasks(project);
|
|
1181
|
-
new
|
|
1240
|
+
new WorkflowDefaults(project);
|
|
1182
1241
|
new PrettierIgnoreGenerated(project);
|
|
1183
1242
|
|
|
1184
1243
|
new GeneratedSource(project);
|