fix: encode branch names in GitHub links (#1713)

* fix: encode branch names in GitHub links

* style: format branch URL helper
This commit is contained in:
Muhammad Abdullah khan
2026-08-25 11:02:49 -07:00
committed by GitHub
parent 8ef9699156
commit 76ac41a83e
5 changed files with 21 additions and 7 deletions
+2 -1
View File
@@ -16,6 +16,7 @@ import type { ParsedGitHubContext } from "../github/context";
import { GITHUB_SERVER_URL } from "../github/api/config";
import { checkAndCommitOrDeleteBranch } from "../github/operations/branch-cleanup";
import { updateClaudeComment } from "../github/operations/comments/update-claude-comment";
import { encodeBranchNameForUrl } from "../github/operations/comments/common";
export type UpdateCommentLinkParams = {
commentId: number;
@@ -159,7 +160,7 @@ export async function updateCommentLink(
const prBody = encodeURIComponent(
`This PR addresses ${entityType.toLowerCase()} #${context.entityNumber}\n\nGenerated with [Claude Code](https://claude.ai/code)`,
);
const prUrl = `${serverUrl}/${owner}/${repo}/compare/${baseBranch}...${claudeBranch}?quick_pull=1&title=${prTitle}&body=${prBody}`;
const prUrl = `${serverUrl}/${owner}/${repo}/compare/${encodeBranchNameForUrl(baseBranch)}...${encodeBranchNameForUrl(claudeBranch)}?quick_pull=1&title=${prTitle}&body=${prBody}`;
prLink = `\n[Create a PR](${prUrl})`;
}
} catch (error) {
+5 -4
View File
@@ -1,5 +1,6 @@
import type { Octokits } from "../api/client";
import { GITHUB_SERVER_URL } from "../api/config";
import { encodeBranchNameForUrl } from "./comments/common";
import { $ } from "bun";
export async function checkAndCommitOrDeleteBranch(
@@ -106,7 +107,7 @@ export async function checkAndCommitOrDeleteBranch(
);
// Set branch link since we now have commits
const branchUrl = `${GITHUB_SERVER_URL}/${owner}/${repo}/tree/${claudeBranch}`;
const branchUrl = `${GITHUB_SERVER_URL}/${owner}/${repo}/tree/${encodeBranchNameForUrl(claudeBranch)}`;
branchLink = `\n[View branch](${branchUrl})`;
} else {
console.log(
@@ -117,7 +118,7 @@ export async function checkAndCommitOrDeleteBranch(
} catch (gitError) {
console.error("Error checking/committing changes:", gitError);
// If we can't check git status, assume the branch might have changes
const branchUrl = `${GITHUB_SERVER_URL}/${owner}/${repo}/tree/${claudeBranch}`;
const branchUrl = `${GITHUB_SERVER_URL}/${owner}/${repo}/tree/${encodeBranchNameForUrl(claudeBranch)}`;
branchLink = `\n[View branch](${branchUrl})`;
}
} else {
@@ -128,13 +129,13 @@ export async function checkAndCommitOrDeleteBranch(
}
} else {
// Only add branch link if there are commits
const branchUrl = `${GITHUB_SERVER_URL}/${owner}/${repo}/tree/${claudeBranch}`;
const branchUrl = `${GITHUB_SERVER_URL}/${owner}/${repo}/tree/${encodeBranchNameForUrl(claudeBranch)}`;
branchLink = `\n[View branch](${branchUrl})`;
}
} catch (error) {
console.error("Error comparing commits on Claude branch:", error);
// If we can't compare but the branch exists remotely, include the branch link
const branchUrl = `${GITHUB_SERVER_URL}/${owner}/${repo}/tree/${claudeBranch}`;
const branchUrl = `${GITHUB_SERVER_URL}/${owner}/${repo}/tree/${encodeBranchNameForUrl(claudeBranch)}`;
branchLink = `\n[View branch](${branchUrl})`;
}
}
+2 -1
View File
@@ -1,5 +1,6 @@
import { GITHUB_SERVER_URL } from "../api/config";
import { redactSecrets } from "../utils/sanitizer";
import { encodeBranchNameForUrl } from "./comments/common";
export type ExecutionDetails = {
total_cost_usd?: number;
@@ -161,7 +162,7 @@ export function updateCommentBody(input: CommentUpdateInput): string {
// Extract owner/repo from jobUrl
const repoMatch = jobUrl.match(/github\.com\/([^\/]+)\/([^\/]+)\//);
if (repoMatch) {
branchUrl = `${GITHUB_SERVER_URL}/${repoMatch[1]}/${repoMatch[2]}/tree/${finalBranchName}`;
branchUrl = `${GITHUB_SERVER_URL}/${repoMatch[1]}/${repoMatch[2]}/tree/${encodeBranchNameForUrl(finalBranchName)}`;
}
}
+6 -1
View File
@@ -12,12 +12,17 @@ export function createJobRunLink(
return `[View job run](${jobRunUrl})`;
}
/** Encode Git-ref path segments without turning `/` into `%2F`. */
export function encodeBranchNameForUrl(branchName: string): string {
return branchName.split("/").map(encodeURIComponent).join("/");
}
export function createBranchLink(
owner: string,
repo: string,
branchName: string,
): string {
const branchUrl = `${GITHUB_SERVER_URL}/${owner}/${repo}/tree/${branchName}`;
const branchUrl = `${GITHUB_SERVER_URL}/${owner}/${repo}/tree/${encodeBranchNameForUrl(branchName)}`;
return `\n[View branch](${branchUrl})`;
}
+6
View File
@@ -36,6 +36,12 @@ describe("comments/common", () => {
);
});
test("encodes URL-significant characters in a branch name", () => {
expect(createBranchLink("o", "r", "claude/fix#123")).toBe(
`\n[View branch](${GITHUB_SERVER_URL}/o/r/tree/claude/fix%23123)`,
);
});
test("prefixes the link with a newline so it renders on its own line", () => {
expect(createBranchLink("o", "r", "main").startsWith("\n")).toBe(true);
});