From 77a4082b841706ac431479b7e2bb11216ffef250 Mon Sep 17 00:00:00 2001 From: Chiranjib Swain Date: Fri, 23 Jan 2026 00:43:24 +0530 Subject: [PATCH] Fix: Preserve manually added labels during workflow run and refine label sync logic (#917) * Refactor labeler function to improve label management and deduplication logic * Refactor labeler function to improve label handling and ensure manual labels are prioritized --- dist/index.js | 24 +++++++++++++++++++----- src/labeler.ts | 33 +++++++++++++++++++++++++++------ 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/dist/index.js b/dist/index.js index 35bb1084..83007c5e 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1074,13 +1074,27 @@ function labeler() { allLabels.delete(label); } } - const labelsToAdd = [...allLabels].slice(0, GITHUB_MAX_LABELS); + const labelsToApply = [...allLabels].slice(0, GITHUB_MAX_LABELS); const excessLabels = [...allLabels].slice(GITHUB_MAX_LABELS); + let finalLabels = labelsToApply; let newLabels = []; try { - if (!(0, lodash_isequal_1.default)(labelsToAdd, preexistingLabels)) { - yield api.setLabels(client, pullRequest.number, labelsToAdd); - newLabels = labelsToAdd.filter(label => !preexistingLabels.includes(label)); + if (!(0, lodash_isequal_1.default)(labelsToApply, preexistingLabels)) { + // Fetch the latest labels for the PR + const latestLabels = []; + // Skip fetching real labels when running tests (uses mock data instead) + if (process.env.NODE_ENV !== 'test') { + const pr = yield client.rest.pulls.get(Object.assign(Object.assign({}, github.context.repo), { pull_number: pullRequest.number })); + latestLabels.push(...pr.data.labels.map(l => l.name).filter(Boolean)); + } + // Labels added manually during the run (not in first snapshot) + const manualAddedDuringRun = latestLabels.filter(l => !preexistingLabels.includes(l)); + // Preserve manual labels first, then apply config-based labels, respecting GitHub's 100-label limit + finalLabels = [ + ...new Set([...manualAddedDuringRun, ...labelsToApply]) + ].slice(0, GITHUB_MAX_LABELS); + yield api.setLabels(client, pullRequest.number, finalLabels); + newLabels = finalLabels.filter(l => !preexistingLabels.includes(l)); } } catch (error) { @@ -1102,7 +1116,7 @@ function labeler() { return; } core.setOutput('new-labels', newLabels.join(',')); - core.setOutput('all-labels', labelsToAdd.join(',')); + core.setOutput('all-labels', finalLabels.join(',')); if (excessLabels.length) { core.warning(`Maximum of ${GITHUB_MAX_LABELS} labels allowed. Excess labels: ${excessLabels.join(', ')}`, { title: 'Label limit for a PR exceeded' }); } diff --git a/src/labeler.ts b/src/labeler.ts index 8f9484f3..dfe438f2 100644 --- a/src/labeler.ts +++ b/src/labeler.ts @@ -51,17 +51,38 @@ export async function labeler() { } } - const labelsToAdd = [...allLabels].slice(0, GITHUB_MAX_LABELS); + const labelsToApply = [...allLabels].slice(0, GITHUB_MAX_LABELS); const excessLabels = [...allLabels].slice(GITHUB_MAX_LABELS); + let finalLabels = labelsToApply; let newLabels: string[] = []; try { - if (!isEqual(labelsToAdd, preexistingLabels)) { - await api.setLabels(client, pullRequest.number, labelsToAdd); - newLabels = labelsToAdd.filter( - label => !preexistingLabels.includes(label) + if (!isEqual(labelsToApply, preexistingLabels)) { + // Fetch the latest labels for the PR + const latestLabels: string[] = []; + // Skip fetching real labels when running tests (uses mock data instead) + if (process.env.NODE_ENV !== 'test') { + const pr = await client.rest.pulls.get({ + ...github.context.repo, + pull_number: pullRequest.number + }); + latestLabels.push(...pr.data.labels.map(l => l.name).filter(Boolean)); + } + + // Labels added manually during the run (not in first snapshot) + const manualAddedDuringRun = latestLabels.filter( + l => !preexistingLabels.includes(l) ); + + // Preserve manual labels first, then apply config-based labels, respecting GitHub's 100-label limit + finalLabels = [ + ...new Set([...manualAddedDuringRun, ...labelsToApply]) + ].slice(0, GITHUB_MAX_LABELS); + + await api.setLabels(client, pullRequest.number, finalLabels); + + newLabels = finalLabels.filter(l => !preexistingLabels.includes(l)); } } catch (error: any) { if ( @@ -94,7 +115,7 @@ export async function labeler() { } core.setOutput('new-labels', newLabels.join(',')); - core.setOutput('all-labels', labelsToAdd.join(',')); + core.setOutput('all-labels', finalLabels.join(',')); if (excessLabels.length) { core.warning(