A GitHub Action that automates semantic versioning and releases using conventional commits. Merge a PR and the action handles the rest — version bumps, changelogs, tags, and GitHub releases. Optionally gate releases behind a label.
- Add the workflow to your repo (see Usage below)
- Merge a PR — the action creates a release PR with the version bump and changelog
- Review and merge the release PR — the action creates the tag and GitHub release
By default, every merged PR triggers a release. If you'd rather control when releases happen, set
require-release-label: true and add the configured label (default: change-release) to PRs that should trigger a
release.
The action operates in two phases, both triggered by pull_request closed events:
When a PR is merged (and the release label requirement is met, if enabled):
- Finds the latest version tag
- Analyzes all commits since that tag using conventional commit prefixes
- Determines the appropriate semver bump (major, minor, or patch)
- Creates a
release/<prefix><version>branch - Bumps
package.jsonversion if npm publishing is enabled - Optionally generates/updates
CHANGELOG.md - Opens a release PR with a summary of what's included
When the release PR (detected by the release/ branch prefix) is merged:
- Creates an annotated git tag
- Optionally creates a GitHub release with auto-generated release notes
- Optionally publishes to an npm registry
# .github/workflows/release.yml
name: Release
on:
pull_request:
types: [ closed ]
permissions:
contents: write
pull-requests: write
jobs:
release:
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.merge_commit_sha }}
fetch-depth: 0
- uses: offload-project/release-champion@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}Note:
fetch-depth: 0is required so the action can access the full commit history and tags.
| Input | Description | Required | Default |
|---|---|---|---|
github-token |
GitHub token for creating PRs, tags, and releases | Yes | — |
release-label |
Label that marks a PR for release (only used when require-release-label is true) |
No | change-release |
require-release-label |
Require the release label to trigger a release PR. When false, every merged PR triggers a release |
No | false |
version-prefix |
Prefix for version tags (e.g., v produces v1.2.3) |
No | v |
create-tag |
Create a git tag when the release PR is merged | No | true |
create-release |
Create a GitHub release when the release PR is merged | No | true |
draft-release |
Create the GitHub release as a draft (unpublished) | No | true |
changelog |
Generate or update CHANGELOG.md in the release PR |
No | true |
publish-npm |
Publish the package to an npm registry when the release PR is merged | No | false |
npm-token |
Auth token for the npm registry (required when publish-npm is true) |
No | — |
npm-registry |
npm registry URL (set to https://npm.pkg.github.com for GitHub Packages) |
No | https://registry.npmjs.org |
npm-build-command |
Build command to run before npm publish (e.g., npm run build) |
No | — |
| Output | Description |
|---|---|
version |
The new version string (e.g., 1.2.3) |
release-pr |
URL of the created release PR (Phase 1) |
tag |
The created tag name (Phase 2) |
release-url |
URL of the created GitHub release (Phase 2) |
The action parses commit messages to determine the version bump:
| Commit prefix | Bump | Example |
|---|---|---|
feat!: or BREAKING CHANGE |
major | feat!: drop support for Node 14 |
feat: |
minor | feat(auth): add OAuth2 support |
fix: |
patch | fix: resolve null pointer in parser |
chore:, docs:, refactor:, perf:, style:, build: |
patch | chore: update dependencies |
The highest applicable bump wins. If any commit contains a breaking change, the bump is always major.
When changelog is enabled, the action generates a CHANGELOG.md grouped by change type with links to the associated
PRs:
## v1.3.0 - 2026-03-27
### Added
- Add support for wildcard permissions [#234](https://github.com/owner/repo/pull/234)
- Add `hasAnyPermission` method [#230](https://github.com/owner/repo/pull/230)
### Fixed
- Fix cache invalidation on role update [#232](https://github.com/owner/repo/pull/232)
### Changed
- Update minimum PHP version to 8.1 [#228](https://github.com/owner/repo/pull/228)Commits that can't be linked to a PR will reference the commit SHA instead.
- uses: offload-project/release-champion@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}- uses: offload-project/release-champion@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
draft-release: false
changelog: false- uses: offload-project/release-champion@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
require-release-label: true- uses: offload-project/release-champion@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
require-release-label: true
release-label: 'ready-to-release'
version-prefix: ''- uses: offload-project/release-champion@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
publish-npm: true
npm-token: ${{ secrets.NPM_TOKEN }}
npm-build-command: 'npm run build'- uses: offload-project/release-champion@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
publish-npm: true
npm-token: ${{ secrets.GITHUB_TOKEN }}
npm-registry: 'https://npm.pkg.github.com'
npm-build-command: 'npm run build'- uses: offload-project/release-champion@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
create-release: falsesteps:
- uses: actions/checkout@v6
with:
ref: ${{ github.event.pull_request.merge_commit_sha }}
fetch-depth: 0
- uses: offload-project/release-champion@v1
id: release
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
- if: steps.release.outputs.version
run: echo "Released version ${{ steps.release.outputs.version }}"The workflow needs contents: write (for tags and releases) and pull-requests: write (for creating PRs). If
publishing to GitHub Packages, also add packages: write. If using the default GITHUB_TOKEN, set these under the
job's permissions key.
bats tests/conventional.batsMIT