diff --git a/packages/server/src/server/workspace-git-metadata.test.ts b/packages/server/src/server/workspace-git-metadata.test.ts index 5b245a7d7..d1a824b41 100644 --- a/packages/server/src/server/workspace-git-metadata.test.ts +++ b/packages/server/src/server/workspace-git-metadata.test.ts @@ -5,7 +5,11 @@ import path from "node:path"; import { afterEach, beforeEach, describe, expect, test } from "vitest"; -import { deriveProjectSlug, parseGitHubRepoNameFromRemote } from "./workspace-git-metadata.js"; +import { + buildWorkspaceGitMetadataFromSnapshot, + deriveProjectSlug, + parseGitHubRepoNameFromRemote, +} from "./workspace-git-metadata.js"; function runGit(cwd: string, args: string[]): void { execFileSync("git", args, { @@ -166,3 +170,47 @@ describe("deriveProjectSlug", () => { expect(deriveProjectSlug(cwd)).toBe("untitled"); }); }); + +describe("buildWorkspaceGitMetadataFromSnapshot", () => { + test("uses owner/repo as the display name for GitHub remotes", () => { + const result = buildWorkspaceGitMetadataFromSnapshot({ + cwd: "/repos/some-dir", + directoryName: "some-dir", + isGit: true, + repoRoot: "/repos/some-dir", + mainRepoRoot: null, + currentBranch: "main", + remoteUrl: "git@github.com:acme/widgets.git", + }); + + expect(result.projectDisplayName).toBe("acme/widgets"); + }); + + test("uses owner/repo as the display name for non-GitHub remotes", () => { + const result = buildWorkspaceGitMetadataFromSnapshot({ + cwd: "/repos/random-name", + directoryName: "random-name", + isGit: true, + repoRoot: "/repos/random-name", + mainRepoRoot: null, + currentBranch: "main", + remoteUrl: "git@gitlab.com:acme/app.git", + }); + + expect(result.projectDisplayName).toBe("acme/app"); + }); + + test("falls back to the directory name when there is no remote", () => { + const result = buildWorkspaceGitMetadataFromSnapshot({ + cwd: "/repos/local-only", + directoryName: "local-only", + isGit: true, + repoRoot: "/repos/local-only", + mainRepoRoot: null, + currentBranch: "main", + remoteUrl: null, + }); + + expect(result.projectDisplayName).toBe("local-only"); + }); +}); diff --git a/packages/server/src/server/workspace-git-metadata.ts b/packages/server/src/server/workspace-git-metadata.ts index e78e7139e..73acf93c7 100644 --- a/packages/server/src/server/workspace-git-metadata.ts +++ b/packages/server/src/server/workspace-git-metadata.ts @@ -1,6 +1,7 @@ import { basename } from "path"; import { parseGitHubRemoteUrl } from "../utils/github-remote.js"; import { slugify } from "../utils/worktree.js"; +import { deriveProjectGroupingKey, deriveProjectGroupingName } from "./workspace-registry-model.js"; export interface WorkspaceGitMetadata { projectKind: "git" | "directory"; @@ -57,13 +58,20 @@ export function buildWorkspaceGitMetadataFromSnapshot(input: { }; } - const githubRepo = input.remoteUrl ? parseGitHubRepoFromRemote(input.remoteUrl) : null; const isWorktree = input.mainRepoRoot !== null && input.repoRoot !== null && input.mainRepoRoot !== input.repoRoot; + const projectKey = deriveProjectGroupingKey({ + cwd: input.repoRoot ?? input.cwd, + remoteUrl: input.remoteUrl, + mainRepoRoot: input.mainRepoRoot, + }); + const projectDisplayName = projectKey.startsWith("remote:") + ? deriveProjectGroupingName(projectKey) + : input.directoryName; return { projectKind: "git", - projectDisplayName: githubRepo ?? input.directoryName, + projectDisplayName, workspaceDisplayName: input.currentBranch ?? input.directoryName, gitRemote: input.remoteUrl, isWorktree,