From 64d2146ca9eafbefda2dad345487176d82c6577e Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Thu, 27 Nov 2025 11:23:47 +0100 Subject: [PATCH 1/4] ci: Add auto-label GH action --- .github/workflows/pr-labeler.yml | 68 ++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 .github/workflows/pr-labeler.yml diff --git a/.github/workflows/pr-labeler.yml b/.github/workflows/pr-labeler.yml new file mode 100644 index 0000000000..8d1ddfa68b --- /dev/null +++ b/.github/workflows/pr-labeler.yml @@ -0,0 +1,68 @@ +name: Changelog Labeler + +on: + pull_request: + types: [opened, edited] + +permissions: + pull-requests: write + +jobs: + label: + runs-on: ubuntu-latest + steps: + - name: Add changelog label + uses: actions/github-script@v7 + with: + script: | + const title = context.payload.pull_request.title.toLowerCase(); + const prNumber = context.payload.pull_request.number; + + // Get current labels + const { data: currentLabels } = await github.rest.issues.listLabelsOnIssue({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + }); + + // Check if a Changelog label already exists + const hasChangelogLabel = currentLabels.some(label => + label.name.startsWith('Changelog') || label.name === 'skip-changelog' + ); + + if (hasChangelogLabel) { + console.log('PR already has a Changelog label, skipping'); + return; + } + + // Determine which label to apply + let newLabel = null; + + if (title.startsWith('feat')) { + newLabel = 'Changelog: Feature'; + } else if (title.startsWith('fix') || title.startsWith('bugfix')) { + newLabel = 'Changelog: Bugfix'; + } else if (title.includes('deprecate')) { + newLabel = 'Changelog: Deprecation'; + } else if (title.startsWith('docs')) { + newLabel = 'Changelog: Docs'; + } else if (title.startswith('ref') || title.startsWith('test')) { + newLabel = 'Changelog: Internal'; + } else if (title.startsWith('ci') || title.startsWith('build')) { + newLabel = 'skip-changelog'; + } + + // Apply the new label if one was determined + if (newLabel) { + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: prNumber, + labels: [newLabel], + }); + + console.log(`Applied label: ${newLabel}`); + } else { + console.log('No matching label pattern found in PR title, please add manually'); + } + From eb3e95ca4bc7c1a763954da5eb89c3387270ef49 Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Thu, 27 Nov 2025 11:28:33 +0100 Subject: [PATCH 2/4] fixes --- .github/workflows/pr-labeler.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pr-labeler.yml b/.github/workflows/pr-labeler.yml index 8d1ddfa68b..ebbd0a8004 100644 --- a/.github/workflows/pr-labeler.yml +++ b/.github/workflows/pr-labeler.yml @@ -1,4 +1,4 @@ -name: Changelog Labeler +name: Label PR for Changelog on: pull_request: @@ -27,7 +27,7 @@ jobs: // Check if a Changelog label already exists const hasChangelogLabel = currentLabels.some(label => - label.name.startsWith('Changelog') || label.name === 'skip-changelog' + label.name.startsWith('Changelog:') || label.name === 'skip-changelog' ); if (hasChangelogLabel) { @@ -46,7 +46,7 @@ jobs: newLabel = 'Changelog: Deprecation'; } else if (title.startsWith('docs')) { newLabel = 'Changelog: Docs'; - } else if (title.startswith('ref') || title.startsWith('test')) { + } else if (title.startsWith('ref') || title.startsWith('test')) { newLabel = 'Changelog: Internal'; } else if (title.startsWith('ci') || title.startsWith('build')) { newLabel = 'skip-changelog'; From 79f7298954d8f70658a7b1e38aa62e44f998cff2 Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Thu, 27 Nov 2025 11:36:49 +0100 Subject: [PATCH 3/4] Move deprecation up to trigger first --- .github/workflows/pr-labeler.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pr-labeler.yml b/.github/workflows/pr-labeler.yml index ebbd0a8004..5833c094e8 100644 --- a/.github/workflows/pr-labeler.yml +++ b/.github/workflows/pr-labeler.yml @@ -38,12 +38,12 @@ jobs: // Determine which label to apply let newLabel = null; - if (title.startsWith('feat')) { + if (title.includes('deprecate')) { + newLabel = 'Changelog: Deprecation'; + } else if (title.startsWith('feat')) { newLabel = 'Changelog: Feature'; } else if (title.startsWith('fix') || title.startsWith('bugfix')) { newLabel = 'Changelog: Bugfix'; - } else if (title.includes('deprecate')) { - newLabel = 'Changelog: Deprecation'; } else if (title.startsWith('docs')) { newLabel = 'Changelog: Docs'; } else if (title.startsWith('ref') || title.startsWith('test')) { From 0f1fffa1d6fea6201a4438575fd3d662c08bca7e Mon Sep 17 00:00:00 2001 From: Ivana Kellyer Date: Thu, 27 Nov 2025 11:40:53 +0100 Subject: [PATCH 4/4] Add notes --- .github/release.yml | 5 +++++ .github/workflows/pr-labeler.yml | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/.github/release.yml b/.github/release.yml index 21e093324e..72e8208ad1 100644 --- a/.github/release.yml +++ b/.github/release.yml @@ -1,3 +1,8 @@ +# This configuration is used by Craft to categorize changelog entries based on +# PR labels. To avoid some manual work, there is a PR labeling GitHub action in +# .github/workflows/pr-labeler.yml that adds a changelog label to PRs based on +# the title. + changelog: exclude: labels: diff --git a/.github/workflows/pr-labeler.yml b/.github/workflows/pr-labeler.yml index 5833c094e8..c489de30d4 100644 --- a/.github/workflows/pr-labeler.yml +++ b/.github/workflows/pr-labeler.yml @@ -1,3 +1,7 @@ +# This action adds changelog labels to PRs that are then used by the release +# notes generator in Craft. The configuration for which labels map to what +# changelog categories can be found in .github/release.yml. + name: Label PR for Changelog on: