Automated release creation and changelog maintenance using Clean Commit convention and Keep a Changelog format.
Zero-intervention release automation with deterministic logicβno AI required!
Stop manually managing versions, changelogs, and GitHub Releases. This action automatically detects new commits, determines version bumps using semantic versioning, generates structured changelogs following the Keep a Changelog format, and creates GitHub Releasesβall from your Clean Commit messages.
- Why Use This Action?
- How It Works
- Features
- Commit Type Mapping
- Quick Start
- Inputs
- Monorepo Support
- Outputs
- Examples
- Conventional Commit Examples
- Generated CHANGELOG.md Example
- Development
- Troubleshooting
- License
- Contributing
- Acknowledgments
The Problem:
Managing releases is tedious and error-prone. Teams spend time manually:
- Deciding version numbers
- Writing changelogs
- Creating Git tags
- Publishing GitHub Releases
- Categorizing changes consistently
The Solution:
One action that analyzes your conventional commits and automatically handles everything. Push code with Clean Commit messages, and get semantic versioning, categorized changelogs, and professional releasesβevery time.
graph LR
A[New Commits] --> B{Parse Commits}
B --> C[Determine Version Bump]
C --> D{Bump Type?}
D -->|Major| E[X.0.0]
D -->|Minor| F[X.Y.0]
D -->|Patch| G[X.Y.Z]
D -->|None| H[Skip]
E --> I[Generate Changelog]
F --> I
G --> I
I --> J[Update CHANGELOG.md]
J --> K[Create Tag]
K --> L[Create GitHub Release]
Fully deterministicβno AI, no guessing. The action parses your commit messages, maps types to changelog sections, bumps versions based on configurable rules, and creates releases with structured content.
- π― Intelligent Version Bumping - Automatically determines MAJOR.MINOR.PATCH based on commit types
- π Keep a Changelog Format - Maintains CHANGELOG.md with proper sections (Added, Changed, Fixed, etc.)
- π·οΈ Clean Commit Parsing - Maps conventional commit types to changelog categories
- π GitHub Release Creation - Automated releases with changelog content
- π’ Monorepo Support - Per-package versioning, changelogs, and releases for multi-package repositories
- βοΈ Highly Configurable - Customize type mappings, exclusions, and version bump rules
- π Deterministic Logic - No AI dependencies, purely rule-based
- π Rich Outputs - Version info, commit counts, categorized change counts, and release URLs
This action uses conventional commits (Clean Commit convention) and maps them to Keep a Changelog sections:
| Commit Type | Changelog Section | Examples |
|---|---|---|
feat, new, add |
Added | New features, capabilities |
fix, bugfix, revert |
Fixed | Bug fixes, corrections, reverts |
security |
Security | Security patches, vulnerability fixes |
perf, refactor, update, change, chore, setup |
Changed | Performance improvements, refactoring, setup tasks |
deprecate |
Deprecated | Soon-to-be removed features |
remove, delete |
Removed | Removed features, deleted code |
Breaking Changes: Commits with ! suffix or BREAKING CHANGE in body trigger major version bumps.
Excluded by default: docs, style, test, ci, build (configurable via exclude-types)
name: Release
on:
push:
branches: [main]
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Required for full git history
- name: Create Release
uses: wgtechlabs/release-build-flow-action@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}- name: Create Release with Custom Settings
uses: wgtechlabs/release-build-flow-action@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
version-prefix: 'v'
initial-version: '1.0.0'
changelog-path: './CHANGELOG.md'
release-name-template: '{tag} - {date}'
exclude-types: 'docs,style,test,ci'- name: Create Beta Release
uses: wgtechlabs/release-build-flow-action@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
prerelease-prefix: 'beta'
release-prerelease: true- name: Create Version Tag
uses: wgtechlabs/release-build-flow-action@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
tag-only: true- name: Create Release with Conventional Commits
uses: wgtechlabs/release-build-flow-action@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
commit-convention: 'conventional'Note: By default, auto-generated commits (e.g., changelog updates) and tag annotations use Clean Commit convention with emoji prefixes. Set
commit-convention: 'conventional'to use standard Conventional Commits format instead.The
commit-conventionsetting also adjusts smart defaults for version bump keywords and excluded types:
Setting clean-commit(default)conventionalCommit format β chore: ...chore: ...Tag format π release: v1.2.0Release v1.2.0minor-keywordsfeat,new,addfeatpatch-keywordsfix,bugfix,security,perf,update,removefix,perf,revertexclude-typesdocs,style,test,ci,build,releasedocs,style,test,ci,build,choreUser-provided values always take priority over convention defaults.
| Input | Description | Default |
|---|---|---|
github-token |
GitHub token for creating releases and tags | ${{ github.token }} |
| Input | Description | Default |
|---|---|---|
main-branch |
Name of the main/production branch | main |
dev-branch |
Name of the development branch | dev |
| Input | Description | Default |
|---|---|---|
version-prefix |
Prefix for version tags (e.g., v for v1.2.3) |
v |
initial-version |
Initial version if no tags exist (falls back to manifest file version first, then this value) | 0.1.0 |
prerelease-prefix |
Prefix for prerelease versions (e.g., beta, alpha, rc) |
`` |
Version Resolution: When no git tags exist, the action checks for a version in manifest files (
package.json,Cargo.toml,pyproject.toml,pubspec.yaml) in priority order. If a valid SemVer version is found, it is used as the starting version. Otherwise, theinitial-versioninput is used as the final fallback.
| Input | Description | Default |
|---|---|---|
changelog-path |
Path to CHANGELOG.md file | ./CHANGELOG.md |
changelog-enabled |
Enable automatic changelog generation | true |
commit-changelog |
Commit and push changelog changes back to repository | true |
| Input | Description | Default |
|---|---|---|
commit-type-mapping |
JSON mapping of commit types to changelog sections | Standard mapping |
exclude-types |
Comma-separated list of commit types to exclude | docs,style,test,ci,build,release |
exclude-scopes |
Comma-separated list of commit scopes to exclude | `` |
| Input | Description | Default |
|---|---|---|
major-keywords |
Keywords that trigger major version bump | BREAKING CHANGE,BREAKING-CHANGE,breaking |
minor-keywords |
Keywords that trigger minor version bump | feat,new,add |
patch-keywords |
Keywords that trigger patch version bump | fix,bugfix,security,perf,update,remove |
| Input | Description | Default |
|---|---|---|
create-release |
Enable GitHub Release creation | true |
release-draft |
Create release as draft | false |
release-prerelease |
Mark release as prerelease | false |
release-name-template |
Template for release name (supports {tag}, {version}, {date}) |
{tag} |
| Input | Description | Default |
|---|---|---|
git-user-name |
Git user name for commits | WG Tech Labs |
git-user-email |
Git user email for commits | 262751631+wgtechlabs-automation@users.noreply.github.com |
commit-convention |
Commit message convention for auto-generated commits and smart defaults (clean-commit or conventional) |
clean-commit |
| Input | Description | Default |
|---|---|---|
sync-version-files |
Automatically update version in manifest files (package.json, Cargo.toml, pyproject.toml, pubspec.yaml) |
false |
version-file-paths |
Comma-separated paths to manifest files to update (auto-detected if not specified) | `` |
Note: Version file sync runs only when
commit-changelogandchangelog-enabledare bothtrue. The action auto-detects supported manifest files in the repository root whenversion-file-pathsis not specified.
| Input | Description | Default |
|---|---|---|
dry-run |
Run without creating tags or releases (testing mode) | false |
tag-only |
Only create tag without GitHub Release | false |
update-major-tag |
Automatically update major version tag (e.g., v1) to point to latest release. Standard practice for GitHub Actions. |
false |
fetch-depth |
Number of commits to fetch for changelog (0 for all) | 0 |
include-all-commits |
Include all commits in changelog, not just since last tag | false |
| Input | Description | Default |
|---|---|---|
monorepo |
Enable monorepo mode for multi-package repositories | false |
workspace-detection |
Auto-detect workspace packages from package.json, pnpm-workspace.yaml, etc. | true |
change-detection |
How to detect affected packages: scope (commit scope), path (file changes), or both |
both |
scope-package-mapping |
JSON mapping of commit scopes to package paths (auto-detected if not provided) | '' |
per-package-changelog |
Generate CHANGELOG.md in each package directory | true |
root-changelog |
Generate aggregated CHANGELOG.md at repository root | true |
monorepo-root-release |
Create a unified root release (tag, GitHub Release) using the aggregated root CHANGELOG.md alongside per-package releases | true |
cascade-bumps |
(Reserved for future use) Automatically bump packages that depend on updated packages | false |
unified-version |
All packages share a single unified version number | false |
package-manager |
Package manager for workspace detection (npm, bun, pnpm, yarn) - auto-detected if not specified |
'' |
Note: Monorepo features require
@v2or later.
The action now supports monorepos with per-package versioning, changelogs, and releases!
When monorepo: true is enabled:
-
Workspace Detection - Automatically discovers packages from:
package.jsonworkspaces fieldpnpm-workspace.yamllerna.json
-
Smart Routing - Routes commits to packages based on:
- Scope-based:
feat(core): add featureβ affects@pkg/core - Path-based: Changes to
packages/core/src/β affects@pkg/core - Both: Combines scope and path detection for maximum accuracy
- Scope-based:
-
Per-Package Versioning - Each package gets independent version bumps:
fix(core):only bumps@pkg/core- Commits without scope affect all packages
-
Per-Package Changelogs - Generates
CHANGELOG.mdin each package directory -
Per-Package Releases - Creates GitHub releases with scoped tags:
@pkg/core@1.2.0@pkg/ui@2.0.1
-
Unified Root Release (enabled by default via
monorepo-root-release: true) - When enabled, creates an additional root-level tag and GitHub Release alongside per-package releases:- Root tag:
v2.1.0 - Root GitHub Release that references:
- Aggregated root
CHANGELOG.mdacross all packages (ifroot-changelog: true; this aggregation runs regardless ofmonorepo-root-release) - Synced root version files such as
package.json(ifsync-version-files: true; version syncing also runs independently ofmonorepo-root-release)
- Aggregated root
This root tag and GitHub Release enable downstream workflows (e.g., container builds) that trigger on
release: types: [published]and filter by semver tag patterns likev1.2.3to work correctly. Setmonorepo-root-release: falseto keep only per-package tags/releases while still optionally generating a rootCHANGELOG.mdand syncing version files viaroot-changelogandsync-version-files. - Root tag:
name: Monorepo Release
on:
push:
branches: [main]
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Create Monorepo Releases
id: release
uses: wgtechlabs/release-build-flow-action@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
monorepo: true
workspace-detection: true
change-detection: both
per-package-changelog: true
- name: Display Results
run: |
echo "Packages Updated: ${{ steps.release.outputs.packages-count }}"
echo "Details: ${{ steps.release.outputs.packages-updated }}"For monorepos that want all packages to share a single version:
- name: Unified Monorepo Release
uses: wgtechlabs/release-build-flow-action@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
monorepo: true
unified-version: true # All packages bump togetherExplicitly map commit scopes to package paths:
- name: Monorepo with Custom Mapping
uses: wgtechlabs/release-build-flow-action@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
monorepo: true
scope-package-mapping: |
{
"core": "packages/core",
"memory": "packages/memory",
"cli": "src/cli",
"discord": "plugins/channel/discord"
}| Output | Description |
|---|---|
packages-updated |
JSON array of packages that were updated |
packages-count |
Number of packages updated |
Each package in packages-updated includes:
name- Package namepath- Package directory patholdVersion- Previous versionversion- New versionbumpType- Type of bump (major,minor,patch,none)tag- Generated tag (e.g.,@pkg/core@1.2.0)
| Output | Description |
|---|---|
version |
Generated version number (e.g., 1.2.3) |
version-tag |
Full version tag with prefix (e.g., v1.2.3) |
previous-version |
Previous version number |
version-bump-type |
Type of version bump (major, minor, patch, or none) |
| Output | Description |
|---|---|
release-created |
Whether a release was created (true/false) |
release-id |
GitHub Release ID |
release-url |
GitHub Release URL |
release-upload-url |
GitHub Release upload URL for assets |
| Output | Description |
|---|---|
major-tag |
The major version tag that was updated (e.g., v1). Empty if update-major-tag is disabled. |
| Output | Description |
|---|---|
changelog-updated |
Whether changelog was updated (true/false) |
changelog-entry |
Generated changelog entry for this version |
commit-count |
Number of commits included in this release |
| Output | Description |
|---|---|
added-count |
Number of Added changes |
changed-count |
Number of Changed items |
deprecated-count |
Number of Deprecated items |
removed-count |
Number of Removed items |
fixed-count |
Number of Fixed items |
security-count |
Number of Security fixes |
name: Release
on:
push:
branches: [main]
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Create Release
id: release
uses: wgtechlabs/release-build-flow-action@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Display Results
run: |
echo "Version: ${{ steps.release.outputs.version }}"
echo "Tag: ${{ steps.release.outputs.version-tag }}"
echo "Release URL: ${{ steps.release.outputs.release-url }}"
echo "Commits: ${{ steps.release.outputs.commit-count }}"- name: Release with Custom Mapping
uses: wgtechlabs/release-build-flow-action@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
commit-type-mapping: |
{
"feat": "Added",
"feature": "Added",
"fix": "Fixed",
"bug": "Fixed",
"security": "Security",
"perf": "Changed",
"improve": "Changed",
"deprecate": "Deprecated",
"remove": "Removed"
}- name: Release Backend Package
uses: wgtechlabs/release-build-flow-action@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
exclude-scopes: 'frontend,docs,infra' # Only include backend changes- name: Create Draft Release
uses: wgtechlabs/release-build-flow-action@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
release-draft: true- name: Create Release
id: release
uses: wgtechlabs/release-build-flow-action@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Notify Slack
if: steps.release.outputs.release-created == 'true'
run: |
curl -X POST ${{ secrets.SLACK_WEBHOOK }} \
-H 'Content-Type: application/json' \
-d '{
"text": "π New release: ${{ steps.release.outputs.version-tag }}\nAdded: ${{ steps.release.outputs.added-count }}, Fixed: ${{ steps.release.outputs.fixed-count }}\n${{ steps.release.outputs.release-url }}"
}'If you need a GitHub Release to trigger other workflows (e.g., a container build workflow that listens for release: [published]), you must use a PAT or GitHub App token instead of the default GITHUB_TOKEN. Releases created with GITHUB_TOKEN will not trigger workflows listening on release events (i.e., will not start downstream workflow runs) due to a GitHub platform limitation.
name: Release
on:
push:
branches: [main]
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Create Release
id: release
uses: wgtechlabs/release-build-flow-action@v1
with:
# Use a PAT or GitHub App token so the resulting release
# event triggers downstream workflows (e.g., container builds).
# GITHUB_TOKEN cannot trigger new workflow runs.
github-token: ${{ secrets.GH_PAT }}The downstream workflow (e.g., container-build-flow-action) will then fire normally:
# .github/workflows/container.yml
on:
release:
types: [published] # β
Triggered when PAT/App token creates the releaseHere are examples of commits and their impact on versioning and changelog:
# MINOR version bump (0.1.0 -> 0.2.0)
feat: add user authentication
feat(api): implement OAuth2 login
new: support multiple themes
# PATCH version bump (0.1.0 -> 0.1.1)
fix: resolve memory leak in worker pool
bugfix(auth): correct token validation
security: patch XSS vulnerability in comments
# MAJOR version bump (0.1.0 -> 1.0.0)
feat!: redesign API endpoints
feat(api)!: change response format
# or in commit body:
feat: new API design
BREAKING CHANGE: Response format changed from XML to JSON
# Changes categorized as "Changed"
perf: improve database query performance
refactor: restructure authentication module
chore: update dependencies
# Changes categorized as "Deprecated"
deprecate: mark legacy API endpoints
# Changes categorized as "Removed"
remove: delete deprecated v1 endpoints
# Excluded from changelog (by default)
docs: update README
style: format code with prettier
test: add unit tests for auth
ci: update GitHub Actions workflow# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [1.2.0] - 2024-02-17
### Added
- User authentication with OAuth2
- Support for multiple themes
- Dark mode toggle
### Changed
- Improved database query performance by 40%
- Restructured authentication module for better maintainability
### Fixed
- Resolved memory leak in worker pool
- Corrected token validation in auth middleware
### Security
- Patched XSS vulnerability in comment system
## [1.1.0] - 2024-02-10
### Added
- API rate limiting
### Fixed
- Database connection timeout issuesTo test the action locally without triggering releases:
- name: Dry Run Test
uses: wgtechlabs/release-build-flow-action@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
dry-run: trueYou can use individual outputs to build custom workflows:
- name: Create Release
id: release
uses: wgtechlabs/release-build-flow-action@v1
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Build Artifacts
if: steps.release.outputs.version-bump-type != 'none'
run: |
# Build your project
npm run build
- name: Upload Release Assets
if: steps.release.outputs.release-created == 'true'
uses: actions/upload-release-asset@v1
with:
upload_url: ${{ steps.release.outputs.release-upload-url }}
asset_path: ./dist/app.zip
asset_name: app-${{ steps.release.outputs.version }}.zip
asset_content_type: application/zipCause: No commits with version-bumping types since last release.
Solution: Ensure commits use conventional format with types like feat, fix, new, etc.
Cause: changelog-enabled is set to false or no changes to include.
Solution: Verify changelog-enabled: true and check excluded types.
Cause: Insufficient permissions or create-release is disabled.
Solution:
- Ensure
github-tokenhascontents: writepermission - Check
create-releaseinput is set totrue
Cause: Action cannot push commits/tags.
Solution: Add repository permissions:
permissions:
contents: writeCause: Workspace configuration not found or incorrectly formatted.
Solution:
- Verify
package.jsonhas aworkspacesfield (for npm/yarn/bun) - Verify
pnpm-workspace.yamlexists (for pnpm) - Check that package directories contain valid
package.jsonfiles - Enable debug logging to see detection details
Cause: Commit scope doesn't match package scope or files are in wrong directory.
Solution:
- Use correct scope in commits:
feat(package-name): description - Provide explicit
scope-package-mappingif auto-detection fails - Set
change-detection: pathto rely only on file changes - Verify package directories match workspace patterns
Cause: Commits without scope affect all packages by default.
Solution:
- Always use scoped commits:
fix(core): bug description - Set
change-detection: scopeto only use scope-based routing - Use
unified-version: trueif you want all packages to share one version
Cause: GitHub releases created with the default ${{ secrets.GITHUB_TOKEN }} do not trigger other workflows in the same repository. This is an intentional GitHub platform limitation to prevent accidental recursive workflow runs.
This affects chained automation such as:
Push to main
β release-build-flow-action creates GitHub Release
β container-build-flow-action watches release: [published]
β β Never triggered because GITHUB_TOKEN created the release
Solution: Use a Personal Access Token (PAT) or a GitHub App token instead of GITHUB_TOKEN:
- name: Create Release
uses: wgtechlabs/release-build-flow-action@v1
with:
github-token: ${{ secrets.GH_PAT }} # PAT or GitHub App tokenNote: GitHub App tokens are the recommended approach for production useβthey provide fine-grained permissions, are auditable, and don't depend on an individual user's account. See Example 6 for a full setup.
If you choose to use a PAT instead of a GitHub App token, create a fine-grained personal access token with the following minimum repository permissions:
| Permission | Access | Why it's needed |
|---|---|---|
| Contents | Read and write | Push commits (changelog updates), create tags, create releases, and read repository contents |
| Metadata | Read-only (required) | Access repository metadata (automatically included) |
Steps:
- Go to GitHub Settings β Developer settings β Personal access tokens β Fine-grained tokens
- Set a descriptive Token name (e.g.,
release-build-flow) - Choose an Expiration period
- Under Repository access, select the repositories that use this action
- Under Permissions β Repository permissions, grant:
- Contents: Read and write
- Metadata: Read-only (selected by default)
- Click Generate token and copy it
- Add the token as a repository secret named
GH_PAT:- Go to your repository β Settings β Secrets and variables β Actions
- Click New repository secret, name it
GH_PAT, and paste the token
Tip: For organization repositories, an admin may need to approve fine-grained PAT requests depending on the organization's token policy.
MIT Β© WG Technology Labs
Contributions are welcome! Please feel free to submit a Pull Request.
- Keep a Changelog - Changelog format specification
- Semantic Versioning - Version numbering scheme
- Conventional Commits - Commit message convention
Made with β€οΈ by WG Technology Labs