Compare commits
2 Commits
wmill-scri
...
fix/inline
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1aac43977e | ||
|
|
05d4d6dd48 |
@@ -29,7 +29,10 @@ import { FlowFile } from "./flow.ts";
|
|||||||
import { FlowValue } from "../../../gen/types.gen.ts";
|
import { FlowValue } from "../../../gen/types.gen.ts";
|
||||||
import { replaceInlineScripts } from "../../../windmill-utils-internal/src/inline-scripts/replacer.ts";
|
import { replaceInlineScripts } from "../../../windmill-utils-internal/src/inline-scripts/replacer.ts";
|
||||||
import { workspaceDependenciesLanguages } from "../../utils/script_common.ts";
|
import { workspaceDependenciesLanguages } from "../../utils/script_common.ts";
|
||||||
import { extractNameFromFolder, getFolderSuffix } from "../../utils/resource_folders.ts";
|
import {
|
||||||
|
extractNameFromFolder,
|
||||||
|
getNonDottedPaths,
|
||||||
|
} from "../../utils/resource_folders.ts";
|
||||||
|
|
||||||
const TOP_HASH = "__flow_hash";
|
const TOP_HASH = "__flow_hash";
|
||||||
async function generateFlowHash(
|
async function generateFlowHash(
|
||||||
@@ -157,7 +160,9 @@ export async function generateFlowLockInternal(
|
|||||||
filteredDeps
|
filteredDeps
|
||||||
);
|
);
|
||||||
|
|
||||||
const lockAssigner = newPathAssigner(opts.defaultTs ?? "bun");
|
const lockAssigner = newPathAssigner(opts.defaultTs ?? "bun", {
|
||||||
|
skipInlineScriptSuffix: getNonDottedPaths(),
|
||||||
|
});
|
||||||
const inlineScripts = extractInlineScriptsForFlows(
|
const inlineScripts = extractInlineScriptsForFlows(
|
||||||
flowValue.value.modules,
|
flowValue.value.modules,
|
||||||
{},
|
{},
|
||||||
|
|||||||
@@ -1768,6 +1768,66 @@ excludes: []
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("Integration: Sync pull with nonDottedPaths uses non-dotted inline script filenames", async () => {
|
||||||
|
await withTestBackend(async (backend, tempDir) => {
|
||||||
|
// Push a flow using default dotted paths
|
||||||
|
await writeFile(
|
||||||
|
`${tempDir}/wmill.yaml`,
|
||||||
|
`defaultTs: bun
|
||||||
|
includes:
|
||||||
|
- "**"
|
||||||
|
excludes: []
|
||||||
|
`,
|
||||||
|
"utf-8",
|
||||||
|
);
|
||||||
|
|
||||||
|
const uniqueId = Date.now();
|
||||||
|
const flowName = `f/test/nondot_pull_inline_${uniqueId}`;
|
||||||
|
const flowFixture = createFlowFixture(flowName);
|
||||||
|
await mkdir(`${tempDir}/f/test/nondot_pull_inline_${uniqueId}${getFolderSuffix("flow")}`, { recursive: true });
|
||||||
|
for (const file of Object.values(flowFixture)) {
|
||||||
|
await writeFile(`${tempDir}/${file.path}`, file.content, "utf-8");
|
||||||
|
}
|
||||||
|
|
||||||
|
const pushResult = await backend.runCLICommand(
|
||||||
|
["sync", "push", "--yes", "--includes", `f/test/nondot_pull_inline_${uniqueId}*/**`],
|
||||||
|
tempDir,
|
||||||
|
);
|
||||||
|
expect(pushResult.code).toEqual(0);
|
||||||
|
|
||||||
|
// Pull into a fresh directory with nonDottedPaths enabled
|
||||||
|
const tempDir2 = await mkdtemp(join(tmpdir(), "wmill_nondot_inline_"));
|
||||||
|
try {
|
||||||
|
await writeFile(
|
||||||
|
`${tempDir2}/wmill.yaml`,
|
||||||
|
`defaultTs: bun
|
||||||
|
nonDottedPaths: true
|
||||||
|
includes:
|
||||||
|
- "**"
|
||||||
|
excludes: []
|
||||||
|
`,
|
||||||
|
"utf-8",
|
||||||
|
);
|
||||||
|
|
||||||
|
const pullResult = await backend.runCLICommand(["sync", "pull", "--yes"], tempDir2);
|
||||||
|
expect(pullResult.code).toEqual(0);
|
||||||
|
|
||||||
|
// Verify pulled files use non-dotted inline script naming
|
||||||
|
const files = await listFilesRecursive(tempDir2);
|
||||||
|
const flowFiles = files.filter((f) => f.includes(`nondot_pull_inline_${uniqueId}`));
|
||||||
|
|
||||||
|
expect(flowFiles.length > 0).toBeTruthy();
|
||||||
|
// Should use __flow folder, not .flow
|
||||||
|
expect(flowFiles.some((f) => f.includes("__flow/"))).toBeTruthy();
|
||||||
|
// No files should have .inline_script. in their name
|
||||||
|
const dottedInlineFiles = flowFiles.filter((f) => f.includes(".inline_script."));
|
||||||
|
expect(dottedInlineFiles.length).toEqual(0);
|
||||||
|
} finally {
|
||||||
|
await cleanupTempDir(tempDir2);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// ws_error_handler_muted Persistence Tests
|
// ws_error_handler_muted Persistence Tests
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
import { expect, test, describe } from "bun:test";
|
import { expect, test, describe } from "bun:test";
|
||||||
import { withTestBackend } from "./test_backend.ts";
|
import { withTestBackend } from "./test_backend.ts";
|
||||||
import { addWorkspace } from "../workspace.ts";
|
import { addWorkspace } from "../workspace.ts";
|
||||||
import { writeFile } from "node:fs/promises";
|
import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
|
||||||
import {
|
import {
|
||||||
createLocalScript,
|
createLocalScript,
|
||||||
createLocalFlow,
|
createLocalFlow,
|
||||||
@@ -19,7 +19,12 @@ import {
|
|||||||
/**
|
/**
|
||||||
* Helper to set up a workspace with wmill.yaml
|
* Helper to set up a workspace with wmill.yaml
|
||||||
*/
|
*/
|
||||||
async function setupWorkspace(backend: any, tempDir: string, workspaceName: string) {
|
async function setupWorkspace(
|
||||||
|
backend: any,
|
||||||
|
tempDir: string,
|
||||||
|
workspaceName: string,
|
||||||
|
nonDottedPaths = false
|
||||||
|
) {
|
||||||
const testWorkspace = {
|
const testWorkspace = {
|
||||||
remote: backend.baseUrl,
|
remote: backend.baseUrl,
|
||||||
workspaceId: backend.workspace,
|
workspaceId: backend.workspace,
|
||||||
@@ -29,11 +34,88 @@ async function setupWorkspace(backend: any, tempDir: string, workspaceName: stri
|
|||||||
await addWorkspace(testWorkspace, { force: true, configDir: backend.testConfigDir });
|
await addWorkspace(testWorkspace, { force: true, configDir: backend.testConfigDir });
|
||||||
|
|
||||||
await writeFile(`${tempDir}/wmill.yaml`, `defaultTs: bun
|
await writeFile(`${tempDir}/wmill.yaml`, `defaultTs: bun
|
||||||
includes:
|
${nonDottedPaths ? "nonDottedPaths: true\n" : ""}includes:
|
||||||
- "**"
|
- "**"
|
||||||
excludes: []`, "utf-8");
|
excludes: []`, "utf-8");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function createLocalNonDottedFlow(tempDir: string, name: string) {
|
||||||
|
const flowDir = `${tempDir}/f/test/${name}__flow`;
|
||||||
|
await mkdir(flowDir, { recursive: true });
|
||||||
|
|
||||||
|
await writeFile(
|
||||||
|
`${flowDir}/a.ts`,
|
||||||
|
`export async function main() {\n return "Hello from flow ${name}";\n}`,
|
||||||
|
"utf-8"
|
||||||
|
);
|
||||||
|
|
||||||
|
await writeFile(
|
||||||
|
`${flowDir}/flow.yaml`,
|
||||||
|
`summary: "${name} flow"
|
||||||
|
description: "A flow for testing"
|
||||||
|
value:
|
||||||
|
modules:
|
||||||
|
- id: a
|
||||||
|
value:
|
||||||
|
type: rawscript
|
||||||
|
content: "!inline a.ts"
|
||||||
|
language: bun
|
||||||
|
input_transforms: {}
|
||||||
|
schema:
|
||||||
|
$schema: "https://json-schema.org/draft/2020-12/schema"
|
||||||
|
type: object
|
||||||
|
properties: {}
|
||||||
|
required: []
|
||||||
|
`,
|
||||||
|
"utf-8"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createLocalNonDottedApp(tempDir: string, name: string) {
|
||||||
|
const appDir = `${tempDir}/f/test/${name}__app`;
|
||||||
|
await mkdir(appDir, { recursive: true });
|
||||||
|
|
||||||
|
await writeFile(
|
||||||
|
`${appDir}/app.yaml`,
|
||||||
|
`summary: "${name} app"
|
||||||
|
value:
|
||||||
|
type: app
|
||||||
|
grid:
|
||||||
|
- id: button1
|
||||||
|
data:
|
||||||
|
type: buttoncomponent
|
||||||
|
componentInput:
|
||||||
|
type: runnable
|
||||||
|
runnable:
|
||||||
|
type: runnableByName
|
||||||
|
inlineScript:
|
||||||
|
content: |
|
||||||
|
export async function main() {
|
||||||
|
return "hello from app";
|
||||||
|
}
|
||||||
|
language: bun
|
||||||
|
hiddenInlineScripts: []
|
||||||
|
css: {}
|
||||||
|
norefreshbar: false
|
||||||
|
policy:
|
||||||
|
on_behalf_of: null
|
||||||
|
on_behalf_of_email: null
|
||||||
|
triggerables: {}
|
||||||
|
execution_mode: viewer
|
||||||
|
`,
|
||||||
|
"utf-8"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fileExists(filePath: string): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
await stat(filePath);
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// Main test: processes scripts, flows, and apps together
|
// Main test: processes scripts, flows, and apps together
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
@@ -156,6 +238,87 @@ describe("generate-metadata flags", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("--lock-only preserves non-dotted flow filenames", async () => {
|
||||||
|
await withTestBackend(async (backend, tempDir) => {
|
||||||
|
await setupWorkspace(backend, tempDir, "lock_only_non_dotted_test", true);
|
||||||
|
|
||||||
|
await createLocalNonDottedFlow(tempDir, "my_flow");
|
||||||
|
|
||||||
|
const result = await backend.runCLICommand(
|
||||||
|
["generate-metadata", "--yes", "--lock-only"],
|
||||||
|
tempDir,
|
||||||
|
"lock_only_non_dotted_test"
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result.code).toEqual(0);
|
||||||
|
|
||||||
|
const flowDir = `${tempDir}/f/test/my_flow__flow`;
|
||||||
|
const flowYaml = await readFile(`${flowDir}/flow.yaml`, "utf-8");
|
||||||
|
|
||||||
|
expect(flowYaml).toContain("!inline a.ts");
|
||||||
|
expect(flowYaml).toContain("!inline a.lock");
|
||||||
|
expect(flowYaml).not.toContain(".inline_script.");
|
||||||
|
expect(await fileExists(`${flowDir}/a.lock`)).toEqual(true);
|
||||||
|
expect(await fileExists(`${flowDir}/a.inline_script.ts`)).toEqual(false);
|
||||||
|
expect(await fileExists(`${flowDir}/a.inline_script.lock`)).toEqual(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("generate-metadata preserves non-dotted flow inline script filenames", async () => {
|
||||||
|
await withTestBackend(async (backend, tempDir) => {
|
||||||
|
await setupWorkspace(backend, tempDir, "full_gen_non_dotted_flow_test", true);
|
||||||
|
|
||||||
|
await createLocalNonDottedFlow(tempDir, "my_flow");
|
||||||
|
|
||||||
|
const result = await backend.runCLICommand(
|
||||||
|
["generate-metadata", "--yes"],
|
||||||
|
tempDir,
|
||||||
|
"full_gen_non_dotted_flow_test"
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result.code).toEqual(0);
|
||||||
|
|
||||||
|
const flowDir = `${tempDir}/f/test/my_flow__flow`;
|
||||||
|
const flowYaml = await readFile(`${flowDir}/flow.yaml`, "utf-8");
|
||||||
|
|
||||||
|
// Inline script references should use non-dotted naming
|
||||||
|
expect(flowYaml).toContain("!inline a.ts");
|
||||||
|
expect(flowYaml).toContain("!inline a.lock");
|
||||||
|
expect(flowYaml).not.toContain(".inline_script.");
|
||||||
|
expect(await fileExists(`${flowDir}/a.ts`)).toEqual(true);
|
||||||
|
expect(await fileExists(`${flowDir}/a.lock`)).toEqual(true);
|
||||||
|
expect(await fileExists(`${flowDir}/a.inline_script.ts`)).toEqual(false);
|
||||||
|
expect(await fileExists(`${flowDir}/a.inline_script.lock`)).toEqual(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("generate-metadata uses non-dotted app inline script filenames", async () => {
|
||||||
|
await withTestBackend(async (backend, tempDir) => {
|
||||||
|
await setupWorkspace(backend, tempDir, "non_dotted_app_gen_test", true);
|
||||||
|
|
||||||
|
await createLocalNonDottedApp(tempDir, "my_app");
|
||||||
|
|
||||||
|
const result = await backend.runCLICommand(
|
||||||
|
["generate-metadata", "--yes"],
|
||||||
|
tempDir,
|
||||||
|
"non_dotted_app_gen_test"
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(result.code).toEqual(0);
|
||||||
|
|
||||||
|
const appDir = `${tempDir}/f/test/my_app__app`;
|
||||||
|
const appYaml = await readFile(`${appDir}/app.yaml`, "utf-8");
|
||||||
|
|
||||||
|
// Inline script references should use non-dotted naming
|
||||||
|
expect(appYaml).not.toContain(".inline_script.");
|
||||||
|
// Verify no dotted inline script files were created
|
||||||
|
const { readdir: readdirAsync } = await import("node:fs/promises");
|
||||||
|
const files = await readdirAsync(appDir);
|
||||||
|
const dottedFiles = files.filter((f: string) => f.includes(".inline_script."));
|
||||||
|
expect(dottedFiles.length).toEqual(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test("--schema-only only processes scripts (skips flows and apps)", async () => {
|
test("--schema-only only processes scripts (skips flows and apps)", async () => {
|
||||||
await withTestBackend(async (backend, tempDir) => {
|
await withTestBackend(async (backend, tempDir) => {
|
||||||
await setupWorkspace(backend, tempDir, "schema_only_test");
|
await setupWorkspace(backend, tempDir, "schema_only_test");
|
||||||
|
|||||||
Reference in New Issue
Block a user