Add worktree init CLI for isolated development instances

This commit is contained in:
Dotta
2026-03-10 10:08:13 -05:00
parent 49b9511889
commit 0704854926
9 changed files with 760 additions and 7 deletions

View File

@@ -9,6 +9,7 @@ export type RunDatabaseBackupOptions = {
retentionDays: number;
filenamePrefix?: string;
connectTimeoutSeconds?: number;
includeMigrationJournal?: boolean;
};
export type RunDatabaseBackupResult = {
@@ -17,6 +18,12 @@ export type RunDatabaseBackupResult = {
prunedCount: number;
};
export type RunDatabaseRestoreOptions = {
connectionString: string;
backupFile: string;
connectTimeoutSeconds?: number;
};
function timestamp(date: Date = new Date()): string {
const pad = (n: number) => String(n).padStart(2, "0");
return `${date.getFullYear()}${pad(date.getMonth() + 1)}${pad(date.getDate())}-${pad(date.getHours())}${pad(date.getMinutes())}${pad(date.getSeconds())}`;
@@ -51,6 +58,7 @@ export async function runDatabaseBackup(opts: RunDatabaseBackupOptions): Promise
const filenamePrefix = opts.filenamePrefix ?? "paperclip";
const retentionDays = Math.max(1, Math.trunc(opts.retentionDays));
const connectTimeout = Math.max(1, Math.trunc(opts.connectTimeoutSeconds ?? 5));
const includeMigrationJournal = opts.includeMigrationJournal === true;
const sql = postgres(opts.connectionString, { max: 1, connect_timeout: connectTimeout });
try {
@@ -89,7 +97,7 @@ export async function runDatabaseBackup(opts: RunDatabaseBackupOptions): Promise
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE n.nspname = 'public'
AND c.relkind = 'r'
AND c.relname != '__drizzle_migrations'
AND (${includeMigrationJournal}::boolean OR c.relname != '__drizzle_migrations')
ORDER BY c.relname
`;
@@ -326,6 +334,18 @@ export async function runDatabaseBackup(opts: RunDatabaseBackupOptions): Promise
}
}
export async function runDatabaseRestore(opts: RunDatabaseRestoreOptions): Promise<void> {
const connectTimeout = Math.max(1, Math.trunc(opts.connectTimeoutSeconds ?? 5));
const sql = postgres(opts.connectionString, { max: 1, connect_timeout: connectTimeout });
try {
await sql`SELECT 1`;
await sql.file(opts.backupFile).execute();
} finally {
await sql.end();
}
}
export function formatDatabaseBackupResult(result: RunDatabaseBackupResult): string {
const size = formatBackupSize(result.sizeBytes);
const pruned = result.prunedCount > 0 ? `; pruned ${result.prunedCount} old backup(s)` : "";

View File

@@ -12,8 +12,10 @@ export {
} from "./client.js";
export {
runDatabaseBackup,
runDatabaseRestore,
formatDatabaseBackupResult,
type RunDatabaseBackupOptions,
type RunDatabaseBackupResult,
type RunDatabaseRestoreOptions,
} from "./backup-lib.js";
export * from "./schema/index.js";