Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion .github/scripts/update-changelog.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,20 @@ const TYPE_TO_PREFIX = {
refactor: "Refactored",
};

/**
* Maps changelog prefixes to verb forms that should be removed from title starts
* to avoid duplicated wording like "Added added ...".
*/
const PREFIX_TO_LEADING_VERB_REGEX = {
added: /^(add|adds|added|adding)\b[\s:-]*/i,
changed: /^(change|changes|changed|changing)\b[\s:-]*/i,
deprecated: /^(deprecate|deprecates|deprecated|deprecating)\b[\s:-]*/i,
fixed: /^(fix|fixes|fixed|fixing)\b[\s:-]*/i,
refactored: /^(refactor|refactors|refactored|refactoring)\b[\s:-]*/i,
removed: /^(remove|removes|removed|removing)\b[\s:-]*/i,
reverted: /^(revert|reverts|reverted|reverting)\b[\s:-]*/i,
};

/**
* Indentation used for PR description lines nested under a changelog list item 2 spaces.
*/
Expand Down Expand Up @@ -296,7 +310,26 @@ function buildEntry(
prBody,
) {
const prefix = TYPE_TO_PREFIX[type] ?? section;
return `- ${prefix} ${cleanedTitle} ([#${prNumber}](${prUrl})) by @${prAuthor}${formatPRDescription(prBody)}\n<!-- end -->`;
const dedupedTitle = removeLeadingDuplicateVerb(prefix, cleanedTitle);
const titlePart = dedupedTitle ? ` ${dedupedTitle}` : ` ${cleanedTitle.trim()}`;
return `- ${prefix}${titlePart} ([#${prNumber}](${prUrl})) by @${prAuthor}${formatPRDescription(prBody)}\n<!-- end -->`;
}

/**
* Removes duplicated leading verbs based on the resolved changelog prefix.
* Example: prefix "Added" + title "added support for x" => "support for x"
* @param {string} prefix - Resolved changelog entry prefix
* @param {string} title - Cleaned PR title
* @returns {string} - Title without duplicated leading verb
*/
function removeLeadingDuplicateVerb(prefix, title) {
const trimmedTitle = title.trim();
if (!trimmedTitle) return "";

const pattern = PREFIX_TO_LEADING_VERB_REGEX[prefix.toLowerCase()];
if (!pattern) return trimmedTitle;

return trimmedTitle.replace(pattern, "").trimStart();
}

/**
Expand Down