// Origin URL — builds a resolvable URL pointing to a TODO issue in the repo's web UI // Format varies by host: // Bitbucket: /src//# // GitHub: /blob//# // GitLab: /-/blob//# import { execSync } from "child_process"; export function getGitRemoteUrl(cwd = process.cwd()) { try { return execSync("git remote get-url origin", { cwd, encoding: "utf-8" }).trim(); } catch { throw new Error("Could not determine git remote URL. Is this a git repository with an 'origin' remote?"); } } export function getGitBranch(cwd = process.cwd()) { try { return execSync("git rev-parse --abbrev-ref HEAD", { cwd, encoding: "utf-8" }).trim(); } catch { return "main"; } } export function normalizeRemoteUrl(url) { let normalized = url; const sshMatch = normalized.match(/^git@([^:]+):(.+?)(?:\.git)?$/); if (sshMatch) { normalized = `https://${sshMatch[1]}/${sshMatch[2]}`; } normalized = normalized.replace(/\.git$/, ""); normalized = normalized.replace(/\/+$/, ""); return normalized; } function detectHost(url) { if (url.includes("bitbucket.org")) return "bitbucket"; if (url.includes("github.com")) return "github"; if (url.includes("gitlab.com") || url.includes("gitlab")) return "gitlab"; return "unknown"; } export function buildOriginUrl(remoteUrl, branch, todoPath, issueId) { const base = normalizeRemoteUrl(remoteUrl); const host = detectHost(base); switch (host) { case "github": return `${base}/blob/${branch}/${todoPath}#${issueId}`; case "gitlab": return `${base}/-/blob/${branch}/${todoPath}#${issueId}`; case "bitbucket": default: return `${base}/src/${branch}/${todoPath}#${issueId}`; } } export function buildCommitUrl(remoteUrl, commitHash) { const base = normalizeRemoteUrl(remoteUrl); const host = detectHost(base); switch (host) { case "github": return `${base}/commit/${commitHash}`; case "gitlab": return `${base}/-/commit/${commitHash}`; case "bitbucket": default: return `${base}/commits/${commitHash}`; } } export function shortHash(hash) { return hash.slice(0, 7); }