Table of Contents
The Problem
Release Drafter is a GitHub Action that automatically generates release note drafts based on PR labels. We had been using separate Release Drafter configurations per service in a monorepo, but ran into an issue where PRs that should be included were missing, or PRs that shouldn’t be included were appearing in the release notes.
For details on automating Release notes with Release Drafter and validating labels, please refer to the following blog posts.
How Release Drafter Works
Release Drafter generates release notes in the following order:
- Find the latest tag (previous release) using
tag-prefix - Retrieve the commit history from the previous release tag to the
HEADof thecommitish(target branch) - Find PRs linked to those commits and classify them by PR labels into categories
- Generate a release note draft according to the template
The key here is commitish. The range of PRs included in the release notes depends on which branch this value points to.
The Problem with commitish: main
In the existing configuration, commitish was fixed to main in release-drafter.yml.
# .github/release-drafter.yml (before)
commitish: main
This leads to the following problems:
1. Changes only in the release branch are missing
Changes applied directly to the release branch via hotfixes or cherry-picks don’t exist on the main branch, so they are excluded from the release notes.
hotfix ──────┐
▼
release: ──A──B──C─┼──H── ← H(hotfix) is not on main, so it's missing from release notes
│
main: ──A──B──C──D──E──F──
2. Changes merged to main after the release branch was created are included
PRs merged to main after the release branch was created are also included in the release notes. These are changes not actually part of the current release.
main: ──A──B──C──D──E──F── ← E, F are for the next release but included in release notes
│
release: ──A──B──C─┘
Solution
Core Idea: Splitting the Workflow
Release Drafter provides two main features:
| Feature | Description | When to Run |
|---|---|---|
| Autolabeler | Automatically assigns labels to PRs | When a PR is created or updated |
| Release note generation | Creates release note drafts based on labels | When there are changes to the release branch |
Previously, both features were executed in a single workflow, but since their execution timing and target branches differ, splitting them is the rational approach.
- Autolabel: Runs on PR events → targets the main branch
- Release note generation: Runs on push to release branches → targets the release branch
Workflow 1: PR Label Checker (autolabel only)
A workflow that only assigns labels automatically when a PR is created or updated. Release note generation is disabled with disable-releaser: true.
# .github/workflows/pr-label-checker.yml
name: PR Label Checker
on:
pull_request:
types: [opened, reopened, synchronize]
permissions:
contents: read
jobs:
check_pr_labels:
permissions:
contents: write
pull-requests: write
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Extract branch and service name
id: extract
uses: ./.github/actions/extract_branch_and_service_name
- name: Set environment variables
run: |
echo "SERVICE_NAME=${{ steps.extract.outputs.SERVICE_NAME }}" >> $GITHUB_ENV
- name: Autolabel
uses: release-drafter/release-drafter@v6
with:
config-name: release-drafter.yml
disable-releaser: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Setting
disable-releaser: trueprevents Release Drafter from generating release note drafts, running only the autolabel feature.
Workflow 2: Release Drafter (release notes only)
A workflow that generates release notes when a push occurs to a release branch. Label assignment is disabled with disable-autolabeler: true, and commitish is dynamically set to the release branch.
# .github/workflows/release-drafter-on-release-branch.yml
name: Release Drafter (on release branch)
on:
push:
branches:
- 'release/**'
permissions:
contents: read
jobs:
update_release_draft:
permissions:
contents: write
pull-requests: write
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Extract branch and service name
id: extract
uses: ./.github/actions/extract_branch_and_service_name
- name: Set environment variables
run: |
echo "SERVICE_NAME=${{ steps.extract.outputs.SERVICE_NAME }}" >> $GITHUB_ENV
echo "FULL_BRANCH_NAME=${{ steps.extract.outputs.FULL_BRANCH_NAME }}" >> $GITHUB_ENV
- name: Run Release Drafter
uses: release-drafter/release-drafter@v6
with:
config-name: release-drafter.yml
commitish: ${{ env.FULL_BRANCH_NAME }}
disable-autolabeler: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
The key is commitish: ${{ env.FULL_BRANCH_NAME }}. By dynamically passing the release branch name (e.g., release/serviceName/1.2.0), only changes included in that release branch are reflected in the release notes.
Updating release-drafter.yml
Remove commitish from the shared configuration file. Since it’s now passed dynamically from the workflow, there’s no need to hardcode it in the configuration file.
# .github/release-drafter.yml (after)
version-resolver:
minor:
labels:
- 'minor'
patch:
labels:
- 'patch'
default: minor
# commitish: main ← removed
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
change-title-escapes: '\<*_&'
template: |
## Changes
$CHANGES
Updating the Composite Action: Supporting Push Events
The existing branch name extraction Composite Action only supported pull_request events. It needs to be updated to also work with push events to release branches.
For details on how to use Composite Actions, please refer to the following link.
# .github/actions/extract_branch_and_service_name/action.yml
runs:
using: composite
steps:
- id: extract_branch_and_service_name
shell: bash
run: |
# Before
# FULL_BRANCH_NAME=${{ github.event.pull_request.head.ref }}
# After: Support both PR events and push events
if [ -n "${{ github.event.pull_request.head.ref }}" ]; then
FULL_BRANCH_NAME=${{ github.event.pull_request.head.ref }}
else
FULL_BRANCH_NAME=${GITHUB_REF#refs/heads/}
fi
pull_requestevent: Gets the branch name fromgithub.event.pull_request.head.ref.pushevent: Extracts the branch name by removing therefs/heads/prefix from theGITHUB_REFenvironment variable.
Key Release Drafter Action Inputs
Here’s a summary of the key Release Drafter Action Inputs used in the workflow split.
| Input | Default | Description |
|---|---|---|
config-name | release-drafter.yml | Path to the configuration file (relative to .github/) |
commitish | Workflow execution branch | Release target branch or commit. Changes up to this branch’s HEAD are included in notes |
disable-releaser | false | When true, disables release note generation and runs only the autolabel feature |
disable-autolabeler | false | When true, disables autolabel and runs only release note generation |
tag-prefix | '' | Release tag prefix. Filters by this prefix when searching for previous releases |
filter-by-commitish | false | When true, only considers releases matching the commitish when searching for previous releases |
Considerations
Separating configuration files per service in a monorepo
When managing multiple services in a monorepo, separate release-drafter-for-{serviceName}.yml configuration files per service with different tag-prefix values to distinguish releases.
# .github/release-drafter-for-serviceName.yml
tag-prefix: serviceName-v
This searches for previous releases from tags like serviceName-v1.2.0 and includes only subsequent changes in the release notes.
Release branch naming conventions
The release/** pattern and the logic for extracting service names in the Composite Action must be consistent. For example, if there’s a rule to extract serviceName as the service name from release/serviceName/1.2.0, this convention must be followed when creating branches.
For details on how to validate branch names with GitHub Actions, please refer to the following link.
Using filter-by-commitish
When multiple release branches exist simultaneously, setting filter-by-commitish: true ensures that only releases created from the relevant release branch are considered when searching for previous releases. This prevents releases from different release branches from being mixed.
Conclusion
Fixing Release Drafter’s commitish to main causes inaccurate release notes due to differences between the release branch and the main branch. By splitting the workflow into autolabel only and release note generation only, and dynamically setting commitish to the release branch, you can generate accurate release notes.
Was my blog helpful? Please leave a comment at the bottom. it will be a great help to me!
App promotion
Deku.Deku created the applications with Flutter.If you have interested, please try to download them for free.