feat: Update PR label from description template (#27)

* feat: update PR label from template

- Search the PR text for checkboxes marked in the format [x] release:...``
- Only accepts these labels (the same as the pull_request_template.md template): release:major, release:feature, release:patterns, release:api, release:data, release:privacy, release:fix, release:docs, release:infra, release:security

- The job fails if more than one release:* is checked
 - Removes other old release:* from the PR and adds only the chosen one (keeps “exactly one” in sync)

* fix(ci): run auto-labeler on pull_request_target

---------

Co-authored-by: bruno cesar <brunoclz@brunos-MacBook-Pro.local>
This commit is contained in:
AbraaoAlves
2026-03-01 22:19:06 -03:00
committed by GitHub
parent e2c564dceb
commit 2c2b32d0c5

96
.github/workflows/auto-label.yml vendored Normal file
View File

@@ -0,0 +1,96 @@
name: Auto Labeler via PR Description
on:
# pull_request_target is required to write labels on PRs from forks.
pull_request_target:
types: [opened, edited, synchronize, reopened, ready_for_review]
jobs:
apply-labels:
runs-on: ubuntu-latest
permissions:
pull-requests: read
issues: write # PR labels are managed via the Issues API.
steps:
- name: Read description and apply labels
uses: actions/github-script@v7
with:
script: |
// Only apply labels that exist in .github/pull_request_template.md
// Change type (choose one release label from taxonomy):
const allowedReleaseLabels = new Set([
'release:major',
'release:feature',
'release:patterns',
'release:api',
'release:data',
'release:privacy',
'release:fix',
'release:docs',
'release:infra',
'release:security',
]);
const body = context.payload.pull_request.body || '';
if (!body.trim()) return;
// Matches: - [x] `release:major`
const checkedReleaseLabelRegex = /\[x\]\s*`(release:[^`]+)`/gi;
const selected = [];
let match;
while ((match = checkedReleaseLabelRegex.exec(body)) !== null) {
const label = (match[1] || '').trim();
if (allowedReleaseLabels.has(label)) selected.push(label);
}
const uniqueSelected = [...new Set(selected)];
if (uniqueSelected.length === 0) {
console.log('No release label selected in PR template; skipping.');
return;
}
if (uniqueSelected.length > 1) {
throw new Error(
`Multiple release labels selected: ${uniqueSelected.join(', ')}. Select exactly one.`
);
}
const chosen = uniqueSelected[0];
const owner = context.repo.owner;
const repo = context.repo.repo;
const issue_number = context.issue.number;
// Sync: remove other release:* labels from the allowed set, then add the chosen one.
const { data: existing } = await github.rest.issues.listLabelsOnIssue({
owner,
repo,
issue_number,
});
const existingReleaseLabels = existing
.map(l => l.name)
.filter(name => allowedReleaseLabels.has(name));
const toRemove = existingReleaseLabels.filter(name => name !== chosen);
for (const name of toRemove) {
await github.rest.issues.removeLabel({
owner,
repo,
issue_number,
name,
});
console.log(`Removed label: ${name}`);
}
if (!existingReleaseLabels.includes(chosen)) {
await github.rest.issues.addLabels({
owner,
repo,
issue_number,
labels: [chosen],
});
console.log(`Added label: ${chosen}`);
} else {
console.log(`Label already present: ${chosen}`);
}