mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-02 08:31:33 +00:00
fix(scripts): materialize PR worktrees before gates (#115120)
* fix(scripts): materialize PR worktrees before gates * test(agents): stabilize failed local service fixture * test(ui): isolate config route location
This commit is contained in:
@@ -29,6 +29,16 @@ EOF
|
||||
return 1
|
||||
}
|
||||
|
||||
ensure_full_pr_worktree_checkout() {
|
||||
local sparse_checkout
|
||||
sparse_checkout=$(git config --bool core.sparseCheckout 2>/dev/null || true)
|
||||
if [ "$sparse_checkout" = "true" ]; then
|
||||
# Prepare gates build the whole repository. Inherited sparse settings can
|
||||
# omit tracked transitive inputs and turn healthy PRs into false failures.
|
||||
git sparse-checkout disable
|
||||
fi
|
||||
}
|
||||
|
||||
enter_worktree() {
|
||||
local pr="$1"
|
||||
local reset_to_main="${2:-false}"
|
||||
@@ -81,6 +91,7 @@ enter_worktree() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
ensure_full_pr_worktree_checkout
|
||||
git fetch origin main
|
||||
if [ "$reset_to_main" = "true" ]; then
|
||||
git checkout -B "temp/pr-$pr" origin/main
|
||||
|
||||
@@ -820,6 +820,9 @@ describe("provider local service", () => {
|
||||
const tempDir = tempDirs.make("openclaw-local-service-failed-unref-");
|
||||
const servicePidPath = path.join(tempDir, "service.pid");
|
||||
const moduleUrl = new URL("./provider-local-service.ts", import.meta.url).href;
|
||||
// The assertion targets diagnostic-pipe cleanup after failed readiness.
|
||||
// Give the nested Node child enough startup time under loaded CI.
|
||||
const failedServiceReadyTimeoutMs = 5_000;
|
||||
const serviceScript = [
|
||||
`const fs=require("node:fs");`,
|
||||
`fs.writeFileSync(${JSON.stringify(servicePidPath)},String(process.pid));`,
|
||||
@@ -837,7 +840,7 @@ describe("provider local service", () => {
|
||||
` service: {`,
|
||||
` command: process.execPath,`,
|
||||
` args: ["-e", ${JSON.stringify(serviceScript)}],`,
|
||||
` readyTimeoutMs: 100,`,
|
||||
` readyTimeoutMs: ${failedServiceReadyTimeoutMs},`,
|
||||
` },`,
|
||||
` });`,
|
||||
`} catch {}`,
|
||||
|
||||
@@ -96,6 +96,22 @@ function createRepo(nestedName?: string) {
|
||||
return dir;
|
||||
}
|
||||
|
||||
function addTrackedUiConfig(repoDir: string) {
|
||||
const configDir = join(repoDir, "ui", "config");
|
||||
mkdirSync(configDir, { recursive: true });
|
||||
writeFileSync(join(configDir, "control-ui-chunking.ts"), "export const chunking = true;\n");
|
||||
execFileSync("git", ["add", "ui/config/control-ui-chunking.ts"], { cwd: repoDir });
|
||||
execFileSync("git", ["commit", "-qm", "add ui config"], { cwd: repoDir });
|
||||
}
|
||||
|
||||
function setSparseCheckout(repoDir: string) {
|
||||
execFileSync("git", ["sparse-checkout", "init", "--no-cone"], { cwd: repoDir });
|
||||
execFileSync("git", ["sparse-checkout", "set", "--no-cone", "--stdin"], {
|
||||
cwd: repoDir,
|
||||
input: "/*\n!/*/\n/base.txt\n",
|
||||
});
|
||||
}
|
||||
|
||||
function bashSource(repoDir: string, supervised = false) {
|
||||
return [
|
||||
"set -euo pipefail",
|
||||
@@ -2193,6 +2209,54 @@ describePosix("scripts/pr per-PR operation lock", () => {
|
||||
).toBe("temp/pr-43");
|
||||
});
|
||||
|
||||
it("materializes a new PR worktree inherited from a sparse checkout", () => {
|
||||
const repoDir = createRepo();
|
||||
addTrackedUiConfig(repoDir);
|
||||
execFileSync("git", ["remote", "add", "origin", repoDir], { cwd: repoDir });
|
||||
setSparseCheckout(repoDir);
|
||||
const worktreeDir = join(repoDir, ".worktrees", "pr-44");
|
||||
|
||||
const result = runLockShell(repoDir, [
|
||||
"ensure_gh_api_auth() { return 0; }",
|
||||
"enter_worktree 44",
|
||||
]);
|
||||
|
||||
expect(result.status, `${result.stdout}\n${result.stderr}`).toBe(0);
|
||||
expect(existsSync(join(worktreeDir, "ui", "config", "control-ui-chunking.ts"))).toBe(true);
|
||||
expect(
|
||||
execFileSync("git", ["config", "--bool", "core.sparseCheckout"], {
|
||||
cwd: worktreeDir,
|
||||
encoding: "utf8",
|
||||
}).trim(),
|
||||
).toBe("false");
|
||||
});
|
||||
|
||||
it("materializes an existing sparse PR worktree before reuse", () => {
|
||||
const repoDir = createRepo();
|
||||
addTrackedUiConfig(repoDir);
|
||||
execFileSync("git", ["remote", "add", "origin", repoDir], { cwd: repoDir });
|
||||
const worktreeDir = join(repoDir, ".worktrees", "pr-45");
|
||||
execFileSync("git", ["worktree", "add", "-q", "-b", "temp/pr-45", worktreeDir], {
|
||||
cwd: repoDir,
|
||||
});
|
||||
setSparseCheckout(worktreeDir);
|
||||
expect(existsSync(join(worktreeDir, "ui", "config", "control-ui-chunking.ts"))).toBe(false);
|
||||
|
||||
const result = runLockShell(repoDir, [
|
||||
"ensure_gh_api_auth() { return 0; }",
|
||||
"enter_worktree 45",
|
||||
]);
|
||||
|
||||
expect(result.status, `${result.stdout}\n${result.stderr}`).toBe(0);
|
||||
expect(existsSync(join(worktreeDir, "ui", "config", "control-ui-chunking.ts"))).toBe(true);
|
||||
expect(
|
||||
execFileSync("git", ["config", "--bool", "core.sparseCheckout"], {
|
||||
cwd: worktreeDir,
|
||||
encoding: "utf8",
|
||||
}).trim(),
|
||||
).toBe("false");
|
||||
});
|
||||
|
||||
it("refuses a symlink alias to another registered worktree", () => {
|
||||
const repoDir = createRepo();
|
||||
const worktreesDir = join(repoDir, ".worktrees");
|
||||
|
||||
@@ -29,6 +29,7 @@ function deferred<T>() {
|
||||
let localStorageMock: Storage;
|
||||
|
||||
beforeEach(() => {
|
||||
window.history.replaceState({}, "", "/");
|
||||
vi.spyOn(realtimeTalk, "switchActiveRealtimeTalkCameras").mockImplementation(
|
||||
switchActiveRealtimeTalkCameras,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user