From adbf94c81b0ee64f1da092fa7b12bc14e28d13a6 Mon Sep 17 00:00:00 2001 From: mari22q2 Date: Wed, 19 Aug 2026 09:48:35 +0200 Subject: [PATCH] fix(server): resolve partial clone repository identities --- .../RepositoryIdentityResolver.test.ts | 20 +++++++++++++++++++ .../src/project/RepositoryIdentityResolver.ts | 5 ++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/apps/server/src/project/RepositoryIdentityResolver.test.ts b/apps/server/src/project/RepositoryIdentityResolver.test.ts index a997459e63d7..43a520542b24 100644 --- a/apps/server/src/project/RepositoryIdentityResolver.test.ts +++ b/apps/server/src/project/RepositoryIdentityResolver.test.ts @@ -61,6 +61,26 @@ it.layer(NodeServices.layer)("RepositoryIdentityResolverLive", (it) => { }).pipe(Effect.provide(RepositoryIdentityResolver.layer)), ); + it.effect("resolves a promisor remote reported with a partial-clone annotation", () => + Effect.gen(function* () { + const fileSystem = yield* FileSystem.FileSystem; + const cwd = yield* fileSystem.makeTempDirectoryScoped({ + prefix: "t3-repository-identity-partial-clone-test-", + }); + + yield* git(cwd, ["init"]); + yield* git(cwd, ["remote", "add", "origin", "git@github.com:T3Tools/t3code.git"]); + yield* git(cwd, ["config", "remote.origin.promisor", "true"]); + yield* git(cwd, ["config", "remote.origin.partialclonefilter", "blob:none"]); + + const resolver = yield* RepositoryIdentityResolver.RepositoryIdentityResolver; + const identity = yield* resolver.resolve(cwd); + + expect(identity?.canonicalKey).toBe("github.com/t3tools/t3code"); + expect(identity?.locator.remoteName).toBe("origin"); + }).pipe(Effect.provide(RepositoryIdentityResolver.layer)), + ); + it.effect("returns the git top-level root path when resolving from a nested workspace", () => Effect.gen(function* () { const fileSystem = yield* FileSystem.FileSystem; diff --git a/apps/server/src/project/RepositoryIdentityResolver.ts b/apps/server/src/project/RepositoryIdentityResolver.ts index 50608e7704c7..d33f6d2499bd 100644 --- a/apps/server/src/project/RepositoryIdentityResolver.ts +++ b/apps/server/src/project/RepositoryIdentityResolver.ts @@ -34,7 +34,10 @@ function parseRemoteFetchUrls(stdout: string): Map { for (const line of stdout.split("\n")) { const trimmed = line.trim(); if (trimmed.length === 0) continue; - const match = /^(\S+)\s+(\S+)\s+\((fetch|push)\)$/.exec(trimmed); + // Partial clones append annotations such as `[blob:none]` after the + // direction. Keep accepting the stable remote/name fields while ignoring + // Git's optional transport metadata. + const match = /^(\S+)\s+(\S+)\s+\((fetch|push)\)(?:\s+\[[^\]]+\])*$/.exec(trimmed); if (!match) continue; const [, remoteName = "", remoteUrl = "", direction = ""] = match; if (direction !== "fetch" || remoteName.length === 0 || remoteUrl.length === 0) {