mirror of
https://github.com/alkimake/paperclip.git
synced 2026-06-14 18:10:39 +09:00
Address Greptile feedback on workspace reuse
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
parent
2b18fc4007
commit
477ef78fed
6 changed files with 109 additions and 24 deletions
|
|
@ -198,6 +198,44 @@ describe("buildRealizedExecutionWorkspaceFromPersisted", () => {
|
|||
expect(result.branchName).toBe("PAP-880-thumbs-capture-for-evals-feature");
|
||||
expect(result.source).toBe("task_session");
|
||||
});
|
||||
|
||||
it("falls back to realization when the persisted workspace has no local path yet", () => {
|
||||
const result = buildRealizedExecutionWorkspaceFromPersisted({
|
||||
base: buildResolvedWorkspace({
|
||||
cwd: "/tmp/project-primary",
|
||||
repoRef: "main",
|
||||
}),
|
||||
workspace: {
|
||||
id: "execution-workspace-2",
|
||||
companyId: "company-1",
|
||||
projectId: "project-1",
|
||||
projectWorkspaceId: "workspace-1",
|
||||
sourceIssueId: "issue-2",
|
||||
mode: "isolated_workspace",
|
||||
strategyType: "git_worktree",
|
||||
name: "PAP-999-missing-provider-ref",
|
||||
status: "active",
|
||||
cwd: null,
|
||||
repoUrl: "https://example.com/paperclip.git",
|
||||
baseRef: "main",
|
||||
branchName: "feature/PAP-999-missing-provider-ref",
|
||||
providerType: "git_worktree",
|
||||
providerRef: null,
|
||||
derivedFromExecutionWorkspaceId: null,
|
||||
lastUsedAt: new Date(),
|
||||
openedAt: new Date(),
|
||||
closedAt: null,
|
||||
cleanupEligibleAt: null,
|
||||
cleanupReason: null,
|
||||
config: null,
|
||||
metadata: null,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("stripWorkspaceRuntimeFromExecutionRunConfig", () => {
|
||||
|
|
|
|||
|
|
@ -284,6 +284,40 @@ describe("realizeExecutionWorkspace", () => {
|
|||
expect(path.basename(realized.cwd)).toBe(realized.branchName);
|
||||
});
|
||||
|
||||
it("preserves intentional slashes and dots from the branch template", async () => {
|
||||
const repoRoot = await createTempRepo();
|
||||
|
||||
const realized = await realizeExecutionWorkspace({
|
||||
base: {
|
||||
baseCwd: repoRoot,
|
||||
source: "project_primary",
|
||||
projectId: "project-1",
|
||||
workspaceId: "workspace-1",
|
||||
repoUrl: null,
|
||||
repoRef: "HEAD",
|
||||
},
|
||||
config: {
|
||||
workspaceStrategy: {
|
||||
type: "git_worktree",
|
||||
branchTemplate: "release/{{issue.identifier}}.{{slug}}",
|
||||
},
|
||||
},
|
||||
issue: {
|
||||
id: "issue-template-safe",
|
||||
identifier: "PAP-992",
|
||||
title: "Hotfix / April.1",
|
||||
},
|
||||
agent: {
|
||||
id: "agent-1",
|
||||
name: "Codex Coder",
|
||||
companyId: "company-1",
|
||||
},
|
||||
});
|
||||
|
||||
expect(realized.branchName).toBe("release/PAP-992.hotfix-april-1");
|
||||
expect(path.basename(realized.cwd)).toBe("PAP-992.hotfix-april-1");
|
||||
});
|
||||
|
||||
it("runs a configured provision command inside the derived worktree", async () => {
|
||||
const repoRoot = await createTempRepo();
|
||||
await fs.mkdir(path.join(repoRoot, "scripts"), { recursive: true });
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ export function buildInvocationEnvForLogs(
|
|||
env: Record<string, string>,
|
||||
options: BuildInvocationEnvForLogsOptions = {},
|
||||
): Record<string, string> {
|
||||
// TODO: Remove this fallback once @paperclipai/adapter-utils exports buildInvocationEnvForLogs everywhere we consume it.
|
||||
const maybeBuildInvocationEnvForLogs = (
|
||||
serverUtils as typeof serverUtils & {
|
||||
buildInvocationEnvForLogs?: (
|
||||
|
|
|
|||
|
|
@ -114,10 +114,10 @@ export function stripWorkspaceRuntimeFromExecutionRunConfig(config: Record<strin
|
|||
export function buildRealizedExecutionWorkspaceFromPersisted(input: {
|
||||
base: ExecutionWorkspaceInput;
|
||||
workspace: ExecutionWorkspace;
|
||||
}): RealizedExecutionWorkspace {
|
||||
}): RealizedExecutionWorkspace | null {
|
||||
const cwd = readNonEmptyString(input.workspace.cwd) ?? readNonEmptyString(input.workspace.providerRef);
|
||||
if (!cwd) {
|
||||
throw new Error(`Execution workspace ${input.workspace.id} has no local path to reuse.`);
|
||||
return null;
|
||||
}
|
||||
|
||||
const strategy = input.workspace.strategyType === "git_worktree" ? "git_worktree" : "project_primary";
|
||||
|
|
@ -2191,12 +2191,13 @@ export function heartbeatService(db: Db) {
|
|||
repoUrl: resolvedWorkspace.repoUrl,
|
||||
repoRef: resolvedWorkspace.repoRef,
|
||||
} satisfies ExecutionWorkspaceInput;
|
||||
const executionWorkspace = shouldReuseExisting && existingExecutionWorkspace
|
||||
const reusedExecutionWorkspace = shouldReuseExisting && existingExecutionWorkspace
|
||||
? buildRealizedExecutionWorkspaceFromPersisted({
|
||||
base: executionWorkspaceBase,
|
||||
workspace: existingExecutionWorkspace,
|
||||
})
|
||||
: await realizeExecutionWorkspace({
|
||||
: null;
|
||||
const executionWorkspace = reusedExecutionWorkspace ?? await realizeExecutionWorkspace({
|
||||
base: executionWorkspaceBase,
|
||||
config: runtimeConfig,
|
||||
issue: issueRef,
|
||||
|
|
|
|||
|
|
@ -231,9 +231,9 @@ function renderWorkspaceTemplate(template: string, input: {
|
|||
function sanitizeBranchName(value: string): string {
|
||||
return value
|
||||
.trim()
|
||||
.replace(/[^A-Za-z0-9_-]+/g, "-")
|
||||
.replace(/[^A-Za-z0-9._/-]+/g, "-")
|
||||
.replace(/-+/g, "-")
|
||||
.replace(/^[-_]+|[-_]+$/g, "")
|
||||
.replace(/^[-/.]+|[-/.]+$/g, "")
|
||||
.slice(0, 120) || "paperclip-work";
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue