Skip to content

Commit b705d7d

Browse files
committed
Add TDD test for trunk branch bug in createWorkspace
This test demonstrates that the trunk branch parameter is not being respected when creating a new workspace. The test: 1. Creates a custom trunk branch with unique content 2. Creates another branch with different content 3. Attempts to create a workspace specifying the custom trunk 4. Verifies the workspace contains content from custom trunk Expected behavior: workspace should be created from specified trunk Current behavior (bug): SSH runtime creates from HEAD instead of trunk This test should: - PASS for LocalRuntime (correctly uses trunk branch) - FAIL for SSHRuntime (ignores trunk branch, uses HEAD) The bug is in src/runtime/SSHRuntime.ts:592 where trunkBranch is renamed to _trunkBranch (unused) and line 618 creates branches from HEAD instead.
1 parent 2dc1f47 commit b705d7d

File tree

1 file changed

+132
-0
lines changed

1 file changed

+132
-0
lines changed

tests/ipcMain/createWorkspace.test.ts

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,138 @@ describeIntegration("WORKSPACE_CREATE with both runtimes", () => {
273273
},
274274
TEST_TIMEOUT_MS
275275
);
276+
277+
test.concurrent(
278+
"creates new branch from specified trunk branch, not from default branch",
279+
async () => {
280+
const env = await createTestEnvironment();
281+
const tempGitRepo = await createTempGitRepo();
282+
283+
try {
284+
// Create a custom trunk branch with a unique commit
285+
const customTrunkBranch = "custom-trunk";
286+
await execAsync(
287+
`git checkout -b ${customTrunkBranch} && echo "custom-trunk-content" > trunk-file.txt && git add . && git commit -m "Custom trunk commit"`,
288+
{ cwd: tempGitRepo }
289+
);
290+
291+
// Create a different branch (which will become the default if we checkout to it)
292+
const otherBranch = "other-branch";
293+
await execAsync(
294+
`git checkout -b ${otherBranch} && echo "other-content" > other-file.txt && git add . && git commit -m "Other branch commit"`,
295+
{ cwd: tempGitRepo }
296+
);
297+
298+
// Switch back to the original default branch
299+
const defaultBranch = await detectDefaultTrunkBranch(tempGitRepo);
300+
await execAsync(`git checkout ${defaultBranch}`, { cwd: tempGitRepo });
301+
302+
// Now create a workspace specifying custom-trunk as the trunk branch
303+
const newBranchName = generateBranchName("from-custom-trunk");
304+
const runtimeConfig = getRuntimeConfig(newBranchName);
305+
306+
const { result, cleanup } = await createWorkspaceWithCleanup(
307+
env,
308+
tempGitRepo,
309+
newBranchName,
310+
customTrunkBranch, // Specify custom trunk branch
311+
runtimeConfig
312+
);
313+
314+
expect(result.success).toBe(true);
315+
if (!result.success) {
316+
throw new Error(
317+
`Failed to create workspace from custom trunk '${customTrunkBranch}': ${result.error}`
318+
);
319+
}
320+
321+
// Wait for workspace initialization to complete
322+
await new Promise((resolve) => setTimeout(resolve, getInitWaitTime()));
323+
324+
// Verify the new branch was created from custom-trunk, not from default branch
325+
const workspacePath = result.metadata.namedWorkspacePath;
326+
327+
// For LocalRuntime, check the worktree directly
328+
// For SSHRuntime, we need to check the remote workspace
329+
if (type === "local") {
330+
// Check that trunk-file.txt exists (from custom-trunk)
331+
const trunkFileExists = await fs
332+
.access(path.join(workspacePath, "trunk-file.txt"))
333+
.then(() => true)
334+
.catch(() => false);
335+
expect(trunkFileExists).toBe(true);
336+
337+
// Check that other-file.txt does NOT exist (from other-branch)
338+
const otherFileExists = await fs
339+
.access(path.join(workspacePath, "other-file.txt"))
340+
.then(() => true)
341+
.catch(() => false);
342+
expect(otherFileExists).toBe(false);
343+
344+
// Verify git log shows the custom trunk commit
345+
const { stdout: logOutput } = await execAsync(
346+
`git log --oneline --all`,
347+
{ cwd: workspacePath }
348+
);
349+
expect(logOutput).toContain("Custom trunk commit");
350+
} else if (type === "ssh" && sshConfig) {
351+
// For SSH runtime, check files on the remote host
352+
const checkFileCmd = `test -f ${workspacePath}/trunk-file.txt && echo "exists" || echo "missing"`;
353+
const checkFileStream = await env.mockIpcRenderer.invoke(
354+
IPC_CHANNELS.RUNTIME_EXEC,
355+
result.metadata.id,
356+
checkFileCmd,
357+
{ cwd: workspacePath, timeout: 10 }
358+
);
359+
360+
// Read stdout to check if file exists
361+
let checkOutput = "";
362+
const reader = checkFileStream.stdout.getReader();
363+
const decoder = new TextDecoder();
364+
try {
365+
while (true) {
366+
const { done, value } = await reader.read();
367+
if (done) break;
368+
checkOutput += decoder.decode(value, { stream: true });
369+
}
370+
} finally {
371+
reader.releaseLock();
372+
}
373+
374+
expect(checkOutput.trim()).toBe("exists");
375+
376+
// Check that other-file.txt does NOT exist
377+
const checkOtherFileCmd = `test -f ${workspacePath}/other-file.txt && echo "exists" || echo "missing"`;
378+
const checkOtherStream = await env.mockIpcRenderer.invoke(
379+
IPC_CHANNELS.RUNTIME_EXEC,
380+
result.metadata.id,
381+
checkOtherFileCmd,
382+
{ cwd: workspacePath, timeout: 10 }
383+
);
384+
385+
let checkOtherOutput = "";
386+
const otherReader = checkOtherStream.stdout.getReader();
387+
try {
388+
while (true) {
389+
const { done, value } = await otherReader.read();
390+
if (done) break;
391+
checkOtherOutput += decoder.decode(value, { stream: true });
392+
}
393+
} finally {
394+
otherReader.releaseLock();
395+
}
396+
397+
expect(checkOtherOutput.trim()).toBe("missing");
398+
}
399+
400+
await cleanup();
401+
} finally {
402+
await cleanupTestEnvironment(env);
403+
await cleanupTempGitRepo(tempGitRepo);
404+
}
405+
},
406+
TEST_TIMEOUT_MS
407+
);
276408
});
277409

278410
describe("Init hook execution", () => {

0 commit comments

Comments
 (0)