From f4380aeeda886186806b8e6744b7b7212e6abda9 Mon Sep 17 00:00:00 2001 From: Xianpeng Shen <3353385+shenxianpeng@users.noreply.github.com> Date: Fri, 16 Oct 2026 18:37:45 +0000 Subject: [PATCH 1/4] chore: label Dependabot PRs with chore and their semver bump The shared PR labeler now adds `chore` and `major`/`minor`/`patch` (from dependabot/fetch-metadata) to Dependabot PRs, creating a label first if the repository lacks it. The release-drafter "Dependency updates" category moves before "Maintenance" and is exclusive, so these PRs are not listed twice. --- .github/release-drafter.yml | 15 ++++++++----- .github/workflows/pr-labeler.yml | 38 ++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index 3303e9b..9bc65dc 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -40,6 +40,15 @@ categories: when: labels: - documentation + # Default label used by Dependabot. Listed before "Maintenance" and + # exclusive, so Dependabot PRs (which also get the `chore` label) are + # listed here only. + - title: 📦 Dependency updates + exclusive: true + when: + labels: + - dependencies + collapse-after: 15 - title: 👻 Maintenance when: labels: @@ -52,12 +61,6 @@ categories: - test - tests - title: ✍ Other changes - # Default label used by Dependabot - - title: 📦 Dependency updates - when: - labels: - - dependencies - collapse-after: 15 # Dropped from the release notes before anything else runs - type: pre-exclude when: diff --git a/.github/workflows/pr-labeler.yml b/.github/workflows/pr-labeler.yml index a62ec7d..4a47451 100644 --- a/.github/workflows/pr-labeler.yml +++ b/.github/workflows/pr-labeler.yml @@ -17,3 +17,41 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: config-name: github:cpp-linter/.github:/.github/release-drafter.yml + + # Dependabot PRs get `chore` plus the semver label of the update + # (major/minor/patch), which release-drafter uses for the changelog + # section and the next version. + label_dependabot_pr: + if: github.event.pull_request.user.login == 'dependabot[bot]' + permissions: + pull-requests: write + contents: read + runs-on: ubuntu-latest + steps: + - name: Fetch Dependabot metadata + id: metadata + uses: dependabot/fetch-metadata@25dd0e34f4fe68f24cc83900b1fe3fe149efef98 # v3.1.0 + - name: Add labels + env: + GH_TOKEN: ${{ github.token }} + GH_REPO: ${{ github.repository }} + PR_NUMBER: ${{ github.event.pull_request.number }} + UPDATE_TYPE: ${{ steps.metadata.outputs.update-type }} + run: | + labels=(chore) + case "${UPDATE_TYPE}" in + version-update:semver-major) labels+=(major) ;; + version-update:semver-minor) labels+=(minor) ;; + version-update:semver-patch) labels+=(patch) ;; + esac + existing=$(gh label list --limit 500 --json name --jq '.[].name') + for label in "${labels[@]}"; do + if ! grep -qxF "${label}" <<< "${existing}"; then + case "${label}" in + chore) description="Maintenance work" ;; + *) description="A ${label} version bump" ;; + esac + gh label create "${label}" --color E99695 --description "${description}" + fi + done + gh pr edit "${PR_NUMBER}" --add-label "$(IFS=,; echo "${labels[*]}")" From e59e3b588ccb3611a80e667d11d5c5828bd7c56a Mon Sep 17 00:00:00 2001 From: Xianpeng Shen <3353385+shenxianpeng@users.noreply.github.com> Date: Fri, 16 Oct 2026 18:42:20 +0000 Subject: [PATCH 2/4] chore: drop version bump labels from Dependabot PRs instead Dependabot itself adds major/minor/patch when the repository has those labels, and release-drafter then bumps the next version by that much. Remove those labels (and chore) from Dependabot PRs in the shared PR labeler, and keep the release-drafter config as it is on main. --- .github/release-drafter.yml | 15 +++++-------- .github/workflows/pr-labeler.yml | 38 ++++++++++---------------------- 2 files changed, 18 insertions(+), 35 deletions(-) diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index 9bc65dc..3303e9b 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -40,15 +40,6 @@ categories: when: labels: - documentation - # Default label used by Dependabot. Listed before "Maintenance" and - # exclusive, so Dependabot PRs (which also get the `chore` label) are - # listed here only. - - title: 📦 Dependency updates - exclusive: true - when: - labels: - - dependencies - collapse-after: 15 - title: 👻 Maintenance when: labels: @@ -61,6 +52,12 @@ categories: - test - tests - title: ✍ Other changes + # Default label used by Dependabot + - title: 📦 Dependency updates + when: + labels: + - dependencies + collapse-after: 15 # Dropped from the release notes before anything else runs - type: pre-exclude when: diff --git a/.github/workflows/pr-labeler.yml b/.github/workflows/pr-labeler.yml index 4a47451..034a99c 100644 --- a/.github/workflows/pr-labeler.yml +++ b/.github/workflows/pr-labeler.yml @@ -18,40 +18,26 @@ jobs: with: config-name: github:cpp-linter/.github:/.github/release-drafter.yml - # Dependabot PRs get `chore` plus the semver label of the update - # (major/minor/patch), which release-drafter uses for the changelog - # section and the next version. - label_dependabot_pr: + # Dependabot adds a `major`/`minor`/`patch` label by itself whenever the + # repository has such labels, and release-drafter would then bump the next + # version by that much. A dependency update should not decide the project's + # version, so drop those labels (and `chore`) from Dependabot PRs; they stay + # under "Dependency updates" through the `dependencies` label. + unlabel_dependabot_pr: if: github.event.pull_request.user.login == 'dependabot[bot]' permissions: pull-requests: write contents: read runs-on: ubuntu-latest steps: - - name: Fetch Dependabot metadata - id: metadata - uses: dependabot/fetch-metadata@25dd0e34f4fe68f24cc83900b1fe3fe149efef98 # v3.1.0 - - name: Add labels + - name: Remove version bump labels env: GH_TOKEN: ${{ github.token }} GH_REPO: ${{ github.repository }} PR_NUMBER: ${{ github.event.pull_request.number }} - UPDATE_TYPE: ${{ steps.metadata.outputs.update-type }} run: | - labels=(chore) - case "${UPDATE_TYPE}" in - version-update:semver-major) labels+=(major) ;; - version-update:semver-minor) labels+=(minor) ;; - version-update:semver-patch) labels+=(patch) ;; - esac - existing=$(gh label list --limit 500 --json name --jq '.[].name') - for label in "${labels[@]}"; do - if ! grep -qxF "${label}" <<< "${existing}"; then - case "${label}" in - chore) description="Maintenance work" ;; - *) description="A ${label} version bump" ;; - esac - gh label create "${label}" --color E99695 --description "${description}" - fi - done - gh pr edit "${PR_NUMBER}" --add-label "$(IFS=,; echo "${labels[*]}")" + remove=$(gh pr view "${PR_NUMBER}" --json labels --jq \ + '[.labels[].name | select(. == "major" or . == "minor" or . == "patch" or . == "chore")] | join(",")') + if [ -n "${remove}" ]; then + gh pr edit "${PR_NUMBER}" --remove-label "${remove}" + fi From 011f0dd38a742eb7111358d172cffc4eb66bba5f Mon Sep 17 00:00:00 2001 From: Xianpeng Shen <3353385+shenxianpeng@users.noreply.github.com> Date: Fri, 16 Oct 2026 20:32:46 +0000 Subject: [PATCH 3/4] chore: resolve the next version from conventional PR titles Replace the Dependabot unlabel job with version resolution from the PR title: `type!:` bumps major, `feat:` bumps minor, anything else patch. Manual overrides use `semver:major`/`semver:minor`/`semver:patch` labels, which Dependabot does not recognize, so once the old `major`/`minor`/`patch` labels are renamed Dependabot stops adding them. --- .github/release-drafter.yml | 17 +++++++++++++---- .github/workflows/pr-labeler.yml | 24 ------------------------ 2 files changed, 13 insertions(+), 28 deletions(-) diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index 3303e9b..fa279c8 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -66,19 +66,28 @@ categories: - skip-changelog - invalid # https://github.com/release-drafter/release-drafter?tab=readme-ov-file#version-resolver + # The next version comes from the conventional PR title: `type!:` is a + # breaking change (major), `feat:` is minor, anything else is patch. + # The `semver:*` labels override it by hand. They are deliberately not + # named `major`/`minor`/`patch`, because Dependabot adds labels with those + # exact names to its PRs whenever they exist in the repository. - type: version-resolver semver-increment: major when: - label: major + - label: semver:major + - conventional: + breaking: true - type: version-resolver semver-increment: minor when: - label: minor + - label: semver:minor + - conventional: + type: feat - type: version-resolver semver-increment: patch when: - label: patch - # Fallback when no version label is present + label: semver:patch + # Fallback when nothing above matches - type: version-resolver semver-increment: patch diff --git a/.github/workflows/pr-labeler.yml b/.github/workflows/pr-labeler.yml index 034a99c..a62ec7d 100644 --- a/.github/workflows/pr-labeler.yml +++ b/.github/workflows/pr-labeler.yml @@ -17,27 +17,3 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: config-name: github:cpp-linter/.github:/.github/release-drafter.yml - - # Dependabot adds a `major`/`minor`/`patch` label by itself whenever the - # repository has such labels, and release-drafter would then bump the next - # version by that much. A dependency update should not decide the project's - # version, so drop those labels (and `chore`) from Dependabot PRs; they stay - # under "Dependency updates" through the `dependencies` label. - unlabel_dependabot_pr: - if: github.event.pull_request.user.login == 'dependabot[bot]' - permissions: - pull-requests: write - contents: read - runs-on: ubuntu-latest - steps: - - name: Remove version bump labels - env: - GH_TOKEN: ${{ github.token }} - GH_REPO: ${{ github.repository }} - PR_NUMBER: ${{ github.event.pull_request.number }} - run: | - remove=$(gh pr view "${PR_NUMBER}" --json labels --jq \ - '[.labels[].name | select(. == "major" or . == "minor" or . == "patch" or . == "chore")] | join(",")') - if [ -n "${remove}" ]; then - gh pr edit "${PR_NUMBER}" --remove-label "${remove}" - fi From 21e23be317b68d3c01f3d1edb2ccfd378e4364b3 Mon Sep 17 00:00:00 2001 From: Xianpeng Shen <3353385+shenxianpeng@users.noreply.github.com> Date: Fri, 16 Oct 2026 20:36:31 +0000 Subject: [PATCH 4/4] chore: let semver labels override the PR title in both directions List the semver:* label resolvers first and make them exclusive, so a labeled PR skips the title rules and its label can also lower the bump (e.g. a feat: PR labeled semver:patch). --- .github/release-drafter.yml | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index fa279c8..fbd2881 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -68,25 +68,36 @@ categories: # https://github.com/release-drafter/release-drafter?tab=readme-ov-file#version-resolver # The next version comes from the conventional PR title: `type!:` is a # breaking change (major), `feat:` is minor, anything else is patch. - # The `semver:*` labels override it by hand. They are deliberately not - # named `major`/`minor`/`patch`, because Dependabot adds labels with those - # exact names to its PRs whenever they exist in the repository. + # A `semver:*` label overrides the title in either direction: these rules + # come first and are exclusive, so the title rules below are skipped for a + # labeled PR. The labels are deliberately not named `major`/`minor`/`patch`, + # because Dependabot adds labels with those exact names to its PRs whenever + # they exist in the repository. - type: version-resolver semver-increment: major + exclusive: true when: - - label: semver:major - - conventional: - breaking: true + label: semver:major - type: version-resolver semver-increment: minor + exclusive: true when: - - label: semver:minor - - conventional: - type: feat + label: semver:minor - type: version-resolver semver-increment: patch + exclusive: true when: label: semver:patch + - type: version-resolver + semver-increment: major + when: + conventional: + breaking: true + - type: version-resolver + semver-increment: minor + when: + conventional: + type: feat # Fallback when nothing above matches - type: version-resolver semver-increment: patch