// 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);
}