Skip to content

Commit d56e66f

Browse files
chore: wip
1 parent 09161b1 commit d56e66f

File tree

2 files changed

+75
-3
lines changed

2 files changed

+75
-3
lines changed

src/pr/pr-generator.ts

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,9 +1022,13 @@ export class PullRequestGenerator {
10221022
// Sanitize @mentions to avoid pinging real users in PRs
10231023
cleaned = this.sanitizeMentions(cleaned)
10241024

1025-
// Limit to reasonable length for PR body
1026-
if (cleaned.length > 1000) {
1027-
cleaned = `${cleaned.substring(0, 1000)}...\n\n*[View full release notes]*`
1025+
// Sanitize GitHub issue/PR references to prevent spam notifications
1026+
cleaned = this.sanitizeGitHubReferences(cleaned)
1027+
1028+
// Limit to reasonable length for PR body (configurable, default: 1000)
1029+
const maxLength = this.config?.releaseNotes?.maxBodyLength ?? 1000
1030+
if (cleaned.length > maxLength) {
1031+
cleaned = `${cleaned.substring(0, maxLength)}...\n\n*[View full release notes]*`
10281032
}
10291033

10301034
return cleaned
@@ -1070,6 +1074,60 @@ export class PullRequestGenerator {
10701074
return protectedText
10711075
}
10721076

1077+
/**
1078+
* Sanitize GitHub issue/PR references to prevent spam notifications.
1079+
* Converts references like #123 and GitHub URLs into non-linking text.
1080+
* Examples:
1081+
* #123 -> `#123`
1082+
* fixes #456 -> fixes `#456`
1083+
* https://github.com/org/repo/pull/123 -> `org/repo#123`
1084+
* https://github.com/org/repo/issues/456 -> `org/repo#456`
1085+
*/
1086+
private sanitizeGitHubReferences(text: string): string {
1087+
// Check if sanitization is enabled (default: true)
1088+
if (this.config?.releaseNotes?.sanitizeReferences === false) {
1089+
return text
1090+
}
1091+
1092+
// Protect fenced code blocks and inline code by temporarily replacing them
1093+
const fences: string[] = []
1094+
const inlineCode: string[] = []
1095+
1096+
// Replace fenced code blocks ```...``` with placeholders
1097+
let protectedText = text.replace(/```[\s\S]*?```/g, (match) => {
1098+
fences.push(match)
1099+
return `__FENCE_PLACEHOLDER_${fences.length - 1}__`
1100+
})
1101+
1102+
// Replace inline code `...` with placeholders
1103+
protectedText = protectedText.replace(/`[^`\n]+`/g, (match) => {
1104+
inlineCode.push(match)
1105+
return `__INLINE_CODE_PLACEHOLDER_${inlineCode.length - 1}__`
1106+
})
1107+
1108+
// Replace full GitHub issue/PR URLs with non-linking format
1109+
// https://github.com/org/repo/pull/123 -> `org/repo#123`
1110+
// https://github.com/org/repo/issues/456 -> `org/repo#456`
1111+
protectedText = protectedText.replace(
1112+
/https?:\/\/github\.com\/([^/]+)\/([^/]+)\/(?:pull|issues)\/(\d+)/g,
1113+
(_match, owner: string, repo: string, num: string) => `\`${owner}/${repo}#${num}\``,
1114+
)
1115+
1116+
// Replace standalone issue/PR references #123 with backtick-wrapped version
1117+
// This prevents GitHub from creating links/notifications
1118+
// Negative lookbehind: don't match if preceded by ` or alphanumeric (part of URL or already wrapped)
1119+
// Negative lookahead: don't match if followed by alphanumeric
1120+
protectedText = protectedText.replace(/(?<![`\w])#(\d+)(?!\d)/g, '`#$1`')
1121+
1122+
// Restore inline code placeholders
1123+
protectedText = protectedText.replace(/__INLINE_CODE_PLACEHOLDER_(\d+)__/g, (_m, i: string) => inlineCode[Number(i)])
1124+
1125+
// Restore fenced code placeholders
1126+
protectedText = protectedText.replace(/__FENCE_PLACEHOLDER_(\d+)__/g, (_m, i: string) => fences[Number(i)])
1127+
1128+
return protectedText
1129+
}
1130+
10731131
/**
10741132
* Generate custom PR templates
10751133
*/

src/types.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,20 @@ export interface BuddyBotConfig {
7171
labels?: string[]
7272
}
7373

74+
/** Release notes configuration */
75+
releaseNotes?: {
76+
/** Enable release notes in PRs (default: true) */
77+
enabled?: boolean
78+
/** Sanitize GitHub references (#123, issue/PR URLs) to prevent spam notifications (default: true) */
79+
sanitizeReferences?: boolean
80+
/** Maximum number of releases to show per package (default: 3) */
81+
maxReleases?: number
82+
/** Maximum character length per release body (default: 1000) */
83+
maxBodyLength?: number
84+
/** Include compare links between versions (default: true) */
85+
includeCompareLinks?: boolean
86+
}
87+
7488
/** Workflow generation settings */
7589
workflows?: {
7690
/** Enable workflow generation */

0 commit comments

Comments
 (0)