Fix worktree seed source selection
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -7,6 +7,7 @@ import {
|
|||||||
copyGitHooksToWorktreeGitDir,
|
copyGitHooksToWorktreeGitDir,
|
||||||
copySeededSecretsKey,
|
copySeededSecretsKey,
|
||||||
rebindWorkspaceCwd,
|
rebindWorkspaceCwd,
|
||||||
|
resolveSourceConfigPath,
|
||||||
resolveGitWorktreeAddArgs,
|
resolveGitWorktreeAddArgs,
|
||||||
resolveWorktreeMakeTargetPath,
|
resolveWorktreeMakeTargetPath,
|
||||||
worktreeInitCommand,
|
worktreeInitCommand,
|
||||||
@@ -305,6 +306,59 @@ describe("worktree helpers", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("defaults the seed source config to the current repo-local Paperclip config", () => {
|
||||||
|
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "paperclip-worktree-source-config-"));
|
||||||
|
const repoRoot = path.join(tempRoot, "repo");
|
||||||
|
const localConfigPath = path.join(repoRoot, ".paperclip", "config.json");
|
||||||
|
const originalCwd = process.cwd();
|
||||||
|
const originalPaperclipConfig = process.env.PAPERCLIP_CONFIG;
|
||||||
|
|
||||||
|
try {
|
||||||
|
fs.mkdirSync(path.dirname(localConfigPath), { recursive: true });
|
||||||
|
fs.writeFileSync(localConfigPath, JSON.stringify(buildSourceConfig()), "utf8");
|
||||||
|
delete process.env.PAPERCLIP_CONFIG;
|
||||||
|
process.chdir(repoRoot);
|
||||||
|
|
||||||
|
expect(fs.realpathSync(resolveSourceConfigPath({}))).toBe(fs.realpathSync(localConfigPath));
|
||||||
|
} finally {
|
||||||
|
process.chdir(originalCwd);
|
||||||
|
if (originalPaperclipConfig === undefined) {
|
||||||
|
delete process.env.PAPERCLIP_CONFIG;
|
||||||
|
} else {
|
||||||
|
process.env.PAPERCLIP_CONFIG = originalPaperclipConfig;
|
||||||
|
}
|
||||||
|
fs.rmSync(tempRoot, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("preserves the source config path across worktree:make cwd changes", () => {
|
||||||
|
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "paperclip-worktree-source-override-"));
|
||||||
|
const sourceConfigPath = path.join(tempRoot, "source", "config.json");
|
||||||
|
const targetRoot = path.join(tempRoot, "target");
|
||||||
|
const originalCwd = process.cwd();
|
||||||
|
const originalPaperclipConfig = process.env.PAPERCLIP_CONFIG;
|
||||||
|
|
||||||
|
try {
|
||||||
|
fs.mkdirSync(path.dirname(sourceConfigPath), { recursive: true });
|
||||||
|
fs.mkdirSync(targetRoot, { recursive: true });
|
||||||
|
fs.writeFileSync(sourceConfigPath, JSON.stringify(buildSourceConfig()), "utf8");
|
||||||
|
delete process.env.PAPERCLIP_CONFIG;
|
||||||
|
process.chdir(targetRoot);
|
||||||
|
|
||||||
|
expect(resolveSourceConfigPath({ sourceConfigPathOverride: sourceConfigPath })).toBe(
|
||||||
|
path.resolve(sourceConfigPath),
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
process.chdir(originalCwd);
|
||||||
|
if (originalPaperclipConfig === undefined) {
|
||||||
|
delete process.env.PAPERCLIP_CONFIG;
|
||||||
|
} else {
|
||||||
|
process.env.PAPERCLIP_CONFIG = originalPaperclipConfig;
|
||||||
|
}
|
||||||
|
fs.rmSync(tempRoot, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it("rebinds same-repo workspace paths onto the current worktree root", () => {
|
it("rebinds same-repo workspace paths onto the current worktree root", () => {
|
||||||
expect(
|
expect(
|
||||||
rebindWorkspaceCwd({
|
rebindWorkspaceCwd({
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ type WorktreeInitOptions = {
|
|||||||
fromConfig?: string;
|
fromConfig?: string;
|
||||||
fromDataDir?: string;
|
fromDataDir?: string;
|
||||||
fromInstance?: string;
|
fromInstance?: string;
|
||||||
|
sourceConfigPathOverride?: string;
|
||||||
serverPort?: number;
|
serverPort?: number;
|
||||||
dbPort?: number;
|
dbPort?: number;
|
||||||
seed?: boolean;
|
seed?: boolean;
|
||||||
@@ -426,8 +427,12 @@ async function rebindSeededProjectWorkspaces(input: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveSourceConfigPath(opts: WorktreeInitOptions): string {
|
export function resolveSourceConfigPath(opts: WorktreeInitOptions): string {
|
||||||
|
if (opts.sourceConfigPathOverride) return path.resolve(opts.sourceConfigPathOverride);
|
||||||
if (opts.fromConfig) return path.resolve(opts.fromConfig);
|
if (opts.fromConfig) return path.resolve(opts.fromConfig);
|
||||||
|
if (!opts.fromDataDir && !opts.fromInstance) {
|
||||||
|
return resolveConfigPath();
|
||||||
|
}
|
||||||
const sourceHome = path.resolve(expandHomePrefix(opts.fromDataDir ?? "~/.paperclip"));
|
const sourceHome = path.resolve(expandHomePrefix(opts.fromDataDir ?? "~/.paperclip"));
|
||||||
const sourceInstanceId = sanitizeWorktreeInstanceId(opts.fromInstance ?? "default");
|
const sourceInstanceId = sanitizeWorktreeInstanceId(opts.fromInstance ?? "default");
|
||||||
return path.resolve(sourceHome, "instances", sourceInstanceId, "config.json");
|
return path.resolve(sourceHome, "instances", sourceInstanceId, "config.json");
|
||||||
@@ -751,6 +756,7 @@ export async function worktreeMakeCommand(nameArg: string, opts: WorktreeMakeOpt
|
|||||||
const name = resolveWorktreeMakeName(nameArg);
|
const name = resolveWorktreeMakeName(nameArg);
|
||||||
const startPoint = resolveWorktreeStartPoint(opts.startPoint);
|
const startPoint = resolveWorktreeStartPoint(opts.startPoint);
|
||||||
const sourceCwd = process.cwd();
|
const sourceCwd = process.cwd();
|
||||||
|
const sourceConfigPath = resolveSourceConfigPath(opts);
|
||||||
const targetPath = resolveWorktreeMakeTargetPath(name);
|
const targetPath = resolveWorktreeMakeTargetPath(name);
|
||||||
if (existsSync(targetPath)) {
|
if (existsSync(targetPath)) {
|
||||||
throw new Error(`Target path already exists: ${targetPath}`);
|
throw new Error(`Target path already exists: ${targetPath}`);
|
||||||
@@ -810,6 +816,7 @@ export async function worktreeMakeCommand(nameArg: string, opts: WorktreeMakeOpt
|
|||||||
await runWorktreeInit({
|
await runWorktreeInit({
|
||||||
...opts,
|
...opts,
|
||||||
name,
|
name,
|
||||||
|
sourceConfigPathOverride: sourceConfigPath,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error;
|
throw error;
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ This command:
|
|||||||
- creates an isolated instance under `~/.paperclip-worktrees/instances/<worktree-id>/`
|
- creates an isolated instance under `~/.paperclip-worktrees/instances/<worktree-id>/`
|
||||||
- when run inside a linked git worktree, mirrors the effective git hooks into that worktree's private git dir
|
- when run inside a linked git worktree, mirrors the effective git hooks into that worktree's private git dir
|
||||||
- picks a free app port and embedded PostgreSQL port
|
- picks a free app port and embedded PostgreSQL port
|
||||||
- by default seeds the isolated DB in `minimal` mode from your main instance via a logical SQL snapshot
|
- by default seeds the isolated DB in `minimal` mode from the current effective Paperclip instance/config (repo-local worktree config when present, otherwise the default instance) via a logical SQL snapshot
|
||||||
|
|
||||||
Seed modes:
|
Seed modes:
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user