Skip to content
Merged
Show file tree
Hide file tree
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
23 changes: 22 additions & 1 deletion .github/scripts/helpers/api.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,27 @@ async function postComment(botContext, body) {
}
}

async function updatePullRequest(botContext, title) {
try {
requireNonEmptyString(title, 'title');

await botContext.github.rest.pulls.update({
owner: botContext.owner,
repo: botContext.repo,
pull_number: botContext.number,
title,
});

getLogger().log(`Updated PR #${botContext.number} title`);
return { success: true };
} catch (error) {
getLogger().error(
`Could not update PR #${botContext.number} title: ${error.message}`,
);
return { success: false, error: error.message };
}
}

function hasLabel(issueOrPr, labelName) {
if (!issueOrPr?.labels?.length) return false;
return issueOrPr.labels.some((label) => {
Expand Down Expand Up @@ -467,7 +488,7 @@ async function hasNeedsReviewPR(github, owner, repo, username, issueNumber) {
}

module.exports = {
buildBotContext, addLabels, removeLabel, addAssignees, removeAssignees, postComment, hasLabel, getLabelsByPrefix,
buildBotContext, addLabels, removeLabel, addAssignees, removeAssignees, postComment, updatePullRequest, hasLabel, getLabelsByPrefix,
swapLabels, getBotComment, postOrUpdateComment, fetchPRCommits, fetchOpenPRs, fetchIssue, fetchClosingIssueNumbers,
fetchLatestMilestone, setMilestone, swapStatusLabel, runAllChecksAndComment, resolveLinkedIssue, acknowledgeComment,
fetchComments, fetchIssueEvents, closeItem, getHighestIssueSkillLevel, countIssuesByAssignee, listAssignedIssues, hasNeedsReviewPR,
Expand Down
38 changes: 36 additions & 2 deletions .github/scripts/pr-labeler.cjs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// SPDX-License-Identifier: Apache-2.0

const { buildBotContext, addLabels } = require('./helpers/api.cjs');
const { buildBotContext, addLabels, updatePullRequest } = require('./helpers/api.cjs');
const { loadAutomationConfig } = require('./helpers/config-loader.cjs');

function detectType(title) {
if (!title || typeof title !== 'string') return null;
const upper = title.toUpperCase();

const kdm = upper.match(/\[KDM-\d+-(FIX|FEAT|REFACTOR)/);
const kdm = upper.match(/^\[KDM-[A-Z0-9-]+-(FIX|FEAT|REFACTOR)-\d+\]/);
if (kdm) {
const map = { FIX: 'bugFix', FEAT: 'feature', REFACTOR: 'refactor' };
return map[kdm[1]] || null;
Expand Down Expand Up @@ -81,6 +81,27 @@ function determineComplexity(score, complexityConfig) {
return 'complex';
}

function buildPRIdentityTitle(title, module, typeKey, prNumber) {
if (!module || !typeKey || !prNumber) return null;

const typeMap = {
bugFix: 'FIX',
feature: 'FEAT',
refactor: 'REFACTOR',
};

const type = typeMap[typeKey];
if (!type) return null;

const prefix = `[KDM-${module.toUpperCase()}-${type}-${prNumber}]`;

const cleanedTitle = title
.replace(/^\[KDM-(?:[A-Z0-9-]+-(?:FIX|FEAT|REFACTOR)-\d+|\d+-(?:FIX|FEAT|REFACTOR))\]\s*/i, '')
.trim();

return `${prefix} ${cleanedTitle}`.trim();
}

async function labelPR({ github, context }) {
let botContext;
try {
Expand Down Expand Up @@ -162,6 +183,19 @@ async function labelPR({ github, context }) {
}
}

const prModule = matchedModules[0];
const newTitle = buildPRIdentityTitle(title, prModule, typeKey, number);

if (newTitle && newTitle !== title) {
console.log(`[pr-labeler] Updating PR title: "${newTitle}"`);

const titleResult = await updatePullRequest(botContext, newTitle);

if (!titleResult.success) {
console.log(`[pr-labeler] Failed to update PR title: ${titleResult.error}`);
}
}

if (labelsToAdd.length) {
console.log(`[pr-labeler] Adding labels: ${labelsToAdd.join(', ')}`);
const result = await addLabels(botContext, labelsToAdd);
Expand Down
Loading