From f2124f8cf92f973f5e7f68133c383cb067c04a33 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Sun, 19 Jul 2026 01:50:04 +0200 Subject: [PATCH] fix(migrate): normalize source references --- .../app/e2e/conductor-migration.electron.spec.ts | 3 ++- .../src/sources/conductor/database.test.ts | 15 +++++++++++++++ .../migrate/src/sources/conductor/database.ts | 3 ++- .../src/sources/conductor/project-config.test.ts | 4 ++++ .../src/sources/conductor/project-config.ts | 2 +- 5 files changed, 24 insertions(+), 3 deletions(-) diff --git a/packages/app/e2e/conductor-migration.electron.spec.ts b/packages/app/e2e/conductor-migration.electron.spec.ts index e9e7b3a33..9c45ae5b8 100644 --- a/packages/app/e2e/conductor-migration.electron.spec.ts +++ b/packages/app/e2e/conductor-migration.electron.spec.ts @@ -19,6 +19,7 @@ import { } from "@playwright/test"; test.skip(process.env.E2E_DESKTOP_RUNTIME !== "1", "requires the real Electron product runtime"); +test.setTimeout(180_000); const repoRoot = path.resolve(__dirname, "../../.."); let installation: Awaited>; @@ -82,7 +83,7 @@ async function launchProduct(): Promise { async function openIntegrations(page: Page): Promise { const settings = page.getByRole("button", { name: "Settings", exact: true }); - await expect(settings).toBeVisible({ timeout: 30_000 }); + await expect(settings).toBeVisible({ timeout: 90_000 }); await settings.click(); await expect(page.getByTestId("settings-sidebar")).toBeVisible(); await page.getByRole("button", { name: "Integrations", exact: true }).click(); diff --git a/packages/migrate/src/sources/conductor/database.test.ts b/packages/migrate/src/sources/conductor/database.test.ts index 2bc36cfc7..c678817c0 100644 --- a/packages/migrate/src/sources/conductor/database.test.ts +++ b/packages/migrate/src/sources/conductor/database.test.ts @@ -110,6 +110,21 @@ test("reports malformed database JSON and script columns per project", async () ]); }); +test("normalizes fully qualified local workspace branches", async () => { + const databasePath = temporaryDatabase(); + cpSync(fixturePath, databasePath); + const database = await openFixtureDatabase(databasePath); + database.run("UPDATE workspaces SET branch = 'refs/heads/feature' WHERE branch IS NOT NULL"); + saveFixtureDatabase(databasePath, database); + + const branches = (await readConductorCatalog(databasePath)).workspaces + .map((workspace) => workspace.branch) + .filter((branch): branch is string => branch !== null); + + expect(branches).toContain("feature"); + expect(branches.some((branch) => branch.startsWith("refs/heads/"))).toBe(false); +}); + function temporaryDatabase(): string { const directory = mkdtempSync(path.join(os.tmpdir(), "paseo-migrate-db-")); cleanup.push(directory); diff --git a/packages/migrate/src/sources/conductor/database.ts b/packages/migrate/src/sources/conductor/database.ts index 087c28f73..cdbdc6bb1 100644 --- a/packages/migrate/src/sources/conductor/database.ts +++ b/packages/migrate/src/sources/conductor/database.ts @@ -141,10 +141,11 @@ function parseRepo(value: unknown): ConductorRepoRecord { function parseWorkspace(value: unknown): ConductorWorkspaceRecord { const row = record(value); + const branch = optionalString(row.branch); return { id: stringColumn(row, "id"), repoId: stringColumn(row, "repo_id"), - branch: optionalString(row.branch), + branch: branch?.replace(/^refs\/heads\//, "") ?? null, state: stringColumn(row, "state"), path: optionalString(row.path), archiveCommit: optionalString(row.archive_commit), diff --git a/packages/migrate/src/sources/conductor/project-config.test.ts b/packages/migrate/src/sources/conductor/project-config.test.ts index 24116057a..4f2775e7d 100644 --- a/packages/migrate/src/sources/conductor/project-config.test.ts +++ b/packages/migrate/src/sources/conductor/project-config.test.ts @@ -76,6 +76,9 @@ cwd = "../outside" [scripts.run.unknown_variable] command = "echo $CONDUCTOR_UNSUPPORTED_VALUE" + +[scripts.run.unsupported_substitution] +command = "serve --port \${CONDUCTOR_PORT/3000/3001}" `, ); @@ -93,6 +96,7 @@ command = "echo $CONDUCTOR_UNSUPPORTED_VALUE" "scripts.absolute.cwd: Absolute or escaping cwd values are not imported.", "scripts.escape.cwd: Absolute or escaping cwd values are not imported.", "scripts.unknown_variable: Unsupported Conductor variables: CONDUCTOR_UNSUPPORTED_VALUE. Command was not imported.", + "scripts.unsupported_substitution: Unsupported Conductor variables: CONDUCTOR_PORT. Command was not imported.", "settings.unknown_project_setting: Unknown Conductor setting.", ]), ); diff --git a/packages/migrate/src/sources/conductor/project-config.ts b/packages/migrate/src/sources/conductor/project-config.ts index c6dd4e124..05d9d468c 100644 --- a/packages/migrate/src/sources/conductor/project-config.ts +++ b/packages/migrate/src/sources/conductor/project-config.ts @@ -602,7 +602,7 @@ function collectConductorVariables(command: string): string[] { const names = new Set(); const mask = activeShellMask(command); const direct = - /\$\{(CONDUCTOR_[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)) { if (mask[match.index] !== "$") continue; const name = match[1] ?? match[2];