mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-22 16:03:43 +00:00
feat(cli): include extra paths in codebase digest for monorepo imports (#11327)
* feat(cli): hash codebase extra_digest_paths and warn on uncovered bundle inputs Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cli): cache codebase digest only once complete, skip entry in warning Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cli): accept string extra_digest_paths, always print uncovered-input warning Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(cli): clarify extra_digest_paths resolution and missing-path error Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
c232ea43b4
commit
9b46b21f51
@@ -1,6 +1,44 @@
|
||||
import { Codebase, SyncOptions } from "../core/conf.ts";
|
||||
import * as log from "../core/log.ts";
|
||||
import { digestDir } from "./utils.ts";
|
||||
import { digestDir, generateHash, generateHashFromBuffer } from "./utils.ts";
|
||||
import { readFile, stat } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
|
||||
// A bare string is accepted, like `includes`/`excludes` in findCodebase.
|
||||
function extraDigestPaths(codebase: Codebase): string[] {
|
||||
return ([] as string[]).concat(codebase.extra_digest_paths ?? []);
|
||||
}
|
||||
|
||||
async function digestPath(p: string): Promise<string> {
|
||||
let s;
|
||||
try {
|
||||
s = await stat(p);
|
||||
} catch {
|
||||
throw new Error(
|
||||
`Codebase extra_digest_paths entry not found: ${p} (resolved to ${path.resolve(p)})`
|
||||
);
|
||||
}
|
||||
return s.isDirectory()
|
||||
? await digestDir(p, "")
|
||||
: await generateHashFromBuffer(await readFile(p));
|
||||
}
|
||||
|
||||
/** Bundle inputs that no codebase digest covers, so edits to them would not trigger a re-push. */
|
||||
export function uncoveredBundleInputs(
|
||||
codebase: Codebase,
|
||||
entry: string,
|
||||
inputs: string[]
|
||||
): string[] {
|
||||
const entryAbs = path.resolve(entry);
|
||||
const roots = [codebase.relative_path, ...extraDigestPaths(codebase)]
|
||||
.map((r) => path.resolve(r));
|
||||
return inputs.filter((i) => {
|
||||
// non-file namespaces ("<define:x>", "(disabled):x", "ns:path") and installed packages
|
||||
if (/^[<(]|^[a-z-]{2,}:/i.test(i) || i.includes("node_modules")) return false;
|
||||
const abs = path.resolve(i);
|
||||
return abs != entryAbs && !roots.some((r) => abs == r || abs.startsWith(r + path.sep));
|
||||
});
|
||||
}
|
||||
|
||||
export type SyncCodebase = Codebase & {
|
||||
getDigest: (forceTar?: boolean) => Promise<string>;
|
||||
@@ -23,13 +61,20 @@ export function listSyncCodebases(options: SyncOptions): SyncCodebase[] {
|
||||
forceTar?: boolean
|
||||
) => {
|
||||
if (_digest == undefined) {
|
||||
_digest = await digestDir(
|
||||
// Concurrent callers read `_digest` across these awaits: assign it only once complete.
|
||||
let digest = await digestDir(
|
||||
codebase.relative_path,
|
||||
JSON.stringify(codebase)
|
||||
);
|
||||
if (codebase.format == "esm") {
|
||||
_digest += ".esm";
|
||||
const extra = extraDigestPaths(codebase);
|
||||
if (extra.length > 0) {
|
||||
const hashes = await Promise.all(extra.map(digestPath));
|
||||
digest = await generateHash(digest + hashes.join(""));
|
||||
}
|
||||
if (codebase.format == "esm") {
|
||||
digest += ".esm";
|
||||
}
|
||||
_digest = digest;
|
||||
if (!alreadyPrinted) {
|
||||
alreadyPrinted = true;
|
||||
log.info(`Codebase ${codebase.relative_path}, digest: ${_digest}`);
|
||||
|
||||
Reference in New Issue
Block a user