mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
feat(server): configure workspace service port allocation (#2165)
* starr * fix(server): honor service port allocator contracts * fix(server): pass workspace context to port scripts * fix(server): cancel released service port plans * test(server): support Windows port allocator fixtures * docs(worktrees): clarify shell-less portScript execution
This commit is contained in:
@@ -33,6 +33,28 @@ describe("paseo config schema", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("parses service port allocation", () => {
|
||||
expect(
|
||||
PaseoConfigSchema.parse({
|
||||
worktree: {
|
||||
servicePorts: { range: "3000-4000", portScript: "/usr/bin/portmake" },
|
||||
},
|
||||
}),
|
||||
).toEqual({
|
||||
worktree: {
|
||||
setup: [],
|
||||
teardown: [],
|
||||
servicePorts: { range: "3000-4000", portScript: "/usr/bin/portmake" },
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("rejects invalid service port ranges", () => {
|
||||
expect(() =>
|
||||
PaseoConfigRawSchema.parse({ worktree: { servicePorts: { range: "4000-3000" } } }),
|
||||
).toThrow("Expected an inclusive TCP port range");
|
||||
});
|
||||
|
||||
it("normalizes partial worktree lifecycle config without dropping present commands", () => {
|
||||
expect(
|
||||
PaseoConfigSchema.parse({
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
import { z } from "zod";
|
||||
|
||||
const TCP_PORT_RANGE_PATTERN = /^(\d{1,5})-(\d{1,5})$/;
|
||||
|
||||
export const PaseoServicePortAllocationSchema = z
|
||||
.object({
|
||||
range: z.string().trim().regex(TCP_PORT_RANGE_PATTERN).optional(),
|
||||
portScript: z.string().trim().min(1).optional(),
|
||||
})
|
||||
.strict()
|
||||
.refine(
|
||||
(value) => value.range !== undefined || value.portScript !== undefined,
|
||||
"Expected range or portScript",
|
||||
)
|
||||
.refine((value) => {
|
||||
if (!value.range) return true;
|
||||
const match = TCP_PORT_RANGE_PATTERN.exec(value.range);
|
||||
if (!match) return false;
|
||||
const start = Number(match[1]);
|
||||
const end = Number(match[2]);
|
||||
return start >= 1 && end <= 65_535 && start <= end;
|
||||
}, "Expected an inclusive TCP port range from 1-65535");
|
||||
|
||||
export function normalizeLifecycleCommands(commands: unknown): string[] {
|
||||
if (typeof commands === "string") {
|
||||
return commands.trim().length > 0 ? [commands] : [];
|
||||
@@ -27,6 +48,7 @@ export const PaseoWorktreeConfigRawSchema = z
|
||||
setup: PaseoLifecycleCommandRawSchema.optional(),
|
||||
teardown: PaseoLifecycleCommandRawSchema.optional(),
|
||||
terminals: z.unknown().optional(),
|
||||
servicePorts: PaseoServicePortAllocationSchema.optional(),
|
||||
})
|
||||
.passthrough();
|
||||
|
||||
@@ -92,6 +114,7 @@ export const ProjectConfigRpcErrorSchema = z.discriminatedUnion("code", [
|
||||
export type PaseoScriptEntryRaw = z.infer<typeof PaseoScriptEntryRawSchema>;
|
||||
export type PaseoMetadataGenerationEntry = z.infer<typeof PaseoMetadataGenerationEntrySchema>;
|
||||
export type PaseoMetadataGeneration = z.infer<typeof PaseoMetadataGenerationSchema>;
|
||||
export type PaseoServicePortAllocation = z.infer<typeof PaseoServicePortAllocationSchema>;
|
||||
export type PaseoConfigRaw = z.infer<typeof PaseoConfigRawSchema>;
|
||||
export type PaseoConfig = z.infer<typeof PaseoConfigSchema>;
|
||||
export type PaseoConfigRevision = z.infer<typeof PaseoConfigRevisionSchema>;
|
||||
|
||||
Reference in New Issue
Block a user