From 61ffd6bc669b2202ca02e80cb2629861cf3645eb Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Mon, 1 Jun 2026 07:48:28 +0100 Subject: [PATCH] fix(ci): bootstrap raw changed gates from clean checkouts --- scripts/crabbox-wrapper.mjs | 9 ++++++--- test/scripts/crabbox-wrapper.test.ts | 28 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/scripts/crabbox-wrapper.mjs b/scripts/crabbox-wrapper.mjs index a0dc5c42141..0cf76a30080 100755 --- a/scripts/crabbox-wrapper.mjs +++ b/scripts/crabbox-wrapper.mjs @@ -1880,15 +1880,18 @@ function isWorktreeClean() { return gitOutput(["status", "--porcelain=v1"]).stdout === ""; } -function shouldUseFullCheckoutForCleanSparseRemoteSync(commandArgs, _providerName) { +function shouldUseFullCheckoutForCleanRemoteSync(commandArgs, _providerName) { if (commandArgs[0] !== "run") { return false; } if (hasOption(commandArgs, "--no-sync")) { return false; } + if (!isWorktreeClean()) { + return false; + } - return isSparseCheckout() && isWorktreeClean(); + return isSparseCheckout() || isChangedGateCommand(runCommandArgs(commandArgs)); } function prepareFullCheckoutForSync(options = {}) { @@ -2099,7 +2102,7 @@ const scriptBootstrap = prepareAwsMacosScriptStdinBootstrap(normalizedArgs, prov normalizedArgs = scriptBootstrap.args; const scriptStdinPrepared = scriptBootstrap.prepared; try { - if (shouldUseFullCheckoutForCleanSparseRemoteSync(normalizedArgs, provider)) { + if (shouldUseFullCheckoutForCleanRemoteSync(normalizedArgs, provider)) { const runWords = runCommandArgs(normalizedArgs); const changedGateBase = isChangedGateCommand(runWords) ? mergeBaseForChangedGate() : ""; const checkout = prepareFullCheckoutForSync({ changedGateBase }); diff --git a/test/scripts/crabbox-wrapper.test.ts b/test/scripts/crabbox-wrapper.test.ts index 49f43969a42..8ffd5c55a43 100644 --- a/test/scripts/crabbox-wrapper.test.ts +++ b/test/scripts/crabbox-wrapper.test.ts @@ -1816,6 +1816,34 @@ describe.concurrent("scripts/crabbox-wrapper", () => { ); }); + it("bootstraps Git metadata for non-sparse changed gates on remote raw syncs", () => { + const result = runWrapper( + "provider: hetzner, aws, local-container, blacksmith-testbox, or cloudflare\n", + ["run", "--provider", "aws", "--", "corepack", "pnpm", "check:changed"], + { + gitResponses: { + [GIT_STATUS_PORCELAIN_KEY]: { stdout: "" }, + [GIT_MERGE_BASE_MAIN_HEAD_KEY]: { stdout: "abc123\n" }, + }, + }, + ); + + const output = parseFakeCrabboxOutput(result); + const remoteCommand = normalizeShellLineEndings(output.args.at(-1) ?? ""); + expect(result.status).toBe(0); + expect(result.stderr).toContain("syncing from temporary full checkout"); + expect(result.stderr).toContain("overlaying local HEAD as worktree changes from abc123"); + expect(output.cwd).toContain("openclaw-crabbox-sync-"); + expect(output.args).toContain("--shell"); + expect(remoteCommand).toContain("git init -q"); + expect(remoteCommand).toContain( + "git fetch -q --depth=1 origin abc123:refs/remotes/origin/main", + ); + expect(remoteCommand).toMatch( + /&& env OPENCLAW_CHECK_CHANGED_REMOTE_CHILD=1 OPENCLAW_CHANGED_LANES_RAW_SYNC=1 CI=1 corepack pnpm check:changed$/u, + ); + }); + it("bootstraps Git metadata for env-prefixed sparse changed gates", () => { const result = runWrapper( "provider: hetzner, aws, local-container, blacksmith-testbox, or cloudflare\n",