Distinguish services from scripts with type system and runtime tracking
This commit is contained in:
@@ -3,7 +3,9 @@ import {
|
||||
createWorktree,
|
||||
deriveWorktreeProjectHash,
|
||||
deletePaseoWorktree,
|
||||
getScriptConfigs,
|
||||
getWorktreeTerminalSpecs,
|
||||
isServiceScript,
|
||||
isPaseoOwnedWorktreeCwd,
|
||||
listPaseoWorktrees,
|
||||
resolveWorktreeRuntimeEnv,
|
||||
@@ -483,6 +485,91 @@ describe("createWorktree", () => {
|
||||
{ command: "npm run test" },
|
||||
]);
|
||||
});
|
||||
|
||||
it("parses omitted script type as a plain script", async () => {
|
||||
writeFileSync(
|
||||
join(repoDir, "paseo.json"),
|
||||
JSON.stringify({
|
||||
scripts: {
|
||||
typecheck: {
|
||||
command: " npm run typecheck ",
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const scriptConfigs = getScriptConfigs(repoDir);
|
||||
const typecheck = scriptConfigs.get("typecheck");
|
||||
|
||||
expect(typecheck).toEqual({
|
||||
command: "npm run typecheck",
|
||||
});
|
||||
expect(typecheck).toBeDefined();
|
||||
expect(isServiceScript(typecheck!)).toBe(false);
|
||||
});
|
||||
|
||||
it("parses service scripts and preserves optional port", async () => {
|
||||
writeFileSync(
|
||||
join(repoDir, "paseo.json"),
|
||||
JSON.stringify({
|
||||
scripts: {
|
||||
server: {
|
||||
type: "service",
|
||||
command: "npm run dev",
|
||||
port: 4321,
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const scriptConfigs = getScriptConfigs(repoDir);
|
||||
const server = scriptConfigs.get("server");
|
||||
|
||||
expect(server).toEqual({
|
||||
type: "service",
|
||||
command: "npm run dev",
|
||||
port: 4321,
|
||||
});
|
||||
expect(server).toBeDefined();
|
||||
expect(isServiceScript(server!)).toBe(true);
|
||||
});
|
||||
|
||||
it("ignores invalid script entries gracefully", async () => {
|
||||
writeFileSync(
|
||||
join(repoDir, "paseo.json"),
|
||||
JSON.stringify({
|
||||
scripts: {
|
||||
valid: {
|
||||
command: "npm run valid",
|
||||
},
|
||||
invalidType: {
|
||||
type: "worker",
|
||||
command: "npm run worker",
|
||||
},
|
||||
missingCommand: {
|
||||
type: "service",
|
||||
},
|
||||
blankCommand: {
|
||||
command: " ",
|
||||
},
|
||||
nonObject: "npm run nope",
|
||||
invalidPort: {
|
||||
type: "service",
|
||||
command: "npm run dev",
|
||||
port: "3000",
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
expect(getScriptConfigs(repoDir)).toEqual(
|
||||
new Map([
|
||||
["valid", { command: "npm run valid" }],
|
||||
["invalidType", { command: "npm run worker" }],
|
||||
["invalidPort", { type: "service", command: "npm run dev" }],
|
||||
]),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("paseo worktree manager", () => {
|
||||
|
||||
@@ -24,7 +24,14 @@ interface PaseoConfig {
|
||||
teardown?: string[];
|
||||
terminals?: WorktreeTerminalConfig[];
|
||||
};
|
||||
scripts?: Record<string, ScriptConfig>;
|
||||
scripts?: Record<
|
||||
string,
|
||||
{
|
||||
type?: unknown;
|
||||
command?: unknown;
|
||||
port?: unknown;
|
||||
}
|
||||
>;
|
||||
}
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
@@ -90,11 +97,24 @@ export interface WorktreeTerminalConfig {
|
||||
command: string;
|
||||
}
|
||||
|
||||
export interface ScriptConfig {
|
||||
export interface PlainScriptConfig {
|
||||
type?: undefined;
|
||||
command: string;
|
||||
port?: undefined;
|
||||
}
|
||||
|
||||
export interface ServiceScriptConfig {
|
||||
type: "service";
|
||||
command: string;
|
||||
port?: number; // explicit port override, otherwise auto-assigned
|
||||
}
|
||||
|
||||
export type ScriptConfig = PlainScriptConfig | ServiceScriptConfig;
|
||||
|
||||
export function isServiceScript(config: ScriptConfig): config is ServiceScriptConfig {
|
||||
return "type" in config && config.type === "service";
|
||||
}
|
||||
|
||||
export class WorktreeSetupError extends Error {
|
||||
readonly results: WorktreeSetupCommandResult[];
|
||||
|
||||
@@ -227,9 +247,15 @@ export function getScriptConfigs(repoRoot: string): Map<string, ScriptConfig> {
|
||||
continue;
|
||||
}
|
||||
|
||||
const scriptConfig: ScriptConfig = { command };
|
||||
const scriptConfig: ScriptConfig =
|
||||
entry.type === "service"
|
||||
? {
|
||||
type: "service",
|
||||
command,
|
||||
}
|
||||
: { command };
|
||||
|
||||
if (typeof entry.port === "number" && Number.isFinite(entry.port)) {
|
||||
if (isServiceScript(scriptConfig) && typeof entry.port === "number" && Number.isFinite(entry.port)) {
|
||||
scriptConfig.port = entry.port;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user