dograh/.github/workflows/pr-conventional-labeler.yml
2026-06-02 13:42:55 +05:30

54 lines
2 KiB
YAML

name: PR Conventional Labeler
# Labels each PR with its conventional-commit type (feat, fix, docs, perf,
# refactor, chore) derived from the PR title. These labels drive the changelog
# categories in .github/release.yml when release-please generates notes.
# chore is labeled but excluded from the changelog (see .github/release.yml),
# preserving the previous "chore hidden" behavior.
on:
pull_request_target:
types: [opened, edited, reopened, ready_for_review]
permissions:
contents: read
pull-requests: write
jobs:
label:
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v7
with:
script: |
// Conventional-commit types we manage as labels.
const managedLabels = ['feat', 'fix', 'docs', 'perf', 'refactor', 'chore'];
const pr = context.payload.pull_request;
const title = pr.title || '';
// Matches: feat:, fix(scope):, perf!:, refactor(api)!: ...
const match = title.match(/^([a-zA-Z]+)(\([^)]*\))?!?:/);
const type = match ? match[1].toLowerCase() : null;
const target = managedLabels.includes(type) ? type : null;
const { owner, repo } = context.repo;
const issue_number = pr.number;
const current = pr.labels.map(l => l.name);
// Remove any managed label that no longer matches the title
// (e.g. PR retitled from feat: to fix:).
for (const label of current) {
if (managedLabels.includes(label) && label !== target) {
await github.rest.issues
.removeLabel({ owner, repo, issue_number, name: label })
.catch(() => {});
}
}
// Apply the matching label if not already present.
if (target && !current.includes(target)) {
await github.rest.issues.addLabels({
owner, repo, issue_number, labels: [target],
});
}