From 2fdc51e62985fc755884436130bdd58e294247c8 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Thu, 28 May 2026 18:13:38 +0200 Subject: [PATCH] fix(git-sync): publish fork branch on only_create_branch from the CLI (#9366) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [ee] fix(git-sync): publish fork branch on only_create_branch from the CLI Fixes WIN-1997. Forking a git-sync-configured workspace must push a `wm-fork//` branch to the repo, but the integration test `test_workspace_fork_creates_branch` failed: the fork callback job succeeded yet no branch appeared. Root cause: the fork-branch callback runs the sync script with `only_create_branch: true` and no items. The hub sync script delegates branch checkout to `wmill sync git-deploy --only-create-branch` and runs its own in-process commit+push ONLY for the `!only_create_branch` path (`if (!only_create_branch) git_push(...)`). #9284 had moved commit+push out of the CLI to the caller for the GPG-cache-warmth invariant (WIN-1974) — but it also dropped the CLI's push for the branch-only case. A branch-only publish has no commit, so no signing is involved and the GPG concern does not apply; with neither the CLI nor the hub script pushing, the empty fork branch was never published. Restore the CLI push for the `only_create_branch` path (a bare `git push --porcelain` of the checked-out branch ref). Adds a deterministic CLI regression test that runs `git-deploy --only-create-branch` for a fork workspace and asserts the branch reaches the remote with no caller-side push. EE companion: format the fork-branch commit message with Display instead of Debug (no more `Some("...")` leak). Co-Authored-By: Claude Opus 4.7 (1M context) * chore: update ee-repo-ref to a30079e75dc5b7d7413aa8ee20e40e80bfea9cbd This commit updates the EE repository reference after PR #597 was merged in windmill-ee-private. Previous ee-repo-ref: 8b02336fcebdfae4b9d2795cbb74fa7046530bcb New ee-repo-ref: a30079e75dc5b7d7413aa8ee20e40e80bfea9cbd Automated by sync-ee-ref workflow. --------- Co-authored-by: Claude Opus 4.7 (1M context) Co-authored-by: windmill-internal-app[bot] --- backend/ee-repo-ref.txt | 2 +- cli/src/commands/sync/sync.ts | 16 ++++++- cli/test/gitsync_promotion.test.ts | 71 ++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 3 deletions(-) diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index 80a746c1c0..f457a34fb7 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -55c19293232be379a3044eb78f677b545882ffd6 \ No newline at end of file +a30079e75dc5b7d7413aa8ee20e40e80bfea9cbd diff --git a/cli/src/commands/sync/sync.ts b/cli/src/commands/sync/sync.ts index 22cdd5900b..2632f6c80c 100644 --- a/cli/src/commands/sync/sync.ts +++ b/cli/src/commands/sync/sync.ts @@ -2504,8 +2504,20 @@ export async function pull( } if (opts.onlyCreateBranch) { - // Branch is checked out locally; the caller pushes it. Symmetric with - // the non-onlyCreateBranch path: CLI does branch + pull, never push. + // Branch-only publish: there is no commit here, so the GPG-cache-warmth + // invariant that motivated moving commit+push to the hub script (WIN-1974, + // #9284) does not apply — a bare `git push` of the (empty) branch ref needs + // no signing. The hub script only runs its in-process commit+push for the + // non-onlyCreateBranch path (`if (!only_create_branch) git_push(...)`), so + // the CLI MUST publish the fork branch here or it is never pushed at all. + gitSyncDeployPush({ + items: deployItems, + authorName: process.env["WM_USERNAME"] || "windmill", + authorEmail: process.env["WM_EMAIL"] || "windmill@windmill.dev", + committerName: opts.gitCommitterName, + committerEmail: opts.gitCommitterEmail, + onlyCreateBranch: true, + }); return; } } diff --git a/cli/test/gitsync_promotion.test.ts b/cli/test/gitsync_promotion.test.ts index 5b73e8f8e1..709ae11fc2 100644 --- a/cli/test/gitsync_promotion.test.ts +++ b/cli/test/gitsync_promotion.test.ts @@ -200,3 +200,74 @@ test.skipIf(shouldSkipOnCI())( }); }, ); + +/** + * Regression test for WIN-1997: forking a workspace with git sync configured + * must publish a `wm-fork//` branch to the remote. + * + * The fork-branch callback runs the sync script with `only_create_branch: + * true` and no items. The hub script delegates branch checkout + push of that + * empty ref to `wmill sync git-deploy --only-create-branch` — its own + * in-process commit+push runs ONLY for the `!only_create_branch` path. So if + * the CLI doesn't push the freshly checked-out branch here, nothing does and + * the fork branch never reaches the remote (the symptom that broke the e2e + * test after #9284 moved commit+push to the caller). This guards that the CLI + * owns the push for the branch-only case. + */ +test.skipIf(shouldSkipOnCI())( + "git-sync fork: only_create_branch publishes the wm-fork branch (CLI owns the push)", + async () => { + await withTestBackend(async (backend) => { + // Bare "remote" seeded with an initial `main` commit. + const bareDir = await mkdtemp(join(tmpdir(), "wmill_fork_bare_")); + execFileSync("git", ["init", "--bare", "--initial-branch=main", bareDir]); + const seedDir = await mkdtemp(join(tmpdir(), "wmill_fork_seed_")); + git(seedDir, "init", "--initial-branch=main"); + git(seedDir, "config", "user.email", "seed@windmill.dev"); + git(seedDir, "config", "user.name", "seed"); + await writeFile(join(seedDir, "README.md"), "# fork test\n"); + git(seedDir, "add", "-A"); + git(seedDir, "commit", "-m", "seed"); + git(seedDir, "remote", "add", "origin", `file://${bareDir}`); + git(seedDir, "push", "-u", "origin", "main"); + const seedMain = remoteHead(bareDir, "main"); + + // The CWD the hub script runs git-deploy in: a clone of the repo on main. + const work = await mkdtemp(join(tmpdir(), "wmill_fork_work_")); + git(work, "clone", `file://${bareDir}`, "."); + await writeFile( + join(work, "wmill.yaml"), + "defaultTs: bun\nincludes:\n - f/**\nexcludes: []\n", + ); + + // Branch creation happens BEFORE the fork workspace exists (step 1 of the + // fork flow), so we pass the fork workspace id straight through — whoami + // returns synthetic superadmin info for it. No items, only_create_branch. + const forkWs = "wm-fork-clitest"; + const res = await backend.runCLICommand( + [ + "sync", + "git-deploy", + "--repository", + "u/test/unused_on_branch_only_path", + "--git-deploy-items", + "[]", + "--only-create-branch", + ], + work, + { workspace: forkWs }, + ); + expect(res.code).toBe(0); + + // The regression: with NO caller-side commit/push, the fork branch must + // already be on the remote because the CLI pushed it. + expect(remoteBranches(bareDir)).toContain("refs/heads/wm-fork/main/clitest"); + // Base branch untouched — branch-only publish creates no commit. + expect(remoteHead(bareDir, "main")).toBe(seedMain); + + await rm(bareDir, { recursive: true, force: true }); + await rm(seedDir, { recursive: true, force: true }); + await rm(work, { recursive: true, force: true }); + }); + }, +);