mirror of
https://github.com/getpaseo/paseo.git
synced 2026-08-14 20:32:46 +00:00
fix(migrate): validate source refs and expansions
This commit is contained in:
@@ -118,6 +118,41 @@ test("does not adopt an existing worktree on a different branch", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("does not recreate a missing workspace from a tag", () => {
|
||||||
|
const repo = createRepository("tag-only-workspace", null);
|
||||||
|
execFileSync("git", ["commit", "--allow-empty", "-m", "initial"], {
|
||||||
|
cwd: repo,
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
GIT_AUTHOR_NAME: "Paseo Test",
|
||||||
|
GIT_AUTHOR_EMAIL: "test@paseo.local",
|
||||||
|
GIT_COMMITTER_NAME: "Paseo Test",
|
||||||
|
GIT_COMMITTER_EMAIL: "test@paseo.local",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
execFileSync("git", ["tag", "release"], { cwd: repo });
|
||||||
|
|
||||||
|
const inspected = inspectCatalog({
|
||||||
|
repos: [repoRecord("repo", repo)],
|
||||||
|
workspaces: [
|
||||||
|
{
|
||||||
|
id: "workspace-tag-only",
|
||||||
|
repoId: "repo",
|
||||||
|
branch: "release",
|
||||||
|
state: "ready",
|
||||||
|
path: null,
|
||||||
|
archiveCommit: null,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(inspected.projects[0]?.workspaces[0]).toMatchObject({
|
||||||
|
sourceId: "workspace-tag-only",
|
||||||
|
disposition: "missing-ref",
|
||||||
|
notices: [{ code: "missing-workspace-ref" }],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
function createRepository(name: string, settings: string | null): string {
|
function createRepository(name: string, settings: string | null): string {
|
||||||
const repo = mkdtempSync(path.join(os.tmpdir(), `paseo-inspect-${name}-`));
|
const repo = mkdtempSync(path.join(os.tmpdir(), `paseo-inspect-${name}-`));
|
||||||
cleanup.push(repo);
|
cleanup.push(repo);
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ function inspectWorkspace(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (workspace.branch && refExists(repo.rootPath, workspace.branch)) {
|
if (workspace.branch && localBranchExists(repo.rootPath, workspace.branch)) {
|
||||||
return {
|
return {
|
||||||
sourceId: workspace.id,
|
sourceId: workspace.id,
|
||||||
state: "ready",
|
state: "ready",
|
||||||
@@ -209,6 +209,17 @@ function refExists(rootPath: string, ref: string): boolean {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function localBranchExists(rootPath: string, branch: string): boolean {
|
||||||
|
const branchName = branch.replace(/^refs\/heads\//, "");
|
||||||
|
if (!branchName) return false;
|
||||||
|
try {
|
||||||
|
git(rootPath, ["show-ref", "--verify", "--quiet", `refs/heads/${branchName}`]);
|
||||||
|
return true;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function safeDirectoryName(workspace: ConductorWorkspaceRecord): string {
|
function safeDirectoryName(workspace: ConductorWorkspaceRecord): string {
|
||||||
const candidate = workspace.path ? path.basename(workspace.path.replaceAll("\\", "/")) : "";
|
const candidate = workspace.path ? path.basename(workspace.path.replaceAll("\\", "/")) : "";
|
||||||
if (/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(candidate) && candidate !== "." && candidate !== "..") {
|
if (/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(candidate) && candidate !== "." && candidate !== "..") {
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ test("preserves literal or escaped Conductor names and rewrites active variables
|
|||||||
arithmeticDirect: { command: "serve --port $(( $CONDUCTOR_PORT ))" },
|
arithmeticDirect: { command: "serve --port $(( $CONDUCTOR_PORT ))" },
|
||||||
arithmeticBraced: { command: "serve --port $(( ${CONDUCTOR_PORT} ))" },
|
arithmeticBraced: { command: "serve --port $(( ${CONDUCTOR_PORT} ))" },
|
||||||
arithmeticOffset: { command: "serve --port $(( CONDUCTOR_PORT + 1 ))" },
|
arithmeticOffset: { command: "serve --port $(( CONDUCTOR_PORT + 1 ))" },
|
||||||
|
prefixExpansion: { command: "serve --length ${#CONDUCTOR_PORT}" },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -187,6 +188,12 @@ test("preserves literal or escaped Conductor names and rewrites active variables
|
|||||||
message:
|
message:
|
||||||
"scripts.arithmeticOffset.port_arithmetic: Conductor port arithmetic is not imported because Paseo reserves one service port.",
|
"scripts.arithmeticOffset.port_arithmetic: Conductor port arithmetic is not imported because Paseo reserves one service port.",
|
||||||
});
|
});
|
||||||
|
expect(inspected.notices).toContainEqual({
|
||||||
|
code: "conductor-setting-unsupported",
|
||||||
|
level: "warning",
|
||||||
|
message:
|
||||||
|
"scripts.prefixExpansion: Unsupported Conductor variables: CONDUCTOR_PORT. Command was not imported.",
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("skips cwd scripts on Windows instead of emitting POSIX shell syntax", () => {
|
test("skips cwd scripts on Windows instead of emitting POSIX shell syntax", () => {
|
||||||
|
|||||||
@@ -613,7 +613,7 @@ function collectConductorVariables(command: string): string[] {
|
|||||||
const names = new Set<string>();
|
const names = new Set<string>();
|
||||||
const mask = activeShellMask(command);
|
const mask = activeShellMask(command);
|
||||||
const direct =
|
const direct =
|
||||||
/\$\{(CONDUCTOR_[A-Za-z0-9_]+)(?=[^A-Za-z0-9_])|\$(CONDUCTOR_[A-Za-z0-9_]+)(?![A-Za-z0-9_])/g;
|
/\$\{[#!]?(CONDUCTOR_[A-Za-z0-9_]+)(?=[^A-Za-z0-9_])|\$(CONDUCTOR_[A-Za-z0-9_]+)(?![A-Za-z0-9_])/g;
|
||||||
for (const match of command.matchAll(direct)) {
|
for (const match of command.matchAll(direct)) {
|
||||||
if (mask[match.index] !== "$") continue;
|
if (mask[match.index] !== "$") continue;
|
||||||
const name = match[1] ?? match[2];
|
const name = match[1] ?? match[2];
|
||||||
|
|||||||
Reference in New Issue
Block a user