fix(cli): sync workspace dependency files on Windows and fix CLI tests (#11288)

* fix(cli): sync workspace dependency files on Windows

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

* test(cli): pin workspace dependency path parsing on both separators

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

* fix(cli): classify workspace dependency files on either separator

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

* test(cli): check out the fork deploy clone without autocrlf

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ruben Fiszel
2026-09-22 12:13:11 +00:00
committed by GitHub
co-authored by Claude Opus 5
parent 732214361f
commit 841f7e1436
7 changed files with 42 additions and 11 deletions
+2 -2
View File
@@ -1153,7 +1153,7 @@ export function ZipFSElement(
? "script"
: p.endsWith(".resource.json")
? "resource"
: p.startsWith("dependencies/")
: isWorkspaceDependencies(p)
? "dependencies"
: "other";
@@ -2752,7 +2752,7 @@ export async function compareDynFSElement(
if (skipMetadata) {
continue;
}
if (k.startsWith("dependencies/")) {
if (isWorkspaceDependencies(k)) {
if (!workspaceDependenciesPathToLanguageAndFilename(k)) {
log.warn(`Skipping unrecognized workspace dependencies file: ${k}`);
continue;
+1 -1
View File
@@ -391,7 +391,7 @@ export function getTypeStrFromPath(
if (isSharedLockPath(p)) {
return "shared_lock";
}
if (p.startsWith("dependencies" + SEP)) {
if (isWorkspaceDependencies(p)) {
return "workspace_dependencies";
}
if (isFileResource(p) || isFilesetResource(p)) {
+3 -1
View File
@@ -45,7 +45,9 @@ export const workspaceDependenciesLanguages: WorkspaceDependenciesLanguage[] = [
] as const;
export function workspaceDependenciesPathToLanguageAndFilename(path: string): { name: string | undefined, language: ScriptLanguage } | undefined {
const relativePath = path.replace("dependencies/", "");
// Sync paths carry the platform separator, while a set's name is always
// forward-slashed.
const relativePath = path.replaceAll("\\", "/").replace("dependencies/", "");
for (const { filename, language } of workspaceDependenciesLanguages) {
if (relativePath.endsWith(filename)) {
return {
+2 -1
View File
@@ -223,8 +223,9 @@ export function isRawAppFile(path: string): boolean {
return isRawAppPath(path);
}
/** Sync paths carry the platform separator: `dependencies\x` on Windows. */
export function isWorkspaceDependencies(path: string): boolean {
return path.startsWith("dependencies/");
return path.startsWith("dependencies/") || path.startsWith("dependencies\\");
}
export function printSync(input: string | Uint8Array) {
@@ -63,7 +63,10 @@ test("git-sync fork deploy follows the fork branch's wmill.yaml", async () => {
git(seed, "commit", "-m", "dedupe");
git(seed, "push", "origin", forkBranch);
git(work, "clone", `file://${bare}`, ".");
// Git for Windows defaults to autocrlf=true, which checks the pulled LF
// files out as CRLF; the deploy's pull would rewrite every one of them
// and the clean-tree assertion below would read that as a change.
git(work, "clone", "-c", "core.autocrlf=false", `file://${bare}`, ".");
const deployed = await backend.runCLICommand(
[
"sync",
+7 -5
View File
@@ -2185,18 +2185,20 @@ describe("settings sync", () => {
const files = await listFilesRecursive(tempDir);
expect(files).toContain("settings.yaml");
// Read and modify a safe setting (webhook URL)
// Read and modify a safe setting (webhook URL). The server resolves the
// webhook host when it is saved and refuses one that does not resolve to a
// public address, so this must be a real public hostname.
const webhook = "https://example.com/hook";
const settingsContent = await readFile(`${tempDir}/settings.yaml`, "utf-8");
let modifiedSettings: string;
if (settingsContent.includes("webhook:")) {
modifiedSettings = settingsContent.replace(
/webhook:.*/,
'webhook: "https://test-webhook.example.com/hook"'
`webhook: "${webhook}"`
);
} else {
modifiedSettings =
settingsContent + '\nwebhook: "https://test-webhook.example.com/hook"\n';
modifiedSettings = settingsContent + `\nwebhook: "${webhook}"\n`;
}
await writeFile(`${tempDir}/settings.yaml`, modifiedSettings, "utf-8");
@@ -2213,7 +2215,7 @@ describe("settings sync", () => {
);
expect(apiResp.status).toEqual(200);
const settingsData = await apiResp.json();
expect(settingsData.webhook).toEqual("https://test-webhook.example.com/hook");
expect(settingsData.webhook).toEqual(webhook);
});
});
});
+23
View File
@@ -0,0 +1,23 @@
import { expect, test } from "bun:test";
import { isWorkspaceDependencies } from "../src/utils/utils.ts";
import { workspaceDependenciesPathToLanguageAndFilename } from "../src/utils/script_common.ts";
// Sync paths carry the platform separator. A Windows path parsed to a different
// set name pushes the file to a set the workspace does not have.
test("workspace dependency paths parse the same with either separator", () => {
for (const sep of ["/", "\\"]) {
expect(isWorkspaceDependencies(`dependencies${sep}requirements.in`)).toBe(true);
expect(
workspaceDependenciesPathToLanguageAndFilename(`dependencies${sep}requirements.in`),
).toEqual({ name: undefined, language: "python3" });
expect(
workspaceDependenciesPathToLanguageAndFilename(`dependencies${sep}team.package.json`),
).toEqual({ name: "team", language: "bun" });
expect(
workspaceDependenciesPathToLanguageAndFilename(
`dependencies${sep}team${sep}python.requirements.in`,
),
).toEqual({ name: "team/python", language: "python3" });
}
expect(isWorkspaceDependencies("f\\dependencies\\requirements.in")).toBe(false);
});