Showing the changes to packages/shared/src/sourceControl.ts (1 of 172 files). Show all
Unified · Split
| @@ -1,4 +1,8 @@ | ||
| 1 | −import type { SourceControlProviderInfo, SourceControlProviderKind } from "@t3tools/contracts"; | |
| 1 | +import type { | |
| 2 | + RepositoryIdentity, | |
| 3 | + SourceControlProviderInfo, | |
| 4 | + SourceControlProviderKind, | |
| 5 | +} from "@t3tools/contracts"; | |
| 2 | 6 | |
| 3 | 7 | export interface ChangeRequestPresentation { |
| 4 | 8 | readonly icon: "github" | "gitlab" | "azure-devops" | "bitbucket" | "change-request"; |
| @@ -234,3 +238,43 @@ export function detectSourceControlProviderFromRemoteUrl( · 229 unmodified lines | ||
| 234 | 238 | baseUrl: toBaseUrl(host), |
| 235 | 239 | }; |
| 236 | 240 | } |
| 241 | + | |
| 242 | +/** | |
| 243 | + * The provider-native repository selector. `displayName` is the full path below the host, which | |
| 244 | + * is what nested GitLab groups need; owner/name is the two-segment fallback for identities | |
| 245 | + * recorded before that field existed. | |
| 246 | + * | |
| 247 | + * Azure DevOps is the exception: `az repos pr list --repository` takes a repository name, and | |
| 248 | + * takes the organisation and project from the checkout it detects — so the recorded | |
| 249 | + * `org/project/_git/repo` path is refused outright and the whole repository reads as | |
| 250 | + * unavailable. Its name is the last segment, which is what this hands over. | |
| 251 | + * | |
| 252 | + * One function because everything downstream is keyed by what it answers: the rows' own | |
| 253 | + * `repository`, the per-repository cursors, and the detail and diff reads a row leads to. | |
| 254 | + */ | |
| 255 | +export function sourceControlRepositorySelector( | |
| 256 | + identity: | |
| 257 | + | Pick<RepositoryIdentity, "provider" | "displayName" | "owner" | "name"> | |
| 258 | + | null | |
| 259 | + | undefined, | |
| 260 | +): string | null { | |
| 261 | + if (!identity) return null; | |
| 262 | + if (identity.provider === "azure-devops") { | |
| 263 | + const segments = (identity.displayName ?? "").split("/").filter((part) => part !== "_git"); | |
| 264 | + return identity.name || segments.at(-1) || null; | |
| 265 | + } | |
| 266 | + if (identity.displayName) return identity.displayName; | |
| 267 | + return identity.owner && identity.name ? `${identity.owner}/${identity.name}` : null; | |
| 268 | +} | |
| 269 | + | |
| 270 | +export function canonicalRepositoryKey(key: string): string { | |
| 271 | + return key | |
| 272 | + .replace( | |
| 273 | + /^(?:ssh\.dev\.azure\.com|vs-ssh\.visualstudio\.com)\/v3\/([^/]+)\/([^/]+)\/([^/]+)$/u, | |
| 274 | + "dev.azure.com/$1/$2/_git/$3", | |
| 275 | + ) | |
| 276 | + .replace( | |
| 277 | + /^([^.]+)\.visualstudio\.com\/(?:defaultcollection\/)?([^/]+)\/_git\/([^/]+)$/u, | |
| 278 | + "dev.azure.com/$1/$2/_git/$3", | |
| 279 | + ); | |
| 280 | +} | |