Panrelease
Panrelease is a versatile release automation tool that manages version bumping, changelog updates, and Git operations across multiple package managers. It supports Cargo (Rust), npm (Node.js), Maven, and Gradle (Java) projects in a unified workflow.
Features
- Multi-Language Support - Unified version management for Cargo, npm, Maven, and Gradle projects
- Semantic Versioning - Automatic major, minor, patch, and post-release version bumping
- Changelog Automation - Automatically updates CHANGELOG.md following Keep a Changelog format
- Changelog from Commits - Auto-populate changelog sections from commit messages (Conventional Commits, Gitmoji)
- Git Integration - Commits version changes, creates tags, and supports GPG signing
- Multi-Module Projects - Manages monorepos with multiple packages
- Custom Hooks - Execute arbitrary commands after releases (build, test, deploy)
- Cross-Platform - Available as native CLI binary and npm package (via WebAssembly)
- Configurable Tag Templates - Customize Git tag naming (e.g.,
v{{version}})
Table of Contents
- Installation
- Quick Start
- Configuration
- Usage
- Package Manager Support
- Multi-Module Projects
- Hooks
- Changelog from Commits
- Strict Mode
- Git Integration
- Documentation
- Contributing
- License
Installation
Using Cargo (Rust)
Using npm/yarn/pnpm (Node.js)
# npm
# yarn
# pnpm
From Source
The binary will be available at target/release/panrelease.
Quick Start
- Initialize your project by creating a
.panproject.tomlfile in your project root:
[]
= "Git"
[]
= "."
= "Cargo" # or "Npm", "Maven", "Gradle"
= true
- Create a release with a version bump:
# Patch release (1.0.0 -> 1.0.1)
# Minor release (1.0.0 -> 1.1.0)
# Major release (1.0.0 -> 2.0.0)
# Set explicit version
That's it! Panrelease will:
- Update version in your package manifest (Cargo.toml, package.json, pom.xml, etc.)
- Update CHANGELOG.md with the new version and date
- Commit the changes
- Create a Git tag
Configuration
Panrelease is configured via a .panproject.toml file in your project root.
Basic Configuration
[]
= "Git"
= false # Require GPG-signed commits
= "{{version}}" # Git tag format (e.g., "v{{version}}" -> "v1.0.0")
[]
= "."
= "Cargo" # Cargo | Npm | Maven | Gradle
= true # Designates primary module for version detection
Configuration Options
| Section | Field | Type | Description |
|---|---|---|---|
vcs |
software |
string | Version control system (Git) |
vcs |
force_sign |
bool | Require GPG-signed commits (default: false) |
vcs |
tag_template |
string | Git tag template (default: {{version}}) |
vcs.strict |
mainline |
string | Mainline branch name for strict mode validation |
modules.<name> |
path |
string | Path to module relative to project root |
modules.<name> |
packageManager |
string | Package manager: Cargo, Npm, Maven, Gradle |
modules.<name> |
main |
bool | Mark as primary module for version extraction |
changelog |
from_commits |
bool | Enable changelog population from commit messages (default: false) |
changelog |
commit_format |
string | Commit format: auto, conventional, gitmoji (default: auto) |
changelog |
include_scope |
bool | Include scope in changelog entries (default: true) |
changelog |
include_unmatched |
bool | Include non-matching commits in "Other" section (default: false) |
For detailed configuration options, see docs/CONFIGURATION.md.
Usage
Command Line Interface
Bump Types
| Type | Description | Example |
|---|---|---|
major |
Increment major version | 1.2.3 -> 2.0.0 |
minor |
Increment minor version | 1.2.3 -> 1.3.0 |
patch |
Increment patch version | 1.2.3 -> 1.2.4 |
post |
Create post-release with build metadata | 1.2.3 -> 1.2.3+feat.r1 |
X.Y.Z |
Set explicit version | 1.2.3 -> 2.0.0 |
Options
-h, --help Print help information
-V, --version Print version information
Environment Variables
| Variable | Description |
|---|---|
RUST_LOG |
Set log level (error, warn, info, debug, trace) |
Examples
# Standard patch release
# Minor release with debug logging
RUST_LOG=debug
# Set specific version
# Post-release for feature branch
Package Manager Support
Cargo (Rust)
Updates Cargo.toml and runs cargo check to update Cargo.lock.
[]
= "."
= "Cargo"
= true
npm (Node.js)
Updates package.json and automatically detects/updates the appropriate lockfile (package-lock.json, yarn.lock, or pnpm-lock.yaml).
[]
= "."
= "Npm"
= true
Maven (Java)
Updates pom.xml, supporting both direct version fields and property-based versions.
[]
= "."
= "Maven"
= true
Gradle (Java/Kotlin)
Updates gradle.properties file.
[]
= "."
= "Gradle"
= true
Multi-Module Projects
Panrelease excels at managing monorepos with multiple packages:
[]
= "Git"
= "v{{version}}"
[]
= "packages/core"
= "Cargo"
= true # Primary module determines project version
[]
= "packages/cli"
= "Cargo"
[]
= "packages/web"
= "Npm"
[]
= "packages/server"
= "Maven"
All modules are updated simultaneously during a release.
Hooks
Execute custom commands after releases using hooks:
[]
= "."
= "Cargo"
= true
[]
= ["cargo", "build", "--release"]
= ["cargo", "test"]
= ["cargo", "publish"]
Hooks are executed in the order they are defined.
Changelog from Commits
Panrelease can automatically populate your CHANGELOG.md with entries derived from commit messages. When enabled, it reads commits since the last version tag, parses them according to a configurable commit format, and maps them into Keep a Changelog sections.
Enabling Changelog from Commits
Add a [changelog] section to your .panproject.toml:
[]
= true
= "auto" # "auto" | "conventional" | "gitmoji"
= true # include scope in entries (default: true)
= false # add non-matching commits to "Other" section (default: false)
Supported Commit Formats
Conventional Commits
Follows the Conventional Commits specification: type(scope): description
| Commit Type | Changelog Section |
|---|---|
feat |
Added |
fix |
Fixed |
refactor, perf |
Changed |
deprecate |
Deprecated |
security |
Security |
docs, chore, ci, build, style, test |
Ignored |
Breaking changes (indicated by ! after the type or BREAKING CHANGE: in the body) are placed in the Changed section with a [BREAKING] prefix.
feat(auth): add OAuth2 support -> ### Added - (auth) Add OAuth2 support
fix: resolve timeout error -> ### Fixed - Resolve timeout error
feat!: remove legacy API -> ### Changed - [BREAKING] Remove legacy API
Gitmoji
Supports Gitmoji shortcodes and unicode emoji: :emoji: description
| Emoji | Changelog Section |
|---|---|
:sparkles: |
Added |
:bug: |
Fixed |
:recycle:, :zap: |
Changed |
:wastebasket: |
Deprecated |
:fire: |
Removed |
:lock: |
Security |
:boom: |
Changed (breaking) |
:memo:, :wrench:, :construction_worker:, :green_heart:, :white_check_mark:, :pencil2: |
Ignored |
Auto Mode (Default)
When commit_format = "auto", Panrelease analyzes all commits since the last tag and selects the single format (Conventional Commits or Gitmoji) that matches the most commits. On a tie, Conventional Commits wins. This ensures consistent formatting within a single release.
Smart Merging
If the ## [Unreleased] section already contains manually written entries, Panrelease preserves them and only adds new entries from commits that are not already represented. It uses git blame to determine which commit introduced each existing entry, preventing duplicates. New entries are interleaved with existing ones by commit date, with the most recent entries appearing first.
Examples
Given these commits since the last tag:
feat(auth): add OAuth2 support
fix: resolve crash on empty input
docs: update API reference
chore: update dependencies
Panrelease generates:
-
-
The docs and chore commits are ignored as they are not relevant for a user-facing changelog.
Strict Mode
Strict mode is an opt-in feature that enforces branch-aware release validation. When enabled, Panrelease checks which branch you are on, restricts what kind of release is allowed, and automatically infers the build metadata slug from the branch name.
Enabling Strict Mode
Add a [vcs.strict] section to your .panproject.toml:
[]
= "Git"
[]
= "main" # your mainline branch name (e.g., "main", "master")
Branch Classification
Strict mode classifies the current branch into one of three kinds:
| Branch Pattern | Kind | Example |
|---|---|---|
Matches mainline exactly |
Mainline | main |
feat/* or feature/* |
Feature | feat/user-registration |
hotfix/* or fix/* |
Hotfix | fix/timeout-error |
Any other branch name is rejected with an error.
Release Rules
Strict mode enforces different rules depending on the branch kind:
Mainline branches can only produce clean releases (major, minor, patch). Post-releases are not allowed from mainline.
# On main branch:
Feature and hotfix branches can only produce post-releases. The build metadata slug is automatically derived from the branch name.
# On feat/user-registration:
Slug Inference
The branch name after the prefix is sanitized into a slug used as build metadata:
- Non-alphanumeric characters are replaced with hyphens
- Consecutive hyphens are collapsed
- Leading/trailing hyphens are removed
- Hotfix branches get a
fix-prefix in the slug
| Branch | Inferred Slug |
|---|---|
feat/user-registration |
user-registration |
feature/hello@.-world |
hello-world |
hotfix/npe-fix |
fix-npe-fix |
fix/timeout |
fix-timeout |
Additional Validations
When releasing from a feature or hotfix branch, strict mode also verifies:
- The version base (major.minor.patch) matches the latest tagged version reachable from the merge-base with mainline
- The mainline version at the branch point is a clean version (not a post-release)
- The build metadata slug matches the expected slug for the current branch
- Releases from detached HEAD are not allowed
If any check fails, Panrelease prints a descriptive error message with a suggested fix (e.g., rebase to latest mainline).
Git Integration
Automatic Operations
During a release, Panrelease automatically:
- Verifies the staging area is clean
- Updates version in package manifests
- Updates CHANGELOG.md
- Executes post-release hooks
- Commits all changes with the version as the commit message
- Creates a Git tag based on
tag_template
GPG Signing
Enable GPG-signed commits and tags:
[]
= "Git"
= true
Tag Templates
Customize Git tag naming:
[]
= "v{{version}}" # v1.0.0
# or
= "release-{{version}}" # release-1.0.0
# or
= "{{version}}" # 1.0.0 (default)
Documentation
- Architecture Overview - Technical design and code structure
- Configuration Guide - Detailed configuration reference
- Contributing Guidelines - How to contribute
- Security Policy - Reporting vulnerabilities
- Changelog - Release history
Requirements
- Git - Required for version control operations
- Rust 1.70+ (for building from source)
- Package manager CLI (optional):
cargofor Rust projectsnpm/yarn/pnpmfor Node.js projectsmvnfor Maven projects (optional, only for hooks)gradlefor Gradle projects (optional, only for hooks)
Contributing
Contributions are welcome! Please read our Contributing Guidelines before submitting a pull request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Acknowledgments
Made with care by dghilardi