Using GitHub Actions to Automate Releases and Changelogs
#github-actions
#ci-cd
#release-management
#changelog
Introduction
Automating releases and changelogs saves time and reduces human error. With GitHub Actions, you can trigger releases when you tag a new version, generate a new changelog automatically, and publish assets or packages to registries. This post walks through practical patterns, from a simple tag-based release to a full end-to-end workflow powered by semantic release.
Prerequisites
- A repository with a conventional commits or clear commit messages to drive changelog generation.
- Access to push to the repository (GitHub token available to Actions by default).
- A package.json or project setup that you want to release (optional for non-NPM projects).
- Basic familiarity with GitHub Actions and YAML workflows.
What you can automate
- Create a GitHub Release when a new tag is pushed.
- Generate or update a CHANGELOG.md automatically.
- Optionally publish artifacts (e.g., binaries, NPM packages) as part of the release.
- Keep release notes aligned with your commit history or conventional commit messages.
Option 1: Tag-based release with a generated CHANGELOG
This approach uses a tag to trigger a release and updates a CHANGELOG.md entry as part of the release process.
Example workflow: release on tag
Create a file at .github/workflows/release-on-tag.yml with the following content:
name: Release on Tag
on:
push:
tags:
- 'v*.*.*'
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Generate CHANGELOG
run: npx conventional-changelog -p angular -i CHANGELOG.md -s && git diff --quiet
- name: Commit CHANGELOG
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add CHANGELOG.md
if git diff --cached --quiet; then
echo "CHANGELOG.md is up to date"
else
git commit -m "docs(changelog): update CHANGELOG for ${GITHUB_REF_NAME}"
git push
fi
- name: Create Release
uses: actions/create-release@v1
with:
tag_name: ${{ github.ref_name }}
release_name: Release ${{ github.ref_name }}
draft: false
prerelease: false
- name: Upload Release Asset (optional)
uses: actions/upload-release-asset@v1
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: dist/my-app.zip
asset_name: my-app.zip
asset_content_type: application/zip
Notes:
- The CHANGELOG generation uses conventional-changelog with the angular preset as a common convention. You can adjust the preset or rules to fit your project.
- The asset upload step is optional and only needed if you build and publish artifacts with the release.
Option 2: Automatic releases and changelog with semantic-release
For a fully automated approach, use semantic-release to determine the next version from commit messages, update CHANGELOG.md, commit changes, and create the GitHub release.
Prerequisites for semantic-release
- Install semantic-release and required plugins (or run via npx).
- A .releaserc.json (or release configuration) specifying your changelog destination and plugins.
- Conventional commits or a similar scheme to drive version bumps.
Example release configuration
Create a file named .releaserc.json with:
{
"branches": ["main"],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
["@semantic-release/changelog", {
"changelogFile": "CHANGELOG.md"
}],
["@semantic-release/git", {
"assets": ["CHANGELOG.md"],
"message": "chore(release): ${nextRelease.version} [skip ci]"
}],
"@semantic-release/github"
]
}
Example workflow: end-to-end semantic release on tag
Create .github/workflows/release-semantic.yml:
name: Semantic Release
on:
push:
tags:
- 'v*.*.*'
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Run semantic-release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npx semantic-release
How this works:
- semantic-release analyzes your commit messages to decide the next version (major, minor, patch).
- It updates CHANGELOG.md via the changelog plugin.
- It commits the changelog and version changes back to the repository.
- It creates a GitHub Release via the GitHub plugin.
Tips for success:
- Use conventional commits (feat, fix, perf, docs, chore, etc.) to drive sensible version bumps.
- Ensure your workflow has permission to push changes (GITHUB_TOKEN with contents: write).
- If you publish packages (e.g., npm), extend the plugins with @semantic-release/npm or similar.
Option 3: Changelog drafts with Release Drafter (synthetic approach)
If you prefer drafting release notes in advance via pull requests, Release Drafter can help populate a draft release body as PRs are merged.
Setup highlights
- Add a draft release config at .github/release-drafter.yml.
- Optionally run a lightweight workflow that creates a release when you push a tag, using Release Drafter to compose the body.
Sample Release Drafter config (.github/release-drafter.yml):
name-template: 'Release ${tag_name}'
tag-template: '${tag_name}'
categories:
- title: 'Features'
label: features
- title: 'Bug Fixes'
label: fixes
- title: 'Other Changes'
label: other
And a minimal workflow to pair with it (optional):
name: Draft Release Notes
on:
push:
branches: [ main ]
jobs:
draft:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: release-drafter/release-drafter@v5
with:
config-name: release-drafter-config
Note: Release Drafter helps generate a draft release body but does not overwrite CHANGELOG.md by default. You can combine it with a separate changelog generation step if you want a CHANGELOG.md in addition to the draft.
Best practices and tips
- Choose a strategy that matches your workflow: simple tag-based releases for straightforward projects, or semantic-release for true automation tied to commit messages.
- Document your release process in CONTRIBUTING.md so contributors understand how releases are produced.
- Use a changelog file (CHANGELOG.md) as the single source of truth for consumers who don’t use the GitHub Releases page.
- If you publish artifacts, consider including checks or tests in the release workflow to ensure the artifact is stable before publishing.
- Keep your workflows versioned alongside your code to avoid sudden breaking changes in CI.
Conclusion
GitHub Actions makes it practical to automate both releases and changelogs, from tag-triggered releases to fully automated version bumps and changelog updates. By selecting a strategy that fits your project’s needs—tag-based with a generated changelog, full semantic-release automation, or a draft-notes approach—you can release faster and more reliably while keeping stakeholders informed.