perf(cli): skip relock more accurate (#7993)

* perf(cli): skip relock more accurate

Signed-off-by: pyranota <pyra@duck.com>

* Update cli/src/utils/metadata.ts

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>

* Update cli/src/commands/flow/flow_metadata.ts

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>

* fix

Signed-off-by: pyranota <pyra@duck.com>

* use structuredClone for safety

Signed-off-by: pyranota <pyra@duck.com>

* chore: update ee-repo-ref to 592848d59ca2304926fb2bd85d000668a7f46a77

This commit updates the EE repository reference after PR #420 was merged in windmill-ee-private.

Previous ee-repo-ref: 931813b75b8260faa13ddc07f36a11607b7e3bf6

New ee-repo-ref: 592848d59ca2304926fb2bd85d000668a7f46a77

Automated by sync-ee-ref workflow.

* fix ci

Signed-off-by: pyranota <pyra@duck.com>

* add simple tests

Signed-off-by: pyranota <pyra@duck.com>

---------

Signed-off-by: pyranota <pyra@duck.com>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
This commit is contained in:
Pyra
2026-02-18 12:17:54 +00:00
committed by GitHub
co-authored by claude[bot] windmill-internal-app[bot]
parent fecebb69b2
commit 5bbb26c72e
8 changed files with 820 additions and 59 deletions
+93 -23
View File
@@ -54,19 +54,90 @@ export async function getRawWorkspaceDependencies(): Promise<Record<string, stri
} catch {
// dependencies directory doesn't exist
}
return rawWorkspaceDeps;
return rawWorkspaceDeps;
}
export function workspaceDependenciesPathToLanguageAndFilename(path: string): { name: string | undefined, language: ScriptLanguage } | undefined {
const relativePath = path.replace("dependencies/", "");
for (const { filename, language } of workspaceDependenciesLanguages) {
if (relativePath.endsWith(filename)) {
return {
name: relativePath === filename ? undefined : relativePath.replace("." + filename, ""),
language
};
const relativePath = path.replace("dependencies/", "");
for (const { filename, language } of workspaceDependenciesLanguages) {
if (relativePath.endsWith(filename)) {
return {
name: relativePath === filename ? undefined : relativePath.replace("." + filename, ""),
language
};
}
}
}
/**
* Filters raw workspace dependencies to only include those that:
* 1. Match the given script language
* 2. Are referenced by the script's workspace dependency annotation, OR
* are the default dependency (no name) when there's no annotation
*/
export function filterWorkspaceDependencies(
rawWorkspaceDependencies: Record<string, string>,
scriptContent: string,
language: ScriptLanguage
): Record<string, string> {
const wda = extractWorkspaceDepsAnnotation(scriptContent, language);
const filtered: Record<string, string> = {};
for (const [depPath, depContent] of Object.entries(rawWorkspaceDependencies)) {
const depInfo = workspaceDependenciesPathToLanguageAndFilename(depPath);
if (depInfo && depInfo.language === language) {
if ((wda && wda.external.includes(depInfo.name ?? "default")) || (wda == null && depInfo.name == undefined)) {
filtered[depPath] = depContent;
}
}
}
return filtered;
}
export interface InlineScriptInfo {
content: string;
language: ScriptLanguage;
}
/**
* Filters workspace dependencies for multiple scripts, resolving !inline refs and computing union.
* Common helper used by flows and apps.
*/
export async function filterWorkspaceDependenciesForScripts(
scripts: InlineScriptInfo[],
rawWorkspaceDependencies: Record<string, string>,
folder: string,
sep: string
): Promise<Record<string, string>> {
const filtered: Record<string, string> = {};
for (const script of scripts) {
let content = script.content;
// Resolve !inline reference to actual content
if (content.startsWith("!inline ")) {
const filePath = folder + sep + content.replace("!inline ", "");
try {
content = await Deno.readTextFile(filePath);
} catch {
continue;
}
}
const scriptFiltered = filterWorkspaceDependencies(
rawWorkspaceDependencies,
content,
script.language
);
for (const [depPath, depContent] of Object.entries(scriptFiltered)) {
filtered[depPath] = depContent;
}
}
return filtered;
}
// on windows, when using powershell, blue is not readable
@@ -95,14 +166,6 @@ export async function generateScriptMetadataInternal(
const language = inferContentTypeFromFilePath(scriptPath, opts.defaultTs);
// Filter workspace dependencies to only include those matching the script's language
const filteredRawWorkspaceDependencies: Record<string, string> = {};
for (const [depPath, depContent] of Object.entries(rawWorkspaceDependencies)) {
const depInfo = workspaceDependenciesPathToLanguageAndFilename(depPath);
if (depInfo && depInfo.language === language) {
filteredRawWorkspaceDependencies[depPath] = depContent;
}
}
const metadataWithType = await parseMetadataFile(
remotePath,
@@ -112,7 +175,14 @@ export async function generateScriptMetadataInternal(
// read script content
const scriptContent = await Deno.readTextFile(scriptPath);
const metadataContent = await Deno.readTextFile(metadataWithType.path);
const filteredRawWorkspaceDependencies = filterWorkspaceDependencies(
rawWorkspaceDependencies,
scriptContent,
language
);
// Note: rawWorkspaceDependencies are now passed in as parameter instead of being searched hierarchically
let hash = await generateScriptHash(filteredRawWorkspaceDependencies, scriptContent, metadataContent);
@@ -671,12 +741,12 @@ export async function parseMetadataFile(
scriptPath: string,
generateMetadataIfMissing:
| (GlobalOptions & {
path: string;
workspaceRemote: Workspace;
schemaOnly?: boolean;
rawWorkspaceDependencies: Record<string, string>;
codebases: SyncCodebase[]
})
path: string;
workspaceRemote: Workspace;
schemaOnly?: boolean;
rawWorkspaceDependencies: Record<string, string>;
codebases: SyncCodebase[]
})
| undefined
): Promise<{ isJson: boolean; payload: any; path: string }> {
let metadataFilePath = scriptPath + ".script.json";