Creating releases with GitHub Actions
In October 2021, GitHub introduced a feature that enables maintainers to generate release notes for a release with the click of a button.
By default, the automatically generated release notes contain
- a list of pull requests maintainers have merged since the last release
- a list of first-time contributors to that release
- a link to the diff, comparing the changes between this and the previous release
Additionally, you can configure filters and groups to fine-tune the content of these release notes, depending on the authors and labels attached to the pull requests.
While these automatically generated release notes may not be perfect, they can be a good companion for a curated, hand-crafted CHANGELOG.md
as proposed by the keepachangelog form.
But - why bother clicking buttons when you could automatically create a release with release notes any time you push a tag to GitHub? In addition to the user interface, GitHub allows maintainers to create a release via their API. In combination with actions/github-script
, you can quickly implement a GitHub Actions workflow that will create a release with generated release notes every time you push a tag!
Release workflow
Here is an example of a release workflow, placed in .github/workflows/release.yaml
in the root of your repository:
# https://docs.github.com/en/actions
name: "Release"
on: # yamllint disable-line rule:truthy
push:
tags:
- "**"
jobs:
release:
name: "Release"
runs-on: "ubuntu-latest"
steps:
- name: "Determine tag"
run: "echo \"RELEASE_TAG=${GITHUB_REF#refs/tags/}\" >> $GITHUB_ENV"
- name: "Create release"
uses: "actions/github-script@v6"
with:
github-token: "${{ secrets.GITHUB_TOKEN }}"
script: |
try {
const response = await github.rest.repos.createRelease({
draft: false,
generate_release_notes: true,
name: process.env.RELEASE_TAG,
owner: context.repo.owner,
prerelease: false,
repo: context.repo.repo,
tag_name: process.env.RELEASE_TAG,
});
core.exportVariable('RELEASE_ID', response.data.id);
core.exportVariable('RELEASE_UPLOAD_URL', response.data.upload_url);
} catch (error) {
core.setFailed(error.message);
}
With a release workflow in place, run
git tag -s x.y.z
followed by
git push --tags
to create a release with automatically generated release notes from the terminal.
Composite action
Since I have started to use this workflow in all of my open-source repositories on GitHub, I have extracted this workflow into a composite action in ergebnis/.github
for easier reuse.
Here is what the composite action looks like:
# https://docs.github.com/en/actions/creating-actions/creating-a-composite-action
# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#inputs
# https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#runs-for-composite-run-steps-actions
# https://docs.github.com/en/rest/reference/releases#create-a-release
# https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#push
name: "Create a release"
description: "Creates a release"
inputs:
github-token:
description: "GitHub token of a user with permission to create a release"
required: true
runs:
using: "composite"
steps:
- name: "Determine tag"
if: "${{ github.event_name }} == 'push' && ${{ github.ref_type }} == 'tag'"
run: "echo \"RELEASE_TAG=${GITHUB_REF#refs/tags/}\" >> $GITHUB_ENV"
shell: "bash"
- name: "Create release"
uses: "actions/github-script@v6.3.3"
with:
github-token: "${{ inputs.github-token }}"
script: |
if (!process.env.RELEASE_TAG) {
core.setFailed("The environment variable RELEASE_TAG is not defined.")
return;
}
try {
const response = await github.rest.repos.createRelease({
draft: false,
generate_release_notes: true,
name: process.env.RELEASE_TAG,
owner: context.repo.owner,
prerelease: false,
repo: context.repo.repo,
tag_name: process.env.RELEASE_TAG,
});
core.exportVariable('RELEASE_ID', response.data.id);
core.exportVariable('RELEASE_UPLOAD_URL', response.data.upload_url);
} catch (error) {
core.setFailed(error.message);
}
Release workflow using composite action
Thanks to the composite action above, a workflow for creating a release on GitHub with automatically generated release notes is as simple as this:
# https://docs.github.com/en/actions
name: "Release"
on: # yamllint disable-line rule:truthy
push:
tags:
- "**"
jobs:
release:
name: "Release"
runs-on: "ubuntu-latest"
steps:
- name: "Create release"
uses: "ergebnis/.github/actions/github/release/create@1.8.0"
with:
github-token: "${{ secrets.GITHUB_TOKEN }}"
You can see an example of a release with release notes created by this workflow in ergebnis/data-provider:1.3.0
.
Project on GitHub
ergebnis/.github
❤️ Provides default community health files and composite actions for the @ergebnis
organization.
Find out more at ergebnis/.github
.
Do you find this article helpful?
Do you have feedback?
Just blogged: Creating releases with @github Actions.
— Andreas Möller (@localheinz) January 24, 2022
↓https://t.co/oWPpllIBUr