Accept string form for worktree setup/teardown
Lifecycle config now takes either a multiline shell script string or an array of commands, making it friendlier to edit in a textarea. Schema parsing moved to Zod so coercion stays in one place.
This commit is contained in:
@@ -5,7 +5,9 @@ import {
|
||||
deriveWorktreeProjectHash,
|
||||
deletePaseoWorktree,
|
||||
getScriptConfigs,
|
||||
getWorktreeSetupCommands,
|
||||
getWorktreeTerminalSpecs,
|
||||
getWorktreeTeardownCommands,
|
||||
isServiceScript,
|
||||
isPaseoOwnedWorktreeCwd,
|
||||
listPaseoWorktrees,
|
||||
@@ -442,6 +444,79 @@ describe.skipIf(process.platform === "win32")("createWorktree", () => {
|
||||
expect(portValue).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("runs string setup scripts from paseo.json as a single shell command", async () => {
|
||||
const paseoConfig = {
|
||||
worktree: {
|
||||
setup: 'greeting="hello from string setup"\necho "$greeting" > setup.log',
|
||||
},
|
||||
};
|
||||
writeFileSync(join(repoDir, "paseo.json"), JSON.stringify(paseoConfig));
|
||||
execSync('git add paseo.json && git -c commit.gpgsign=false commit -m "add string setup"', {
|
||||
cwd: repoDir,
|
||||
});
|
||||
|
||||
const result = await createLegacyWorktreeForTest({
|
||||
branchName: "main",
|
||||
cwd: repoDir,
|
||||
baseBranch: "main",
|
||||
worktreeSlug: "string-setup-test",
|
||||
paseoHome,
|
||||
});
|
||||
|
||||
expect(getWorktreeSetupCommands(result.worktreePath)).toEqual([
|
||||
'greeting="hello from string setup"\necho "$greeting" > setup.log',
|
||||
]);
|
||||
expect(readFileSync(join(result.worktreePath, "setup.log"), "utf8").trim()).toBe(
|
||||
"hello from string setup",
|
||||
);
|
||||
});
|
||||
|
||||
it("treats blank lifecycle strings as empty", () => {
|
||||
writeFileSync(
|
||||
join(repoDir, "paseo.json"),
|
||||
JSON.stringify({
|
||||
worktree: {
|
||||
setup: " \n\t ",
|
||||
teardown: " \n ",
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(getWorktreeSetupCommands(repoDir)).toEqual([]);
|
||||
expect(getWorktreeTeardownCommands(repoDir)).toEqual([]);
|
||||
});
|
||||
|
||||
it("filters non-string and blank entries from lifecycle arrays", () => {
|
||||
writeFileSync(
|
||||
join(repoDir, "paseo.json"),
|
||||
JSON.stringify({
|
||||
worktree: {
|
||||
setup: [
|
||||
'echo "first" > setup-array.log',
|
||||
null,
|
||||
" ",
|
||||
'echo "second" >> setup-array.log',
|
||||
],
|
||||
teardown: [
|
||||
'echo "first" > "$PASEO_SOURCE_CHECKOUT_PATH/teardown-array.log"',
|
||||
null,
|
||||
"",
|
||||
'echo "second" >> "$PASEO_SOURCE_CHECKOUT_PATH/teardown-array.log"',
|
||||
],
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(getWorktreeSetupCommands(repoDir)).toEqual([
|
||||
'echo "first" > setup-array.log',
|
||||
'echo "second" >> setup-array.log',
|
||||
]);
|
||||
expect(getWorktreeTeardownCommands(repoDir)).toEqual([
|
||||
'echo "first" > "$PASEO_SOURCE_CHECKOUT_PATH/teardown-array.log"',
|
||||
'echo "second" >> "$PASEO_SOURCE_CHECKOUT_PATH/teardown-array.log"',
|
||||
]);
|
||||
});
|
||||
|
||||
it("does not run setup commands when runSetup=false", async () => {
|
||||
const paseoConfig = {
|
||||
worktree: {
|
||||
@@ -858,6 +933,34 @@ describe("paseo worktree manager", () => {
|
||||
expect(teardownLog).toContain(`port=${runtimeEnv.PASEO_WORKTREE_PORT}`);
|
||||
});
|
||||
|
||||
it("runs string teardown scripts from paseo.json as a single shell command", async () => {
|
||||
const paseoConfig = {
|
||||
worktree: {
|
||||
teardown:
|
||||
'cleanup_message="teardown string"\necho "$cleanup_message" > "$PASEO_SOURCE_CHECKOUT_PATH/teardown.log"',
|
||||
},
|
||||
};
|
||||
writeFileSync(join(repoDir, "paseo.json"), JSON.stringify(paseoConfig));
|
||||
execSync('git add paseo.json && git -c commit.gpgsign=false commit -m "add string teardown"', {
|
||||
cwd: repoDir,
|
||||
});
|
||||
|
||||
const created = await createLegacyWorktreeForTest({
|
||||
branchName: "teardown-string-branch",
|
||||
cwd: repoDir,
|
||||
baseBranch: "main",
|
||||
worktreeSlug: "teardown-string-test",
|
||||
paseoHome,
|
||||
});
|
||||
|
||||
await deletePaseoWorktree({ cwd: repoDir, worktreePath: created.worktreePath, paseoHome });
|
||||
|
||||
expect(getWorktreeTeardownCommands(repoDir)).toEqual([
|
||||
'cleanup_message="teardown string"\necho "$cleanup_message" > "$PASEO_SOURCE_CHECKOUT_PATH/teardown.log"',
|
||||
]);
|
||||
expect(readFileSync(join(repoDir, "teardown.log"), "utf8").trim()).toBe("teardown string");
|
||||
});
|
||||
|
||||
it("omits PASEO_WORKTREE_PORT from teardown env when runtime metadata is missing", async () => {
|
||||
const paseoConfig = {
|
||||
worktree: {
|
||||
|
||||
Reference in New Issue
Block a user