@dbx-tools/projen 0.9.19 → 0.9.28
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 +83 -229
- package/index.ts +11 -18
- package/package.json +9 -5
- package/src/_task-command.ts +75 -0
- package/src/barrels.ts +1 -74
- package/src/module-exports.ts +175 -1
- package/src/openapi.ts +5 -72
- package/src/packages.ts +45 -0
- package/src/project-js.ts +5 -48
- package/src/project-predicate.ts +1 -2
- package/src/project-py.ts +87 -199
- package/src/project.ts +2 -2
- package/src/python-node-bindings.ts +138 -0
- package/src/python-node-bundle.ts +92 -0
- package/src/release-catalog.ts +40 -208
- package/src/{release-dispatch.ts → release-context.ts} +0 -11
- package/src/release.ts +74 -778
- package/src/scaffold.ts +2 -6
- package/src/workspace-version.ts +9 -121
- package/tasks/bump.ts +17 -34
- package/tasks/databricks-cli-assets.ts +129 -0
- package/tasks/local-publish.ts +61 -138
- package/tasks/publish-npm.ts +71 -30
- package/tasks/publish-python.ts +61 -148
- package/tasks/publish.ts +32 -182
- package/tasks/python-node-bindings-watch.ts +47 -0
- package/tasks/python-node-bindings.ts +1017 -0
- package/tasks/python-registry.ts +2 -9
- package/tasks/python-release.ts +74 -0
- package/tasks/release-version.ts +23 -2
- package/tasks/release.ts +99 -0
- package/tasks/sync.ts +13 -18
- package/tasks/version-check.ts +13 -72
- package/src/_rust-project.ts +0 -429
- package/src/_rust-release-workflow.ts +0 -698
- package/src/project-rs.ts +0 -1127
- package/src/release-plan.ts +0 -269
- package/src/release-please.ts +0 -242
- package/src/uniffi.ts +0 -65
- package/tasks/publish-uniffi-local.ts +0 -314
- package/tasks/release-assets.ts +0 -476
- package/tasks/release-bootstrap.ts +0 -59
- package/tasks/release-candidate.ts +0 -383
- package/tasks/release-manifest.ts +0 -273
- package/tasks/release-plan.ts +0 -89
- package/tasks/release-please.ts +0 -162
- package/tasks/release-pr.ts +0 -563
- package/tasks/release-request.ts +0 -166
- package/tasks/release-summary-units.ts +0 -75
- package/tasks/release-summary.ts +0 -381
- package/tasks/rust.ts +0 -178
- package/tasks/stamp-python.ts +0 -13
- package/tasks/uniffi-python.d.ts +0 -61
- package/tasks/uniffi-python.js +0 -191
- package/tasks/uniffi-release.mjs +0 -573
- package/tasks/uniffi.ts +0 -271
package/tasks/publish.ts
CHANGED
|
@@ -1,73 +1,52 @@
|
|
|
1
1
|
#!/usr/bin/env -S bun
|
|
2
2
|
/**
|
|
3
3
|
* `bun tasks/publish.ts <version> [--registry <url>] [--exclude <dir>] [--dry-run] [--skip-compile]`
|
|
4
|
-
* - verify every workspace member
|
|
5
|
-
*
|
|
4
|
+
* - verify every workspace member carries the release version, then pack and
|
|
5
|
+
* publish each package owned by the standard Node release.
|
|
6
6
|
*
|
|
7
7
|
* Bun has no `pnpm -r publish`, so this loop is the recursive-publish stand-in.
|
|
8
8
|
* It leans on native bun for everything bun already does:
|
|
9
9
|
*
|
|
10
10
|
* - **version validation** fails when any member differs from the reviewed
|
|
11
11
|
* `VERSION`; publication never repairs committed release metadata;
|
|
12
|
-
* - **`workspace:` / `catalog:` rewriting** is NOT done here - `bun
|
|
12
|
+
* - **`workspace:` / `catalog:` rewriting** is NOT done here - `bun pm pack`
|
|
13
13
|
* strips both protocols in the PACKED tarball, resolving `workspace:*` to the
|
|
14
14
|
* sibling's version and `catalog:` to the root catalog entry. (Verified: a
|
|
15
15
|
* packed manifest shows `"@scope/x": "<version>"` and the real catalog range,
|
|
16
16
|
* while the on-disk manifest keeps the protocols.) Setting each member's
|
|
17
17
|
* version first is the only prerequisite, so a sibling resolves the release
|
|
18
|
-
* version. When Bun's workspace lock already carries the version, its
|
|
19
|
-
* refresh is skipped;
|
|
20
18
|
* - **`publishConfig` substitution** (compiled `lib/` entry points) is done
|
|
21
|
-
*
|
|
19
|
+
* inside the temporary archive, NOT in the checkout: unlike pnpm/npm, `bun
|
|
22
20
|
* publish`/`bun pm pack` do NOT fold `publishConfig`'s `main`/`types`/`bin`/
|
|
23
21
|
* `exports` into the packed manifest (verified: the packed manifest keeps the
|
|
24
22
|
* raw `.ts` source paths and an inert `publishConfig`). Left unsubstituted, a
|
|
25
23
|
* published CLI's `bin` points at `./bin/x.ts`, and because the bin runs via
|
|
26
24
|
* its `#!/usr/bin/env node` shebang, node chokes on the `.ts`
|
|
27
25
|
* (ERR_UNKNOWN_FILE_EXTENSION). We merge `publishConfig` onto the top-level
|
|
28
|
-
* manifest
|
|
26
|
+
* manifest after packing so the tarball advertises the compiled `lib/` tree;
|
|
29
27
|
* - **compiled output** is emitted once, before packing, by one root-level
|
|
30
28
|
* filtered `bun run` that fans out to every publishable member in parallel.
|
|
31
29
|
* Every package is then packed once with lifecycle scripts disabled. The
|
|
32
|
-
* exact validated archive is passed to `
|
|
30
|
+
* exact validated archive is passed to `npm publish`, so upload never
|
|
33
31
|
* repacks or repeats a member's `prepack`. Packages retain `prepack` for
|
|
34
32
|
* standalone publishes.
|
|
35
33
|
* - **release recovery** compares each packed archive's integrity and
|
|
36
34
|
* repository identity with registry metadata. A matching immutable version
|
|
37
35
|
* is skipped, while any mismatch fails the retry.
|
|
38
36
|
*
|
|
39
|
-
* `--dry-run` forwards to `
|
|
40
|
-
* but uploads nothing
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* repo-relative) skips a member owned by another publication flow.
|
|
37
|
+
* `--dry-run` forwards to `npm publish`: it packs + validates
|
|
38
|
+
* but uploads nothing. `--registry` targets a non-default registry (a local
|
|
39
|
+
* verdaccio); `--exclude <dir>` (repeatable, repo-relative) skips a member owned
|
|
40
|
+
* by another publication flow.
|
|
44
41
|
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* The disk manifests carry the workspace `VERSION` (projen owns them, read-only);
|
|
49
|
-
* this unlocks each only long enough to fold in the `publishConfig` entry points
|
|
50
|
-
* and publish, then RESTORES every one it touched
|
|
51
|
-
* byte-for-byte (and re-locks the mode) on the way out - see
|
|
52
|
-
* {@link restoreManifests}. Restore returns each manifest to its committed
|
|
53
|
-
* content, which already equals the release version, so the worktree is never
|
|
54
|
-
* left regressed.
|
|
42
|
+
* The checkout remains byte-for-byte unchanged. A stale manifest is a release
|
|
43
|
+
* error rather than something publication repairs. Local lockfiles are ignored
|
|
44
|
+
* because configured registries can leak into them.
|
|
55
45
|
*/
|
|
56
|
-
import {
|
|
57
|
-
chmodSync,
|
|
58
|
-
copyFileSync,
|
|
59
|
-
existsSync,
|
|
60
|
-
mkdirSync,
|
|
61
|
-
mkdtempSync,
|
|
62
|
-
readFileSync,
|
|
63
|
-
rmSync,
|
|
64
|
-
statSync,
|
|
65
|
-
writeFileSync,
|
|
66
|
-
} from "node:fs";
|
|
46
|
+
import { copyFileSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
67
47
|
import { tmpdir } from "node:os";
|
|
68
48
|
import { delimiter, dirname, join, resolve } from "node:path";
|
|
69
49
|
import { asyncUtils, log } from "@dbx-tools/shared-core";
|
|
70
|
-
import ts from "typescript";
|
|
71
50
|
import { parse } from "yaml";
|
|
72
51
|
import {
|
|
73
52
|
npmReleaseMatches,
|
|
@@ -76,26 +55,9 @@ import {
|
|
|
76
55
|
readNpmArchiveIdentity,
|
|
77
56
|
} from "./publish-npm.ts";
|
|
78
57
|
import { runTaskCommand, runTaskCommandAsync } from "../src/_task-command.ts";
|
|
79
|
-
import { toPosix } from "../src/packages.ts";
|
|
80
|
-
import type { ReleasePlan } from "../src/release-plan.ts";
|
|
81
58
|
|
|
82
59
|
const logger = log.logger("projen:publish");
|
|
83
60
|
|
|
84
|
-
/** A manifest's on-disk bytes + mode, captured before this task edits it. */
|
|
85
|
-
interface ManifestBackup {
|
|
86
|
-
readonly content: string;
|
|
87
|
-
readonly mode: number;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Original state of every manifest this task has unlocked, keyed by path.
|
|
92
|
-
*
|
|
93
|
-
* Bun does not apply `publishConfig` while packing, so publication temporarily
|
|
94
|
-
* projects those entry points onto projen-owned manifests. The projection is
|
|
95
|
-
* only meant for the packed tarball and is restored before the process exits.
|
|
96
|
-
*/
|
|
97
|
-
const manifestBackups = new Map<string, ManifestBackup>();
|
|
98
|
-
|
|
99
61
|
/**
|
|
100
62
|
* Workspace member dirs (absolute), read from the root `pnpm-workspace.yaml` - the
|
|
101
63
|
* file the engine keeps for the Databricks Apps pnpm deploy, which also lists every
|
|
@@ -109,78 +71,16 @@ function workspaceMembers(root: string): string[] {
|
|
|
109
71
|
return (doc?.packages ?? []).map((m) => resolve(root, m));
|
|
110
72
|
}
|
|
111
73
|
|
|
112
|
-
/** Whether selected workspace members carry
|
|
113
|
-
function
|
|
114
|
-
root: string,
|
|
115
|
-
members: readonly string[],
|
|
116
|
-
expected: ReadonlyMap<string, string>,
|
|
117
|
-
): boolean {
|
|
74
|
+
/** Whether selected workspace members carry the reviewed workspace version. */
|
|
75
|
+
function manifestsMatchVersion(members: readonly string[], version: string): boolean {
|
|
118
76
|
return members.every((dir) => {
|
|
119
77
|
const pkg = JSON.parse(readFileSync(join(dir, "package.json"), "utf8")) as {
|
|
120
78
|
version?: string;
|
|
121
79
|
};
|
|
122
|
-
|
|
123
|
-
return pkg.version === expected.get(path);
|
|
80
|
+
return pkg.version === version;
|
|
124
81
|
});
|
|
125
82
|
}
|
|
126
83
|
|
|
127
|
-
/** Whether Bun's workspace lock records each live workspace manifest version. */
|
|
128
|
-
function lockfileMatchesManifestVersions(root: string, members: readonly string[]): boolean {
|
|
129
|
-
const lockfile = join(root, "bun.lock");
|
|
130
|
-
if (!existsSync(lockfile)) return false;
|
|
131
|
-
try {
|
|
132
|
-
const parsed = ts.parseConfigFileTextToJson(lockfile, readFileSync(lockfile, "utf8"));
|
|
133
|
-
if (parsed.error) return false;
|
|
134
|
-
const lock = parsed.config as {
|
|
135
|
-
workspaces?: Record<string, { version?: string }>;
|
|
136
|
-
};
|
|
137
|
-
return members.every((dir) => {
|
|
138
|
-
const manifest = JSON.parse(readFileSync(join(dir, "package.json"), "utf8")) as {
|
|
139
|
-
version?: string;
|
|
140
|
-
};
|
|
141
|
-
const relative = toPosix(dir.slice(resolve(root).length + 1));
|
|
142
|
-
return lock.workspaces?.[relative]?.version === manifest.version;
|
|
143
|
-
});
|
|
144
|
-
} catch {
|
|
145
|
-
return false;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Make a projen-readonly manifest writable so the publishConfig projection can
|
|
151
|
-
* edit it, recording its original bytes and mode for {@link restoreManifests}
|
|
152
|
-
* the first time it is seen.
|
|
153
|
-
*/
|
|
154
|
-
function unlockManifest(pkgPath: string): void {
|
|
155
|
-
const mode = statSync(pkgPath).mode;
|
|
156
|
-
if (!manifestBackups.has(pkgPath)) {
|
|
157
|
-
manifestBackups.set(pkgPath, { content: readFileSync(pkgPath, "utf8"), mode });
|
|
158
|
-
}
|
|
159
|
-
chmodSync(pkgPath, mode | 0o200);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Put every manifest this task edited back exactly as it was found, mode included.
|
|
164
|
-
*
|
|
165
|
-
* Runs from an `exit` handler so a clean finish and a failure partway through the
|
|
166
|
-
* publish loop are covered alike - a `bun publish` that dies on package 12 of 34
|
|
167
|
-
* must not leave the first 11 projected. Best-effort per file: one unwritable
|
|
168
|
-
* manifest is logged and the rest are still restored, since a partial restore
|
|
169
|
-
* beats none.
|
|
170
|
-
*/
|
|
171
|
-
function restoreManifests(): void {
|
|
172
|
-
for (const [pkgPath, backup] of manifestBackups) {
|
|
173
|
-
try {
|
|
174
|
-
chmodSync(pkgPath, backup.mode | 0o200);
|
|
175
|
-
writeFileSync(pkgPath, backup.content);
|
|
176
|
-
chmodSync(pkgPath, backup.mode);
|
|
177
|
-
} catch (cause) {
|
|
178
|
-
logger.warn(`could not restore ${pkgPath}`, { cause });
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
manifestBackups.clear();
|
|
182
|
-
}
|
|
183
|
-
|
|
184
84
|
/** Entry-point fields projen writes as `.ts` source in-repo and rewrites to `lib/` for publish. */
|
|
185
85
|
const PUBLISH_CONFIG_ENTRY_FIELDS = ["main", "types", "bin", "exports"] as const;
|
|
186
86
|
|
|
@@ -195,23 +95,18 @@ function compiledPublishTargets(value: unknown): string[] {
|
|
|
195
95
|
/**
|
|
196
96
|
* Fold a package's `publishConfig` entry-point fields onto the top-level manifest,
|
|
197
97
|
* the way pnpm/npm do at pack time but `bun publish` does NOT (see the module
|
|
198
|
-
* doc).
|
|
199
|
-
* in place (npm ignores it once the top-level fields already point at `lib/`). The
|
|
200
|
-
* manifest must already be unlocked. {@link restoreManifests} puts the `.ts` entry
|
|
201
|
-
* points back at exit, so this only ever affects the packed tarball.
|
|
98
|
+
* doc). The input is the temporary archive manifest, never the checkout.
|
|
202
99
|
*/
|
|
203
|
-
function applyPublishConfig(
|
|
204
|
-
|
|
100
|
+
export function applyPublishConfig(
|
|
101
|
+
source: Readonly<Record<string, unknown>>,
|
|
102
|
+
): Readonly<Record<string, unknown>> {
|
|
103
|
+
const pkg = { ...source };
|
|
205
104
|
const publishConfig = pkg.publishConfig as Record<string, unknown> | undefined;
|
|
206
|
-
if (!publishConfig) return;
|
|
207
|
-
let changed = false;
|
|
105
|
+
if (!publishConfig) return pkg;
|
|
208
106
|
for (const field of PUBLISH_CONFIG_ENTRY_FIELDS) {
|
|
209
|
-
if (field in publishConfig)
|
|
210
|
-
pkg[field] = publishConfig[field];
|
|
211
|
-
changed = true;
|
|
212
|
-
}
|
|
107
|
+
if (field in publishConfig) pkg[field] = publishConfig[field];
|
|
213
108
|
}
|
|
214
|
-
|
|
109
|
+
return pkg;
|
|
215
110
|
}
|
|
216
111
|
|
|
217
112
|
/**
|
|
@@ -229,14 +124,9 @@ const argv = process.argv.slice(2);
|
|
|
229
124
|
const version = argv[0] && !argv[0].startsWith("--") ? argv[0] : undefined;
|
|
230
125
|
const rest = version ? argv.slice(1) : argv;
|
|
231
126
|
const root = process.cwd();
|
|
232
|
-
|
|
233
|
-
const plan =
|
|
234
|
-
planIdx >= 0
|
|
235
|
-
? (JSON.parse(readFileSync(resolve(root, rest[planIdx + 1]), "utf8")) as ReleasePlan)
|
|
236
|
-
: undefined;
|
|
237
|
-
if (!version && !plan) {
|
|
127
|
+
if (!version) {
|
|
238
128
|
logger.error(
|
|
239
|
-
"usage: bun tasks/publish.ts <version> [--
|
|
129
|
+
"usage: bun tasks/publish.ts <version> [--registry <url>] [--output <dir>] [--exclude <dir>] [--dry-run] [--skip-compile]",
|
|
240
130
|
);
|
|
241
131
|
process.exit(1);
|
|
242
132
|
}
|
|
@@ -252,47 +142,21 @@ if (!Number.isInteger(parsedConcurrency) || parsedConcurrency < 1) {
|
|
|
252
142
|
throw new Error(`--concurrency must be a positive integer, got ${String(parsedConcurrency)}`);
|
|
253
143
|
}
|
|
254
144
|
const concurrency = parsedConcurrency;
|
|
255
|
-
// Undo transient publishConfig edits at exit.
|
|
256
|
-
const restore = !rest.includes("--no-restore");
|
|
257
145
|
const excluded = new Set(
|
|
258
146
|
rest.reduce<string[]>((acc, arg, i) => (arg === "--exclude" ? [...acc, rest[i + 1]] : acc), []),
|
|
259
147
|
);
|
|
260
148
|
|
|
261
149
|
const path = enrichedPath(root);
|
|
262
|
-
// Registered BEFORE the first manifest edit so no exit path can skip it: a clean
|
|
263
|
-
// finish and a `bun publish` failure mid-loop both land here, so a publish that
|
|
264
|
-
// dies partway does not leave half the workspace stamped.
|
|
265
|
-
if (restore) process.on("exit", restoreManifests);
|
|
266
150
|
const allMembers = workspaceMembers(root)
|
|
267
151
|
.filter((dir) => existsSync(join(dir, "package.json")))
|
|
268
152
|
.filter((dir) => !excluded.has(resolve(root, dir).replace(`${resolve(root)}/`, "")));
|
|
269
|
-
const
|
|
270
|
-
plan
|
|
271
|
-
? plan.nodePackages.map((pkg) => [pkg.path, pkg.version] as const)
|
|
272
|
-
: allMembers.map((dir) => [toPosix(dir.slice(resolve(root).length + 1)), version!]),
|
|
273
|
-
);
|
|
274
|
-
const members = plan
|
|
275
|
-
? allMembers.filter((dir) => expectedVersions.has(toPosix(dir.slice(resolve(root).length + 1))))
|
|
276
|
-
: allMembers;
|
|
153
|
+
const members = allMembers;
|
|
277
154
|
|
|
278
|
-
if (!
|
|
279
|
-
throw new Error(
|
|
155
|
+
if (!manifestsMatchVersion(members, version)) {
|
|
156
|
+
throw new Error(`workspace manifests do not match release ${version}; run projen`);
|
|
280
157
|
}
|
|
281
158
|
logger.info(`validated ${members.length} selected member manifests`);
|
|
282
159
|
|
|
283
|
-
// Ensure the lockfile resolves each `workspace:*` to the release version.
|
|
284
|
-
// `bun publish`/`pm pack` reads workspace versions from the LOCKFILE, not just
|
|
285
|
-
// live manifests. A normal bump's synth/install already makes it current; after
|
|
286
|
-
// fallback stamping, deleting it before install is what forces re-resolution.
|
|
287
|
-
const lockfile = join(root, "bun.lock");
|
|
288
|
-
if (lockfileMatchesManifestVersions(root, allMembers)) {
|
|
289
|
-
logger.info("workspace lock already resolves live member versions");
|
|
290
|
-
} else {
|
|
291
|
-
if (existsSync(lockfile)) rmSync(lockfile);
|
|
292
|
-
logger.info("refreshing lockfile so workspace deps resolve to the release version");
|
|
293
|
-
runTaskCommand(root, "bun", ["install"], { env: { ...process.env, PATH: path } });
|
|
294
|
-
}
|
|
295
|
-
|
|
296
160
|
const publishArgs = [
|
|
297
161
|
"--ignore-scripts",
|
|
298
162
|
...(registry ? ["--registry", registry] : []),
|
|
@@ -311,17 +175,12 @@ for (const dir of members) {
|
|
|
311
175
|
name?: string;
|
|
312
176
|
version?: string;
|
|
313
177
|
private?: boolean;
|
|
314
|
-
dbxToolsConfig?: { uniffi?: boolean };
|
|
315
178
|
publishConfig?: { access?: unknown };
|
|
316
179
|
};
|
|
317
180
|
if (pkg.private) {
|
|
318
181
|
logger.info(`skip private ${pkg.name ?? dirname(dir)}`);
|
|
319
182
|
continue;
|
|
320
183
|
}
|
|
321
|
-
if (pkg.dbxToolsConfig?.uniffi === true) {
|
|
322
|
-
logger.info(`skip UniFFI ${pkg.name ?? dirname(dir)}`);
|
|
323
|
-
continue;
|
|
324
|
-
}
|
|
325
184
|
if (!pkg.version) throw new Error(`Missing package version for ${pkg.name ?? dirname(dir)}`);
|
|
326
185
|
const access = pkg.publishConfig?.access;
|
|
327
186
|
if (access !== undefined && access !== "public" && access !== "restricted") {
|
|
@@ -365,15 +224,6 @@ if (compiled.length > 0) {
|
|
|
365
224
|
}
|
|
366
225
|
}
|
|
367
226
|
|
|
368
|
-
// Compile against workspace source exports first. Switching manifests to their
|
|
369
|
-
// publishConfig entries before compilation makes consumers resolve sibling
|
|
370
|
-
// `lib/*.d.ts` files that have not been emitted yet in a clean checkout.
|
|
371
|
-
for (const { dir } of publishable) {
|
|
372
|
-
const manifestPath = join(dir, "package.json");
|
|
373
|
-
unlockManifest(manifestPath);
|
|
374
|
-
applyPublishConfig(manifestPath);
|
|
375
|
-
}
|
|
376
|
-
|
|
377
227
|
logger.info(
|
|
378
228
|
`${output ? "packing" : dryRun ? "dry-run packing" : "publishing"} ${publishable.length} packages with concurrency ${concurrency}`,
|
|
379
229
|
);
|
|
@@ -386,7 +236,7 @@ await asyncUtils.mapConcurrent(
|
|
|
386
236
|
async ({ dir, name, version: packageVersion, access }) => {
|
|
387
237
|
const packed = mkdtempSync(join(tmpdir(), "projen-npm-release-"));
|
|
388
238
|
try {
|
|
389
|
-
const archive = packNpmPackage(dir, packed, path);
|
|
239
|
+
const archive = packNpmPackage(dir, packed, path, applyPublishConfig);
|
|
390
240
|
const local = readNpmArchiveIdentity(archive);
|
|
391
241
|
if (local.name !== name || local.version !== packageVersion) {
|
|
392
242
|
throw new Error(
|
|
@@ -417,7 +267,7 @@ await asyncUtils.mapConcurrent(
|
|
|
417
267
|
logger.info(`${dryRun ? "dry-run publishing" : "publishing"} ${name} @ ${packageVersion}`);
|
|
418
268
|
await runTaskCommandAsync(
|
|
419
269
|
dir,
|
|
420
|
-
"
|
|
270
|
+
"npm",
|
|
421
271
|
["publish", ...(access ? ["--access", access] : []), ...publishArgs, archive],
|
|
422
272
|
{ env: { ...process.env, PATH: path } },
|
|
423
273
|
);
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env -S bun
|
|
2
|
+
import { dirname, isAbsolute, resolve, sep } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { parseArgs } from "node:util";
|
|
5
|
+
import { log } from "@dbx-tools/shared-core";
|
|
6
|
+
import { runTaskCommand } from "../src/_task-command.ts";
|
|
7
|
+
import { pythonNodeBindingProjects, repoRoot } from "../src/packages.ts";
|
|
8
|
+
import {
|
|
9
|
+
pythonNodeBindingWatchInputs,
|
|
10
|
+
resolvePythonNodeBindings,
|
|
11
|
+
type ResolvedPythonNodeBindings,
|
|
12
|
+
} from "../src/python-node-bindings.ts";
|
|
13
|
+
import { watchLoop } from "../src/watch.ts";
|
|
14
|
+
|
|
15
|
+
const logger = log.logger("projen:python-node-bindings");
|
|
16
|
+
const task = resolve(dirname(fileURLToPath(import.meta.url)), "python-node-bindings.ts");
|
|
17
|
+
const { values } = parseArgs({ options: { project: { type: "string" } } });
|
|
18
|
+
const projects = values.project ? [values.project] : pythonNodeBindingProjects(repoRoot);
|
|
19
|
+
const configs = projects.map((project) => resolvePythonNodeBindings(repoRoot, project));
|
|
20
|
+
|
|
21
|
+
if (configs.length > 0) {
|
|
22
|
+
watchLoop(
|
|
23
|
+
"python-node-bindings",
|
|
24
|
+
[...new Set(configs.flatMap(pythonNodeBindingWatchInputs))],
|
|
25
|
+
(changed) => {
|
|
26
|
+
for (const config of configs.filter((candidate) => affected(candidate, changed))) {
|
|
27
|
+
logger.start(`generating ${config.project} Node bindings`);
|
|
28
|
+
runTaskCommand(repoRoot, "bun", [task, "--project", config.project]);
|
|
29
|
+
logger.success(`generated ${config.project} Node bindings`);
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
check: (changed) => configs.some((config) => affected(config, changed)),
|
|
34
|
+
},
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function affected(config: ResolvedPythonNodeBindings, changed: readonly string[]): boolean {
|
|
39
|
+
const inputs = pythonNodeBindingWatchInputs(config);
|
|
40
|
+
return changed.some((path) => inputs.some((input) => contains(input, path)));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function contains(input: string, candidate: string): boolean {
|
|
44
|
+
const root = isAbsolute(input) ? input : resolve(repoRoot, input);
|
|
45
|
+
const path = isAbsolute(candidate) ? candidate : resolve(repoRoot, candidate);
|
|
46
|
+
return path === root || path.startsWith(root + sep);
|
|
47
|
+
}
|