Files
windmill/cli/test/script_runtime_settings_sync.test.ts
Ruben Fiszel ef4dc46d4b fix(cli): keep script settings on push and repair the up-to-date check (#10741)
* fix(cli): keep script retention, debounce and cache settings on push

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test(cli): surface the create response when the fixture fails

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test(cli): drop debounce settings the CI build refuses to accept

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* repair the script push up-to-date comparison (#10743)

* test: settle the backlog before the capped audit-export drain (#10737)

* test: settle the backlog before the capped audit-export drain

* chore: update ee-repo-ref to bd4de74eb37b32a2b6c7c69f6dedac031ef8436b

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

Previous ee-repo-ref: b5a5f9114df26088cfe976d91f10e55ba8bfcaa6

New ee-repo-ref: bd4de74eb37b32a2b6c7c69f6dedac031ef8436b

Automated by sync-ee-ref workflow.

---------

Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>

* fix(cli): repair the script push up-to-date comparison

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test(cli): drain dependency jobs and pin a non-1 priority skip

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test(cli): describe the priority fixture without the old comparison

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>

* refactor(cli): read cache_ignore_s3_path off the typed response

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(cli): stop redeploying bunnative scripts on every push

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
2026-08-18 12:26:41 +02:00

127 lines
4.8 KiB
TypeScript

/**
* Runtime settings that live only in the script metadata file (the retention
* delay, the debouncing bounds, the cache s3-path flag) must survive a sync
* pull/push cycle. A field missing from the create_script body the CLI builds
* lands as NULL on the deployed version; one missing from its up-to-date
* comparison makes a change to it alone report as up to date and never deploy.
*/
import { expect, test } from "bun:test";
import { writeFile, readFile, mkdir } from "node:fs/promises";
import { withTestBackend } from "./test_backend.ts";
import { waitForDeploymentJobs } from "./new_commands_helpers.ts";
// The debounce bounds this PR also restores cannot be asserted here: a build without
// git tags reports a bare commit as its version, GIT_SEM_VERSION then falls back to
// 0.1.0, and every version-gated feature (debouncing wants 1.566.0) is refused. That is
// what CI builds, so a fixture that sets any debounce field fails at create.
const SETTINGS = {
delete_after_secs: 900,
cache_ignore_s3_path: true,
};
test("Integration: script runtime settings survive a sync pull/push cycle", async () => {
await withTestBackend(async (backend, tempDir) => {
const uniqueId = Date.now();
const scriptPath = `f/test/settings_${uniqueId}`;
const getScript = async () => {
const resp = await backend.apiRequest!(
`/api/w/${backend.workspace}/scripts/get/p/${scriptPath}`,
);
expect(resp.ok).toEqual(true);
return await resp.json();
};
await mkdir(`${tempDir}/f/test`, { recursive: true });
const folderResp = await backend.apiRequest!(
`/api/w/${backend.workspace}/folders/create`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "test" }),
},
);
const folderStatus = `${folderResp.status} ${await folderResp.text()}`;
const createResp = await backend.apiRequest!(
`/api/w/${backend.workspace}/scripts/create`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
path: scriptPath,
content: `export async function main() {\n return "Hello world";\n}`,
summary: "Test runtime settings",
description: "",
language: "bun",
kind: "script",
schema: {
$schema: "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: {},
required: [],
},
...SETTINGS,
}),
},
);
if (!createResp.ok) {
throw new Error(
`scripts/create failed: ${createResp.status} ${await createResp.text()} ` +
`(folders/create: ${folderStatus})`,
);
}
await writeFile(
`${tempDir}/wmill.yaml`,
`defaultTs: bun\nincludes:\n - "${scriptPath}**"\nexcludes: []\n`,
"utf-8",
);
// The lock a deploy's dependency job writes is compared before the settings are,
// so a pull taken before that job lands makes the next push deploy over the lock
// instead of over the setting under test.
await waitForDeploymentJobs(backend);
const pullResult = await backend.runCLICommand(["sync", "pull", "--yes"], tempDir);
expect(pullResult.code).toEqual(0);
const metadataPath = `${tempDir}/${scriptPath}.script.yaml`;
const pulledMetadata = await readFile(metadataPath, "utf-8");
for (const key of Object.keys(SETTINGS)) {
expect(pulledMetadata).toContain(key);
}
// A content-only edit must carry the settings through to the new version.
const scriptFilePath = `${tempDir}/${scriptPath}.ts`;
const originalContent = await readFile(scriptFilePath, "utf-8");
await writeFile(
scriptFilePath,
originalContent.replace("Hello world", "Hello world modified"),
"utf-8",
);
expect((await backend.runCLICommand(["sync", "push", "--yes"], tempDir)).code).toEqual(0);
const afterContentPush = await getScript();
expect(afterContentPush.content).toContain("Hello world modified");
for (const [key, value] of Object.entries(SETTINGS)) {
expect(afterContentPush[key]).toEqual(value);
}
// A settings-only edit must reach the remote rather than be skipped as up to
// date. 0 is "delete immediately after completion", not "unset".
await waitForDeploymentJobs(backend);
expect((await backend.runCLICommand(["sync", "pull", "--yes"], tempDir)).code).toEqual(0);
await writeFile(
metadataPath,
(await readFile(metadataPath, "utf-8")).replace(
`delete_after_secs: ${SETTINGS.delete_after_secs}`,
"delete_after_secs: 0",
),
"utf-8",
);
expect((await backend.runCLICommand(["sync", "push", "--yes"], tempDir)).code).toEqual(0);
expect((await getScript()).delete_after_secs).toEqual(0);
});
});