@dbx-tools/projen 0.9.153 → 0.9.157
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 +44 -52
- package/index.ts +43 -21
- package/package.json +8 -8
- package/src/_task-command.ts +7 -7
- package/src/appkit-workspace.ts +278 -104
- package/src/barrels.ts +147 -259
- package/src/bun-app.ts +54 -10
- package/src/clean.ts +6 -6
- package/src/engine-root.ts +4 -4
- package/src/mixin.ts +0 -2
- package/src/module-exports.ts +4 -5
- package/src/npm-packaging.ts +128 -0
- package/src/npm-release.ts +200 -0
- package/src/packages.ts +11 -11
- package/src/project-js.ts +209 -103
- package/src/project-predicate.ts +5 -12
- package/src/project-py.ts +8 -6
- package/src/project.ts +7 -14
- package/src/publish.ts +3 -3
- package/src/python-node-bindings.ts +16 -12
- package/src/python-packaging.ts +177 -0
- package/src/release-context.ts +4 -0
- package/src/release-options.ts +2 -2
- package/src/release.ts +133 -13
- package/src/shared-core-usage.ts +17 -4
- package/src/tags.ts +10 -9
- package/src/watch.ts +7 -9
- package/src/workspace-lock.ts +2 -2
- package/src/workspace-manifest.ts +2 -2
- package/tasks/appkit-deploy.ts +35 -15
- package/tasks/barrels.ts +6 -9
- package/tasks/bump.ts +1 -1
- package/tasks/clean.ts +3 -3
- package/tasks/cli.ts +3 -3
- package/tasks/compile-workspace.ts +8 -8
- package/tasks/dev-watch.ts +11 -11
- package/tasks/local-publish.ts +6 -6
- package/tasks/publish-npm.ts +11 -317
- package/tasks/publish-python.ts +2 -180
- package/tasks/publish.ts +6 -11
- package/tasks/python-node-bindings.ts +2 -2
- package/tasks/python-registry.ts +6 -6
- package/tasks/python-sync.ts +2 -3
- package/tasks/release-version.ts +1 -1
- package/tasks/release.ts +11 -11
- package/tasks/sync.ts +2 -2
- package/tasks/test-workspace.ts +9 -9
- package/tasks/verify-publications.ts +273 -0
- package/tasks/version-check.ts +5 -5
- /package/{tasks → src}/python-release.ts +0 -0
package/src/tags.ts
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* across the subtree; the root applies built-in tag mixins during construction and
|
|
14
14
|
* callers add their own afterward.
|
|
15
15
|
*/
|
|
16
|
+
import { relative } from "node:path";
|
|
16
17
|
import type { IMixin as ConstructsMixin } from "constructs";
|
|
17
18
|
import { DependencyType, javascript } from "projen";
|
|
18
19
|
import { BunBuildFile, BunDevServerFile, BunfigFile } from "./bun-app.ts";
|
|
@@ -23,7 +24,7 @@ import {
|
|
|
23
24
|
applyCompilerOptions,
|
|
24
25
|
applyExports,
|
|
25
26
|
applyIncludes,
|
|
26
|
-
|
|
27
|
+
srcFolderExports,
|
|
27
28
|
} from "./project-js.ts";
|
|
28
29
|
import * as projectPredicate from "./project-predicate.ts";
|
|
29
30
|
|
|
@@ -83,11 +84,13 @@ export const PACKAGE_TAG_MIXINS = {
|
|
|
83
84
|
applyCompilerOptions(p, {
|
|
84
85
|
target: "ES2022",
|
|
85
86
|
lib: [...DOM_LIB],
|
|
87
|
+
noEmit: true,
|
|
88
|
+
rootDir: relative(p.outdir, p.root.outdir).replaceAll("\\", "/") || ".",
|
|
86
89
|
});
|
|
87
|
-
// UI libraries
|
|
88
|
-
// and any other public source modules are discovered from the source tree.
|
|
90
|
+
// UI libraries expose their package barrel, folder barrels, and public CSS.
|
|
89
91
|
applyExports(p, {
|
|
90
|
-
|
|
92
|
+
".": "./index.ts",
|
|
93
|
+
...srcFolderExports(p),
|
|
91
94
|
"./package.json": "./package.json",
|
|
92
95
|
});
|
|
93
96
|
}),
|
|
@@ -149,13 +152,11 @@ export const PACKAGE_TAG_MIXINS = {
|
|
|
149
152
|
// A CLI compiles code OUTSIDE `src/` - its root `index.ts` barrel and the
|
|
150
153
|
// `bin/` entries - which the src-only tag default doesn't reach.
|
|
151
154
|
applyCompilerOptions(p, NODE_COMPILER_OPTIONS);
|
|
152
|
-
applyIncludes(p, "index
|
|
153
|
-
// A CLI's standard surface: the
|
|
154
|
-
// top-level `src` module, and `./package.json`. Derived rather than declared
|
|
155
|
-
// so no CLI has to hand-list its own modules.
|
|
155
|
+
applyIncludes(p, "index*.ts", "bin/**/*.ts");
|
|
156
|
+
// A CLI's standard surface: the root barrel, folder barrels, and package metadata.
|
|
156
157
|
applyExports(p, {
|
|
157
158
|
".": "./index.ts",
|
|
158
|
-
...
|
|
159
|
+
...srcFolderExports(p),
|
|
159
160
|
"./package.json": "./package.json",
|
|
160
161
|
});
|
|
161
162
|
// A CLI is the one shape whose entry point lives outside `src`, so its
|
package/src/watch.ts
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
* is thin glue.
|
|
17
17
|
*/
|
|
18
18
|
import { isAbsolute, resolve } from "node:path";
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
19
|
+
import { watchFiles } from "@dbx-tools/path";
|
|
20
|
+
import { log, sleep, toError } from "@dbx-tools/shared-core";
|
|
21
21
|
import { isGeneratedFile, recordedRoots, repoRoot } from "./packages.ts";
|
|
22
22
|
import { withWorkspaceMutationLock } from "./workspace-lock.ts";
|
|
23
23
|
|
|
@@ -49,9 +49,7 @@ const CLOSE_GRACE_MS = 2_000;
|
|
|
49
49
|
const FATAL_WATCH_ERROR_CODES = new Set(["EMFILE", "ENFILE", "ENOSPC"]);
|
|
50
50
|
|
|
51
51
|
/** node-path's built-in ignore-group toggles (`{ dot, temp, test, lock, defaults }`). */
|
|
52
|
-
export type IgnoreGroupOptions = NonNullable<
|
|
53
|
-
Parameters<typeof pathWatch.watchFiles>[1]
|
|
54
|
-
>["ignoreOptions"];
|
|
52
|
+
export type IgnoreGroupOptions = NonNullable<Parameters<typeof watchFiles>[1]>["ignoreOptions"];
|
|
55
53
|
|
|
56
54
|
/** The package roots (absolute), where every watchable source file lives. */
|
|
57
55
|
export function watchRoots(): string[] {
|
|
@@ -119,7 +117,7 @@ export async function watchLoop(
|
|
|
119
117
|
});
|
|
120
118
|
}
|
|
121
119
|
} catch (err) {
|
|
122
|
-
logger.error(`${tag} cycle failed`, { error:
|
|
120
|
+
logger.error(`${tag} cycle failed`, { error: toError(err) });
|
|
123
121
|
} finally {
|
|
124
122
|
running = false;
|
|
125
123
|
if (rerun) {
|
|
@@ -129,7 +127,7 @@ export async function watchLoop(
|
|
|
129
127
|
}
|
|
130
128
|
}
|
|
131
129
|
|
|
132
|
-
const watcher = await
|
|
130
|
+
const watcher = await watchFiles(paths, {
|
|
133
131
|
cwd: repoRoot,
|
|
134
132
|
ignoreInitial: true,
|
|
135
133
|
ignore: (path) => ignoredPath(path),
|
|
@@ -146,7 +144,7 @@ export async function watchLoop(
|
|
|
146
144
|
if (closing) return;
|
|
147
145
|
closing = true;
|
|
148
146
|
clearTimeout(timer);
|
|
149
|
-
await Promise.race([watcher.close().catch(() => {}),
|
|
147
|
+
await Promise.race([watcher.close().catch(() => {}), sleep(CLOSE_GRACE_MS)]);
|
|
150
148
|
process.exit(code);
|
|
151
149
|
}
|
|
152
150
|
|
|
@@ -156,7 +154,7 @@ export async function watchLoop(
|
|
|
156
154
|
timer = setTimeout(() => void flush(), DEBOUNCE_MS);
|
|
157
155
|
});
|
|
158
156
|
watcher.on("error", (err) => {
|
|
159
|
-
logger.error(`${tag} watcher error`, { error:
|
|
157
|
+
logger.error(`${tag} watcher error`, { error: toError(err) });
|
|
160
158
|
const code = (err as NodeJS.ErrnoException | undefined)?.code;
|
|
161
159
|
if (code === undefined || !FATAL_WATCH_ERROR_CODES.has(code)) return;
|
|
162
160
|
logger.error(`${tag}: ${code} leaves the watcher blind - exiting so it is restarted`);
|
package/src/workspace-lock.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Cross-process coordination for generated workspace mutations. */
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
|
-
import
|
|
3
|
+
import { withFileLock } from "@dbx-tools/core";
|
|
4
4
|
import { log } from "@dbx-tools/shared-core";
|
|
5
5
|
|
|
6
6
|
const MUTATION_LOCK_SCOPE = "dbx-tools-workspace-mutation";
|
|
@@ -36,7 +36,7 @@ export async function withWorkspaceMutationLock<T>(
|
|
|
36
36
|
}
|
|
37
37
|
let waitLogTimer: ReturnType<typeof setInterval> | undefined;
|
|
38
38
|
try {
|
|
39
|
-
return await
|
|
39
|
+
return await withFileLock(
|
|
40
40
|
[MUTATION_LOCK_SCOPE, repository],
|
|
41
41
|
async () => {
|
|
42
42
|
if (check && !(await check())) {
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
} from "node:fs";
|
|
18
18
|
import { tmpdir } from "node:os";
|
|
19
19
|
import { dirname, join, resolve } from "node:path";
|
|
20
|
-
import
|
|
20
|
+
import { spawnSync } from "@dbx-tools/core";
|
|
21
21
|
|
|
22
22
|
const DEPENDENCY_FIELDS = [
|
|
23
23
|
"dependencies",
|
|
@@ -102,7 +102,7 @@ export async function withStagedWorkspaceManifests<T>(
|
|
|
102
102
|
): Promise<T> {
|
|
103
103
|
const stage = mkdtempSync(join(tmpdir(), "dbx-tools-app-deploy-"));
|
|
104
104
|
try {
|
|
105
|
-
const listed =
|
|
105
|
+
const listed = spawnSync(
|
|
106
106
|
"git",
|
|
107
107
|
["ls-files", "--cached", "--others", "--exclude-standard", "-z"],
|
|
108
108
|
{
|
package/tasks/appkit-deploy.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env -S bun
|
|
2
2
|
/** Deploy an AppKit workspace through npm-compatible temporary manifests. */
|
|
3
|
-
import { existsSync, rmSync } from "node:fs";
|
|
4
|
-
import { join } from "node:path";
|
|
5
|
-
import {
|
|
3
|
+
import { cpSync, existsSync, rmSync } from "node:fs";
|
|
4
|
+
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
5
|
+
import { resolveProfile } from "@dbx-tools/auth";
|
|
6
6
|
import { serializeArgs } from "@dbx-tools/cli-args";
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
7
|
+
import { spawn, spawnSync } from "@dbx-tools/core";
|
|
8
|
+
import { log, toError } from "@dbx-tools/shared-core";
|
|
9
9
|
import { z } from "zod";
|
|
10
10
|
import { runTaskMain, taskCommand, taskOptions } from "./cli.ts";
|
|
11
11
|
import { withStagedWorkspaceManifests } from "../src/workspace-manifest.ts";
|
|
@@ -33,6 +33,13 @@ export const AppKitDeployContextOptionsSchema = z.object({
|
|
|
33
33
|
});
|
|
34
34
|
|
|
35
35
|
export const AppKitDeployOptionsSchema = AppKitDeployContextOptionsSchema.extend({
|
|
36
|
+
directory: z
|
|
37
|
+
.string()
|
|
38
|
+
.trim()
|
|
39
|
+
.min(1)
|
|
40
|
+
.default(".")
|
|
41
|
+
.describe("Application directory relative to the workspace root")
|
|
42
|
+
.meta({ env: [] }),
|
|
36
43
|
autoApprove: z
|
|
37
44
|
.boolean()
|
|
38
45
|
.default(false)
|
|
@@ -81,6 +88,17 @@ export async function deployApp(
|
|
|
81
88
|
): Promise<void> {
|
|
82
89
|
const root = dependencies.root ?? process.cwd();
|
|
83
90
|
const options = await resolveDeployOptions(args, dependencies);
|
|
91
|
+
const application = resolve(root, options.directory);
|
|
92
|
+
const applicationPath = relative(root, application);
|
|
93
|
+
if (!applicationPath || applicationPath.startsWith("..") || isAbsolute(applicationPath)) {
|
|
94
|
+
if (options.directory !== ".") {
|
|
95
|
+
throw new Error("Application directory must be inside the workspace root");
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const clientDist = join(application, "client", "dist");
|
|
99
|
+
if (!existsSync(clientDist)) {
|
|
100
|
+
throw new Error(`Built client is missing: ${clientDist}`);
|
|
101
|
+
}
|
|
84
102
|
const context = AppKitDeployContextOptionsSchema.parse({
|
|
85
103
|
target: options.target,
|
|
86
104
|
profile: options.profile,
|
|
@@ -99,7 +117,7 @@ export async function deployApp(
|
|
|
99
117
|
(dependencies.run
|
|
100
118
|
? undefined
|
|
101
119
|
: (validateArgs: readonly string[], cwd: string) =>
|
|
102
|
-
|
|
120
|
+
spawn(
|
|
103
121
|
"databricks",
|
|
104
122
|
["bundle", "validate", ...serializeArgs({ strict: true }), ...validateArgs],
|
|
105
123
|
{
|
|
@@ -111,7 +129,7 @@ export async function deployApp(
|
|
|
111
129
|
},
|
|
112
130
|
));
|
|
113
131
|
if (validate) {
|
|
114
|
-
const validation = await validate(contextArgs,
|
|
132
|
+
const validation = await validate(contextArgs, application);
|
|
115
133
|
if (validation.exitCode !== 0) {
|
|
116
134
|
throw new Error(`databricks bundle validate exited with code ${validation.exitCode}`);
|
|
117
135
|
}
|
|
@@ -119,7 +137,7 @@ export async function deployApp(
|
|
|
119
137
|
const run =
|
|
120
138
|
dependencies.run ??
|
|
121
139
|
((deployArgs: readonly string[], cwd: string) =>
|
|
122
|
-
|
|
140
|
+
spawn("databricks", ["apps", "deploy", ...deployArgs], {
|
|
123
141
|
cwd,
|
|
124
142
|
env: dependencies.environment ?? process.env,
|
|
125
143
|
stdin: "inherit",
|
|
@@ -127,10 +145,12 @@ export async function deployApp(
|
|
|
127
145
|
stderr: "inherit",
|
|
128
146
|
}));
|
|
129
147
|
await withStagedWorkspaceManifests(root, async (stage) => {
|
|
130
|
-
|
|
131
|
-
|
|
148
|
+
const stagedApplication = resolve(stage, options.directory);
|
|
149
|
+
cpSync(clientDist, join(stagedApplication, "client", "dist"), { recursive: true });
|
|
150
|
+
await reconcileStagedBundleState(stagedApplication, contextArgs, options.target, dependencies);
|
|
151
|
+
const result = await run(deployArgs, stagedApplication);
|
|
132
152
|
if (result.exitCode !== 0) {
|
|
133
|
-
await printAppLogs(contextArgs,
|
|
153
|
+
await printAppLogs(contextArgs, stagedApplication, dependencies);
|
|
134
154
|
throw new Error(`databricks apps deploy exited with code ${result.exitCode}`);
|
|
135
155
|
}
|
|
136
156
|
});
|
|
@@ -148,7 +168,7 @@ async function reconcileStagedBundleState(
|
|
|
148
168
|
? undefined
|
|
149
169
|
: (args: readonly string[], cwd: string) =>
|
|
150
170
|
Promise.resolve(
|
|
151
|
-
|
|
171
|
+
spawnSync(
|
|
152
172
|
"databricks",
|
|
153
173
|
["bundle", "plan", ...serializeArgs({ quiet: true }), ...args],
|
|
154
174
|
{
|
|
@@ -186,7 +206,7 @@ async function printAppLogs(
|
|
|
186
206
|
const showLogs =
|
|
187
207
|
dependencies.logs ??
|
|
188
208
|
((args: readonly string[], logsCwd: string) =>
|
|
189
|
-
|
|
209
|
+
spawn("databricks", ["apps", "logs", ...serializeArgs({ tailLines: 200 }), ...args], {
|
|
190
210
|
cwd: logsCwd,
|
|
191
211
|
env: dependencies.environment ?? process.env,
|
|
192
212
|
stdin: "ignore",
|
|
@@ -200,7 +220,7 @@ async function printAppLogs(
|
|
|
200
220
|
}
|
|
201
221
|
} catch (error) {
|
|
202
222
|
logger.warn("Could not read Databricks App logs", {
|
|
203
|
-
|
|
223
|
+
error: toError(error),
|
|
204
224
|
});
|
|
205
225
|
}
|
|
206
226
|
}
|
|
@@ -229,7 +249,7 @@ async function resolveDeployOptions(
|
|
|
229
249
|
configuredProfile ??
|
|
230
250
|
(hasEnvironmentAuth
|
|
231
251
|
? undefined
|
|
232
|
-
: (dependencies.resolveProfile ?? (() =>
|
|
252
|
+
: (dependencies.resolveProfile ?? (() => resolveProfile()?.name))());
|
|
233
253
|
if (!hasEnvironmentAuth && !resolvedProfile) {
|
|
234
254
|
throw new Error(
|
|
235
255
|
"Select a Databricks profile with --profile or configure Databricks environment credentials",
|
package/tasks/barrels.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env -S bun
|
|
2
2
|
/** Generate package barrels once or keep affected barrels current in watch mode. */
|
|
3
3
|
import { sep } from "node:path";
|
|
4
|
-
import { log,
|
|
4
|
+
import { log, type Sequence, sequence, pluralize } from "@dbx-tools/shared-core";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
import { runTaskMain, taskCommand, taskOptions } from "./cli.ts";
|
|
7
7
|
import { TaskDirectoriesOptionSchema, TaskWatchOptionSchema } from "./options.ts";
|
|
@@ -19,10 +19,9 @@ function ownerPackageDir(
|
|
|
19
19
|
return packages.find(({ dir }) => abs === dir || abs.startsWith(dir + sep))?.dir;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
function changedBarrelTargets(changed: readonly string[]):
|
|
22
|
+
function changedBarrelTargets(changed: readonly string[]): Sequence<string> {
|
|
23
23
|
const packages = recordedPackages();
|
|
24
|
-
return
|
|
25
|
-
.sequence(changed)
|
|
24
|
+
return sequence(changed)
|
|
26
25
|
.map((path) => ownerPackageDir(path, packages))
|
|
27
26
|
.nonNull()
|
|
28
27
|
.distinct();
|
|
@@ -31,7 +30,7 @@ function changedBarrelTargets(changed: readonly string[]): object.Sequence<strin
|
|
|
31
30
|
function warnUnownedChanges(changed: readonly string[]): void {
|
|
32
31
|
if (changed.length) {
|
|
33
32
|
logger.warn(
|
|
34
|
-
`no recorded package owns ${
|
|
33
|
+
`no recorded package owns ${pluralize(changed.length, "change")}; ` +
|
|
35
34
|
"run `bun run default` (or touch .projenrc.ts) to pick up a new package folder",
|
|
36
35
|
);
|
|
37
36
|
}
|
|
@@ -62,7 +61,7 @@ export async function main(args: string[] = process.argv.slice(2)): Promise<void
|
|
|
62
61
|
watchRoots(),
|
|
63
62
|
(changed) => {
|
|
64
63
|
const n = generateBarrels({ dirs: [...changedBarrelTargets(changed)] });
|
|
65
|
-
if (n) logger.success(`rebuilt ${
|
|
64
|
+
if (n) logger.success(`rebuilt ${pluralize(n, "barrel")}`);
|
|
66
65
|
},
|
|
67
66
|
{
|
|
68
67
|
check: (changed) => {
|
|
@@ -80,9 +79,7 @@ export async function main(args: string[] = process.argv.slice(2)): Promise<void
|
|
|
80
79
|
} else {
|
|
81
80
|
const dirs = values.dir;
|
|
82
81
|
const n = generateBarrels(dirs.length ? { dirs } : undefined);
|
|
83
|
-
logger.success(
|
|
84
|
-
n === 0 ? "barrels already up to date" : `updated ${stringUtils.pluralize(n, "barrel")}`,
|
|
85
|
-
);
|
|
82
|
+
logger.success(n === 0 ? "barrels already up to date" : `updated ${pluralize(n, "barrel")}`);
|
|
86
83
|
}
|
|
87
84
|
}
|
|
88
85
|
|
package/tasks/bump.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* generated version surface. This task has no git, registry, or publication
|
|
5
5
|
* side effects; release preparation owns those operations.
|
|
6
6
|
*/
|
|
7
|
-
import
|
|
7
|
+
import { projectUtils } from "@dbx-tools/core";
|
|
8
8
|
import { log } from "@dbx-tools/shared-core";
|
|
9
9
|
import { z } from "zod";
|
|
10
10
|
import { runTaskMain, taskCommand, taskOptions, taskRoot } from "./cli.ts";
|
package/tasks/clean.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env -S bun
|
|
2
2
|
/** Interactively remove generated files and installed dependency directories. */
|
|
3
3
|
import { relative } from "node:path";
|
|
4
|
-
import { log,
|
|
4
|
+
import { log, pluralize } from "@dbx-tools/shared-core";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
import { runTaskMain, taskCommand, taskOptions } from "./cli.ts";
|
|
7
7
|
import { listGeneratedFiles, listNodeModulesDirs, removePaths } from "../src/clean.ts";
|
|
@@ -43,7 +43,7 @@ export async function main(args: string[] = process.argv.slice(2)): Promise<void
|
|
|
43
43
|
if (yes) {
|
|
44
44
|
const n = removePaths(targets);
|
|
45
45
|
logger.success(
|
|
46
|
-
`removed ${
|
|
46
|
+
`removed ${pluralize(n, "path")} (${files.length} generated + ${nodeModules.length} node_modules) - ${regenHint(nodeModules.length > 0)}`,
|
|
47
47
|
);
|
|
48
48
|
process.exit(0);
|
|
49
49
|
}
|
|
@@ -83,7 +83,7 @@ export async function main(args: string[] = process.argv.slice(2)): Promise<void
|
|
|
83
83
|
|
|
84
84
|
const removedNodeModules = picked.some((p) => nodeModules.includes(p));
|
|
85
85
|
const n = removePaths(picked);
|
|
86
|
-
clack.outro(`removed ${
|
|
86
|
+
clack.outro(`removed ${pluralize(n, "path")} - ${regenHint(removedNodeModules)}`);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
await runTaskMain(import.meta, main);
|
package/tasks/cli.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { basename, extname, resolve } from "node:path";
|
|
3
3
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
4
4
|
import { addArgs, parseArgs, type CliArgsOptions } from "@dbx-tools/cli-args";
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
5
|
+
import { projectUtils } from "@dbx-tools/core";
|
|
6
|
+
import { tokenize } from "@dbx-tools/shared-core";
|
|
7
7
|
import { Command } from "commander";
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
|
|
@@ -15,7 +15,7 @@ export function taskName(moduleUrl: string): string {
|
|
|
15
15
|
|
|
16
16
|
/** Config resolution shared by task schemas. */
|
|
17
17
|
export function taskCliArgsOptions(moduleUrl: string): CliArgsOptions {
|
|
18
|
-
const prefix = [...
|
|
18
|
+
const prefix = [...tokenize(taskName(moduleUrl))].join("_").toUpperCase();
|
|
19
19
|
return {
|
|
20
20
|
cwd: process.cwd(),
|
|
21
21
|
prefix: `PROJEN_${prefix}`,
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
import { existsSync, readFileSync } from "node:fs";
|
|
4
4
|
import { availableParallelism } from "node:os";
|
|
5
5
|
import { join, resolve } from "node:path";
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
6
|
+
import { type ExecResult, spawn } from "@dbx-tools/core";
|
|
7
|
+
import { log, toError } from "@dbx-tools/shared-core";
|
|
8
8
|
import type { TaskSpec, TasksManifest } from "projen";
|
|
9
9
|
import { runTaskMain } from "./cli.ts";
|
|
10
10
|
|
|
@@ -80,7 +80,7 @@ const emoji = /[\p{Extended_Pictographic}\uFE0F\u200D]/gu;
|
|
|
80
80
|
export async function main(): Promise<void> {
|
|
81
81
|
const root = process.cwd();
|
|
82
82
|
const plan = compilePlan(root);
|
|
83
|
-
const jobs: Array<{ name: string; result: Promise<
|
|
83
|
+
const jobs: Array<{ name: string; result: Promise<ExecResult> }> = [];
|
|
84
84
|
if (plan.typescriptConfigs.length > 0) {
|
|
85
85
|
const batchCount = Math.min(4, availableParallelism(), plan.typescriptConfigs.length);
|
|
86
86
|
const batches = Array.from({ length: batchCount }, () => [] as string[]);
|
|
@@ -91,7 +91,7 @@ export async function main(): Promise<void> {
|
|
|
91
91
|
for (const [index, batch] of batches.entries()) {
|
|
92
92
|
jobs.push({
|
|
93
93
|
name: `TypeScript batch ${index + 1}`,
|
|
94
|
-
result:
|
|
94
|
+
result: spawn("bunx", ["tsc", "--build", ...batch], {
|
|
95
95
|
cwd: root,
|
|
96
96
|
stdin: "ignore",
|
|
97
97
|
stdout: "inherit",
|
|
@@ -111,7 +111,7 @@ export async function main(): Promise<void> {
|
|
|
111
111
|
for (const [index, result] of results.entries()) {
|
|
112
112
|
if (result.status === "rejected") {
|
|
113
113
|
logger.error(`${jobs[index]!.name} compile failed`, {
|
|
114
|
-
error:
|
|
114
|
+
error: toError(result.reason),
|
|
115
115
|
});
|
|
116
116
|
failed = true;
|
|
117
117
|
} else if (result.value.exitCode !== 0) {
|
|
@@ -125,10 +125,10 @@ export async function main(): Promise<void> {
|
|
|
125
125
|
async function compileCustomPackage(pkg: {
|
|
126
126
|
readonly name: string;
|
|
127
127
|
readonly directory: string;
|
|
128
|
-
}): Promise<
|
|
129
|
-
let result:
|
|
128
|
+
}): Promise<ExecResult> {
|
|
129
|
+
let result: ExecResult | undefined;
|
|
130
130
|
for (const task of ["pre-compile", "compile", "post-compile"]) {
|
|
131
|
-
result = await
|
|
131
|
+
result = await spawn("bun", ["run", task], {
|
|
132
132
|
cwd: pkg.directory,
|
|
133
133
|
stdin: "ignore",
|
|
134
134
|
stdout: (line) => logger.info(`${pkg.name}: ${line.replace(emoji, "")}`),
|
package/tasks/dev-watch.ts
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
/** Restart a development command after relevant workspace changes settle. */
|
|
3
3
|
import { isAbsolute, relative, resolve } from "node:path";
|
|
4
4
|
import { serializeArgs } from "@dbx-tools/cli-args";
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
5
|
+
import { spawn, type ChildProcessResult } from "@dbx-tools/core";
|
|
6
|
+
import { watchFiles } from "@dbx-tools/path";
|
|
7
|
+
import { log, sleep, toError } from "@dbx-tools/shared-core";
|
|
8
8
|
import { CommanderError } from "commander";
|
|
9
9
|
import { z } from "zod";
|
|
10
10
|
import { parsedTaskOptions, runTaskMain, taskCommand, taskPositionals } from "./cli.ts";
|
|
@@ -232,7 +232,7 @@ export async function main(args: string[] = process.argv.slice(2)): Promise<void
|
|
|
232
232
|
if (options.watchDisable) {
|
|
233
233
|
logger.info(`watch disabled; running ${commandLabel}`);
|
|
234
234
|
const [command, ...commandArgs] = options.command;
|
|
235
|
-
const { exitCode } = await
|
|
235
|
+
const { exitCode } = await spawn(command!, commandArgs, {
|
|
236
236
|
cwd,
|
|
237
237
|
stdin: "inherit",
|
|
238
238
|
stdout: "inherit",
|
|
@@ -250,13 +250,13 @@ export async function main(args: string[] = process.argv.slice(2)): Promise<void
|
|
|
250
250
|
options.watchInclude,
|
|
251
251
|
options.watchExclude,
|
|
252
252
|
);
|
|
253
|
-
let child:
|
|
253
|
+
let child: ChildProcessResult | undefined;
|
|
254
254
|
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
255
255
|
let restartReason: string | undefined;
|
|
256
256
|
let restarting = false;
|
|
257
257
|
let stopping = false;
|
|
258
258
|
|
|
259
|
-
const watcher = await
|
|
259
|
+
const watcher = await watchFiles([...watchPaths], {
|
|
260
260
|
cwd: root,
|
|
261
261
|
ignore: watchIgnore.length > 0 ? [...watchIgnore] : undefined,
|
|
262
262
|
ignoreInitial: true,
|
|
@@ -276,7 +276,7 @@ export async function main(args: string[] = process.argv.slice(2)): Promise<void
|
|
|
276
276
|
});
|
|
277
277
|
} catch (err) {
|
|
278
278
|
logger.error("failed to stop command process tree", {
|
|
279
|
-
error:
|
|
279
|
+
error: toError(err),
|
|
280
280
|
});
|
|
281
281
|
}
|
|
282
282
|
}
|
|
@@ -284,7 +284,7 @@ export async function main(args: string[] = process.argv.slice(2)): Promise<void
|
|
|
284
284
|
function startChild(reason: string): void {
|
|
285
285
|
logger.info(`${reason}; starting ${commandLabel}`);
|
|
286
286
|
const [command, ...commandArgs] = options.command;
|
|
287
|
-
const current =
|
|
287
|
+
const current = spawn(command!, commandArgs, {
|
|
288
288
|
cwd,
|
|
289
289
|
stdin: "ignore",
|
|
290
290
|
stdout: "inherit",
|
|
@@ -304,7 +304,7 @@ export async function main(args: string[] = process.argv.slice(2)): Promise<void
|
|
|
304
304
|
.catch((err) => {
|
|
305
305
|
if (child !== current || stopping) return;
|
|
306
306
|
child = undefined;
|
|
307
|
-
logger.error("command failed", { error:
|
|
307
|
+
logger.error("command failed", { error: toError(err) });
|
|
308
308
|
});
|
|
309
309
|
}
|
|
310
310
|
|
|
@@ -337,7 +337,7 @@ export async function main(args: string[] = process.argv.slice(2)): Promise<void
|
|
|
337
337
|
}
|
|
338
338
|
|
|
339
339
|
watcher.on("all", scheduleRestart);
|
|
340
|
-
watcher.on("error", (err) => logger.error("watcher error", { error:
|
|
340
|
+
watcher.on("error", (err) => logger.error("watcher error", { error: toError(err) }));
|
|
341
341
|
watcher.on("ready", () => {
|
|
342
342
|
const count = watchPaths.length;
|
|
343
343
|
const source = options.watchInclude.length > 0 ? "include glob" : "workspace directory";
|
|
@@ -380,7 +380,7 @@ export async function main(args: string[] = process.argv.slice(2)): Promise<void
|
|
|
380
380
|
restoreStdin();
|
|
381
381
|
await Promise.race([
|
|
382
382
|
Promise.allSettled([watcher.close(), stopChild()]),
|
|
383
|
-
|
|
383
|
+
sleep(SHUTDOWN_TIMEOUT_MS),
|
|
384
384
|
]);
|
|
385
385
|
process.exit(exitCode);
|
|
386
386
|
}
|
package/tasks/local-publish.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/** Build and publish the current workspace to configured loopback registries. */
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
-
import type { ChildProcessResult } from "@dbx-tools/core
|
|
5
|
-
import
|
|
6
|
-
import { log,
|
|
4
|
+
import type { ChildProcessResult } from "@dbx-tools/core";
|
|
5
|
+
import { npmRegistry } from "@dbx-tools/core";
|
|
6
|
+
import { log, isLoopbackHost } from "@dbx-tools/shared-core";
|
|
7
7
|
import { activePythonIndexes, resolveLocalPypi } from "./python-registry.ts";
|
|
8
8
|
import { spawnTaskCommand } from "../src/_task-command.ts";
|
|
9
9
|
|
|
@@ -22,8 +22,8 @@ export function resolveLocalRegistry(value: string): string | undefined {
|
|
|
22
22
|
const trimmed = value.trim();
|
|
23
23
|
if (!trimmed || trimmed.toLowerCase() === "false") return undefined;
|
|
24
24
|
if (trimmed.toLowerCase() === "auto") {
|
|
25
|
-
const registry =
|
|
26
|
-
return registry &&
|
|
25
|
+
const registry = npmRegistry();
|
|
26
|
+
return registry && isLoopbackHost(registry) ? registry.href : undefined;
|
|
27
27
|
}
|
|
28
28
|
return trimmed;
|
|
29
29
|
}
|
|
@@ -69,7 +69,7 @@ export async function publishLocalRelease(
|
|
|
69
69
|
|
|
70
70
|
if (
|
|
71
71
|
options.localPypi.toLowerCase() === "auto" &&
|
|
72
|
-
activeIndexes.some((index) =>
|
|
72
|
+
activeIndexes.some((index) => isLoopbackHost(index)) &&
|
|
73
73
|
!localPypi
|
|
74
74
|
) {
|
|
75
75
|
logger.info(
|