Automating Releases with GitHub Actions
Releasing by hand (build, write notes, upload files) is slow and easy to get wrong. A tag-triggered workflow does it the same way every time.
Trigger on version tags
# .github/workflows/release.yml
name: Release
on:
push:
tags: ['v*.*.*']
permissions:
contents: write # create releases
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm test
- run: npm run build
- run: tar -czf dist-${{ github.ref_name }}.tar.gz dist
- name: Create GitHub release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release create "${{ github.ref_name }}" \
dist-${{ github.ref_name }}.tar.gz \
--title "${{ github.ref_name }}" \
--generate-notes
# Releasing is now just:
git tag v1.4.0
git push origin v1.4.0
Better release notes
--generate-notes lists merged pull requests since the previous release. Group them by label with a .github/release.yml file:
changelog:
categories:
- title: New features
labels: [feature]
- title: Bug fixes
labels: [bug]
- title: Other changes
labels: ['*']
Fully automated versioning
If you use Conventional Commits, tools like release-please or semantic-release can decide the next version number, update the changelog and create the tag for you. release-please opens a "release PR" that you merge when you're ready to ship.
Publishing packages
- npm:
npm publish --provenancewith an npm token, or trusted publishing via OIDC, to link packages to the workflow that built them. - Docker images: push a semver tag alongside the SHA tag.
- Run the full test suite in the release workflow; never release untested tags.
Was this article helpful?
Comments
No comments yet. Have a question or a tip? Be the first to share it.