mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-06 16:34:36 +00:00
refactor(import): load the import engine as a dependency
This commit is contained in:
+8
-105
@@ -3,7 +3,6 @@ import { existsSync, mkdtempSync, realpathSync, rmSync, statSync, writeFileSync
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { connectHostAutomation, connectToDaemon } from "@getpaseo/client/node";
|
||||
import { migrate } from "@getpaseo/migrate";
|
||||
import { afterEach, expect, test } from "vitest";
|
||||
import { hashDaemonPassword } from "../auth.js";
|
||||
import { createTestPaseoDaemon, type TestPaseoDaemon } from "../test-utils/paseo-daemon.js";
|
||||
@@ -38,59 +37,6 @@ function isWindowsBusyError(error: unknown): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
test("two complete migrations reuse the same real daemon checkout", async () => {
|
||||
const repoRoot = createRepository();
|
||||
const daemon = await createTestPaseoDaemon();
|
||||
cleanupDaemons.add(daemon);
|
||||
const paseo = await connectHostAutomation({
|
||||
appVersion: "0.1.110",
|
||||
clientId: "migration-idempotence-e2e",
|
||||
env: {},
|
||||
host: `127.0.0.1:${daemon.port}`,
|
||||
});
|
||||
cleanupConnections.add(paseo);
|
||||
const source = migrationSource(repoRoot);
|
||||
|
||||
const first = await migrate({ source, paseo, dryRun: false, output: () => undefined });
|
||||
const second = await migrate({ source, paseo, dryRun: false, output: () => undefined });
|
||||
|
||||
expect(first.notices).toEqual([]);
|
||||
expect(second.notices).toEqual([]);
|
||||
expect(listFeatureWorktrees(repoRoot)).toEqual([
|
||||
expect.objectContaining({ branch: "refs/heads/feature", path: expect.any(String) }),
|
||||
]);
|
||||
expect(path.basename(listFeatureWorktrees(repoRoot)[0]?.path ?? "")).toBe("imported-feature");
|
||||
});
|
||||
|
||||
test.skipIf(process.platform === "win32")(
|
||||
"a complete migration recreates an externally deleted checkout",
|
||||
async () => {
|
||||
const repoRoot = createRepository();
|
||||
const daemon = await createTestPaseoDaemon();
|
||||
cleanupDaemons.add(daemon);
|
||||
const paseo = await connectHostAutomation({
|
||||
appVersion: "0.1.110",
|
||||
clientId: "migration-deleted-checkout-e2e",
|
||||
env: {},
|
||||
host: `127.0.0.1:${daemon.port}`,
|
||||
});
|
||||
cleanupConnections.add(paseo);
|
||||
const source = migrationSource(repoRoot);
|
||||
|
||||
const first = await migrate({ source, paseo, dryRun: false, output: () => undefined });
|
||||
const deletedPath = listFeatureWorktrees(repoRoot)[0]?.path;
|
||||
if (!deletedPath) throw new Error("First migration did not create the feature checkout");
|
||||
rmSync(deletedPath, { recursive: true, force: true });
|
||||
expect(existsSync(deletedPath)).toBe(false);
|
||||
|
||||
const second = await migrate({ source, paseo, dryRun: false, output: () => undefined });
|
||||
|
||||
expect(first.notices).toEqual([]);
|
||||
expect(second.notices).toEqual([]);
|
||||
expect(existsSync(deletedPath)).toBe(true);
|
||||
},
|
||||
);
|
||||
|
||||
test("a different live checkout continues to protect its branch", async () => {
|
||||
const repoRoot = createRepository();
|
||||
const existingPath = path.join(path.dirname(repoRoot), "existing-feature");
|
||||
@@ -99,7 +45,7 @@ test("a different live checkout continues to protect its branch", async () => {
|
||||
cleanupDaemons.add(daemon);
|
||||
const paseo = await connectHostAutomation({
|
||||
appVersion: "0.1.110",
|
||||
clientId: "migration-live-protection-e2e",
|
||||
clientId: "import-live-protection-e2e",
|
||||
env: {},
|
||||
host: `127.0.0.1:${daemon.port}`,
|
||||
});
|
||||
@@ -129,7 +75,7 @@ test("ensureCheckout repairs only the requested missing registration", async ()
|
||||
cleanupDaemons.add(daemon);
|
||||
const paseo = await connectHostAutomation({
|
||||
appVersion: "0.1.110",
|
||||
clientId: "migration-stale-registration-e2e",
|
||||
clientId: "import-stale-registration-e2e",
|
||||
env: {},
|
||||
host: `127.0.0.1:${daemon.port}`,
|
||||
});
|
||||
@@ -157,7 +103,7 @@ test("normalized checkout-name collisions cannot reuse another branch", async ()
|
||||
cleanupDaemons.add(daemon);
|
||||
const paseo = await connectHostAutomation({
|
||||
appVersion: "0.1.110",
|
||||
clientId: "migration-slug-collision-e2e",
|
||||
clientId: "import-slug-collision-e2e",
|
||||
env: {},
|
||||
host: `127.0.0.1:${daemon.port}`,
|
||||
});
|
||||
@@ -201,7 +147,7 @@ test("the public connector authenticates to a real password-protected daemon and
|
||||
await expect(
|
||||
connectToDaemon({
|
||||
appVersion: "0.1.110",
|
||||
clientId: "migration-auth-failure-e2e",
|
||||
clientId: "import-auth-failure-e2e",
|
||||
env: { PASEO_PASSWORD: "wrong-secret" },
|
||||
host: `127.0.0.1:${daemon.port}`,
|
||||
timeoutMs: 2_000,
|
||||
@@ -210,7 +156,7 @@ test("the public connector authenticates to a real password-protected daemon and
|
||||
|
||||
const client = await connectToDaemon({
|
||||
appVersion: "0.1.110",
|
||||
clientId: "migration-auth-success-e2e",
|
||||
clientId: "import-auth-success-e2e",
|
||||
env: { PASEO_PASSWORD: "connector-secret" },
|
||||
host: `127.0.0.1:${daemon.port}`,
|
||||
});
|
||||
@@ -230,7 +176,7 @@ test("the public connector uses PORT fallback and skips malformed discovered can
|
||||
|
||||
const client = await connectToDaemon({
|
||||
appVersion: "0.1.110",
|
||||
clientId: "migration-port-fallback-e2e",
|
||||
clientId: "import-port-fallback-e2e",
|
||||
env: { PASEO_HOME: paseoHome, PORT: String(daemon.port) },
|
||||
});
|
||||
cleanupConnections.add(client);
|
||||
@@ -251,7 +197,7 @@ test.skipIf(process.platform === "win32")(
|
||||
|
||||
const client = await connectToDaemon({
|
||||
appVersion: "0.1.110",
|
||||
clientId: "migration-ipc-e2e",
|
||||
clientId: "import-ipc-e2e",
|
||||
env: {},
|
||||
host: `unix://${socketPath}`,
|
||||
});
|
||||
@@ -262,7 +208,7 @@ test.skipIf(process.platform === "win32")(
|
||||
);
|
||||
|
||||
function createRepository(): string {
|
||||
const parent = realpathSync(mkdtempSync(path.join(os.tmpdir(), "paseo-migration-daemon-")));
|
||||
const parent = realpathSync(mkdtempSync(path.join(os.tmpdir(), "paseo-import-daemon-")));
|
||||
cleanupPaths.add(parent);
|
||||
const repoRoot = path.join(parent, "repo");
|
||||
execFileSync("git", ["init", "-b", "main", repoRoot]);
|
||||
@@ -276,46 +222,3 @@ function createRepository(): string {
|
||||
execFileSync("git", ["branch", "feature"], { cwd: repoRoot });
|
||||
return realpathSync(repoRoot);
|
||||
}
|
||||
|
||||
function migrationSource(repoRoot: string) {
|
||||
return {
|
||||
id: "fixture",
|
||||
inspect: async () => ({
|
||||
skippedSettings: [],
|
||||
projects: [
|
||||
{
|
||||
sourceId: "project",
|
||||
rootPath: repoRoot,
|
||||
config: null,
|
||||
notices: [],
|
||||
workspaces: [
|
||||
{
|
||||
sourceId: "workspace",
|
||||
state: "ready",
|
||||
path: null,
|
||||
branch: "feature",
|
||||
archiveCommit: null,
|
||||
directoryName: "imported-feature",
|
||||
disposition: "create" as const,
|
||||
notices: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
function listFeatureWorktrees(repoRoot: string): Array<{ path: string; branch: string }> {
|
||||
const entries = execFileSync("git", ["worktree", "list", "--porcelain"], {
|
||||
cwd: repoRoot,
|
||||
encoding: "utf8",
|
||||
})
|
||||
.trim()
|
||||
.split("\n\n");
|
||||
return entries.flatMap((entry) => {
|
||||
const worktreePath = entry.match(/^worktree (.+)$/m)?.[1];
|
||||
const branch = entry.match(/^branch (.+)$/m)?.[1];
|
||||
return worktreePath && branch === "refs/heads/feature" ? [{ path: worktreePath, branch }] : [];
|
||||
});
|
||||
}
|
||||
@@ -1,7 +1,4 @@
|
||||
import { projectServiceProxyUrls } from "./service-proxy.js";
|
||||
import { normalizeServiceEnvName } from "@getpaseo/protocol/service-env-name";
|
||||
|
||||
export { normalizeServiceEnvName } from "@getpaseo/protocol/service-env-name";
|
||||
|
||||
export interface WorkspaceServicePeer {
|
||||
scriptName: string;
|
||||
@@ -18,6 +15,13 @@ export interface BuildWorkspaceServiceEnvOptions {
|
||||
peers: readonly WorkspaceServicePeer[];
|
||||
}
|
||||
|
||||
export function normalizeServiceEnvName(scriptName: string): string {
|
||||
return scriptName
|
||||
.toUpperCase()
|
||||
.replace(/[^A-Z0-9]+/g, "_")
|
||||
.replace(/^_+|_+$/g, "");
|
||||
}
|
||||
|
||||
export function buildWorkspaceServiceEnv(
|
||||
options: BuildWorkspaceServiceEnvOptions,
|
||||
): Record<string, string> {
|
||||
|
||||
Reference in New Issue
Block a user