* Add PR number segment to status bar Add a new 'pr' status line segment that shows the GitHub PR number (e.g., #1234) as a clickable OSC 8 hyperlink when the current branch has an associated pull request. - Async lookup via 'gh pr view', cached per branch - Invalidates on branch change via .git/HEAD watcher - Falls back to hidden segment when no PR exists or gh unavailable - Supports all theme presets (unicode, nerd font, ascii) - Added to all preset layouts after the git segment * Skip PR lookup on default branch, resolve dynamically * Extract git-utils, add tests for parseGitHubRepo and parseDefaultBranch * Fix PR lookup race condition, invalidation churn, and dotted repo names - Guard #cachedPr writes against branch change during in-flight lookup - Stop clearing PR cache in invalidate() (only .git/HEAD watcher should) - Allow dots in GitHub repo names in parseGitHubRepo regex * Simplify PR lookup: use gh pr view, try upstream/HEAD for default branch - Replace gh pr list --head with gh pr view (requires gh repo set-default) - Remove manual remote URL resolution — gh handles it - Default branch detection falls back to upstream/HEAD when origin/HEAD is unset
79 lines
2.5 KiB
TypeScript
79 lines
2.5 KiB
TypeScript
import { describe, expect, test } from "bun:test";
|
|
import { parseDefaultBranch, parseGitHubRepo } from "@oh-my-pi/pi-coding-agent/modes/components/status-line/git-utils";
|
|
|
|
describe("parseGitHubRepo", () => {
|
|
test("parses HTTPS URL", () => {
|
|
expect(parseGitHubRepo("https://github.com/can1357/oh-my-pi.git")).toBe("can1357/oh-my-pi");
|
|
});
|
|
|
|
test("parses HTTPS URL without .git suffix", () => {
|
|
expect(parseGitHubRepo("https://github.com/can1357/oh-my-pi")).toBe("can1357/oh-my-pi");
|
|
});
|
|
|
|
test("parses SSH scp-style URL", () => {
|
|
expect(parseGitHubRepo("git@github.com:loftiskg/oh-my-pi.git")).toBe("loftiskg/oh-my-pi");
|
|
});
|
|
|
|
test("parses SSH scp-style URL without .git suffix", () => {
|
|
expect(parseGitHubRepo("git@github.com:loftiskg/oh-my-pi")).toBe("loftiskg/oh-my-pi");
|
|
});
|
|
|
|
test("parses ssh:// protocol URL", () => {
|
|
expect(parseGitHubRepo("ssh://git@github.com/user/repo.git")).toBe("user/repo");
|
|
});
|
|
|
|
test("returns null for non-GitHub URL", () => {
|
|
expect(parseGitHubRepo("https://gitlab.com/user/repo.git")).toBeNull();
|
|
});
|
|
|
|
test("returns null for empty string", () => {
|
|
expect(parseGitHubRepo("")).toBeNull();
|
|
});
|
|
|
|
test("returns null for malformed URL", () => {
|
|
expect(parseGitHubRepo("not-a-url")).toBeNull();
|
|
});
|
|
|
|
test("handles GitHub Enterprise-style URLs (no match)", () => {
|
|
expect(parseGitHubRepo("https://github.corp.com/org/repo.git")).toBeNull();
|
|
});
|
|
|
|
test("parses HTTPS URL with dots in repo name", () => {
|
|
expect(parseGitHubRepo("https://github.com/org/my.repo.name.git")).toBe("org/my.repo.name");
|
|
});
|
|
|
|
test("parses SSH URL with dots in repo name", () => {
|
|
expect(parseGitHubRepo("git@github.com:org/dotted.repo.git")).toBe("org/dotted.repo");
|
|
});
|
|
|
|
test("parses URL with dots in repo name and no .git suffix", () => {
|
|
expect(parseGitHubRepo("https://github.com/org/my.repo")).toBe("org/my.repo");
|
|
});
|
|
});
|
|
|
|
describe("parseDefaultBranch", () => {
|
|
test("strips origin/ prefix from origin/main", () => {
|
|
expect(parseDefaultBranch("origin/main")).toBe("main");
|
|
});
|
|
|
|
test("strips origin/ prefix from origin/master", () => {
|
|
expect(parseDefaultBranch("origin/master")).toBe("master");
|
|
});
|
|
|
|
test("strips origin/ prefix from origin/develop", () => {
|
|
expect(parseDefaultBranch("origin/develop")).toBe("develop");
|
|
});
|
|
|
|
test("strips upstream/ prefix", () => {
|
|
expect(parseDefaultBranch("upstream/main")).toBe("main");
|
|
});
|
|
|
|
test("returns bare branch name unchanged", () => {
|
|
expect(parseDefaultBranch("main")).toBe("main");
|
|
});
|
|
|
|
test("handles empty string", () => {
|
|
expect(parseDefaultBranch("")).toBe("");
|
|
});
|
|
});
|