release-tool manages releases from change files in .changes/. It computes the next semver, writes release.json, can generate markdown release notes, and creates the corresponding git tag.
Install
Fastest: download a release binary
Pick the binary for your platform from GitHub Releases.
Common installs:
Linux x86_64
curl -Lo /usr/local/bin/release-tool \
https://github.com/OpenShock/release-tool/releases/latest/download/release-tool-linux-amd64
chmod +x /usr/local/bin/release-tool
macOS Apple Silicon
curl -Lo /usr/local/bin/release-tool \
https://github.com/OpenShock/release-tool/releases/latest/download/release-tool-darwin-arm64
chmod +x /usr/local/bin/release-tool
macOS Intel
curl -Lo /usr/local/bin/release-tool \
https://github.com/OpenShock/release-tool/releases/latest/download/release-tool-darwin-amd64
chmod +x /usr/local/bin/release-tool
Windows PowerShell
Invoke-WebRequest `
-Uri https://github.com/OpenShock/release-tool/releases/latest/download/release-tool-windows-amd64.exe `
-OutFile $env:USERPROFILE\bin\release-tool.exe
If you use a different architecture, download the matching asset from Releases.
Alternative: install with Go
go install github.com/OpenShock/release-tool@latest
If release-tool is not found afterwards, add your Go bin directory to PATH:
export PATH="$(go env GOPATH)/bin:$PATH"
Check it works
release-tool --help
Workflow
- Initialise a repo once:
release-tool init
- Add change files as work lands:
release-tool new
Or non-interactively:
release-tool new "Add support for X" --type minor --categories api,cli
- Inspect pending changes:
release-tool status
- Cut a release:
release-tool stable
stable:
- Computes the next version from pending
.changes/*.md
- Writes
release.json
- Optionally writes markdown notes via
--notes
- Prepends a new entry to
CHANGELOG.md
- Removes consumed change files
- Commits the changelog/update and creates a stable tag
For prereleases, use:
release-tool --prerelease-label beta rc
release-tool --prerelease-label develop --git-sha rc --allow-empty
rc does not consume .changes/ files or update CHANGELOG.md; it only writes release data and creates a prerelease tag.
---
type: minor # major | minor | patch
breaking: false # optional; major defaults to true
categories: [api] # optional
pr: 123 # optional; see below
---
Title shown in changelog
Optional extended body shown in the changelog.
## Release Note
Plain-language note for end users. Included in `release.json`, not in `CHANGELOG.md`.
## Notices
- warning: something users must know before upgrading
- info: optional migration or rollout note
pr is tri-state:
- absent: the PR number is derived from git history (the PR that introduced the file)
- integer (
pr: 123): used verbatim, no derivation
pr: null: suppresses the PR link entirely
Notice levels must be one of info, warning, or error, and each line must be
- level: message. Invalid levels or malformed lines fail validation (caught by status).
Special files in .changes/:
README.md: local format reference created by release-tool init
_headline.md: optional markdown shown at the top of the generated changelog entry
config.json: optional repo config
Example .changes/config.json:
{
"tag_prefix": "v",
"categories": ["api", "firmware", "frontend"]
}
categories, when present, is an allowlist: change files declaring a category
outside the list fail validation. When omitted, any category string is accepted.
Contributors & PR enrichment
When the gh CLI is available and authenticated (GH_TOKEN), stable and rc
enrich the release with GitHub data:
- PR numbers are derived for change files that don't pin one (see
pr above).
- Contributors — every commit author since the previous tag is recorded in
release.json (contributors), and the generated notes gain a ### Contributors
footer thanking them, excluding repo maintainers (admin/maintain collaborators)
and *[bot] accounts.
Both require the checkout to include tags and history (fetch-depth: 0) so the
previous tag is a resolvable ref. Maintainer detection needs a token with push
access; without it, the footer simply thanks everyone. Enrichment is skipped
under --dry-run.
Common flags
Global flags available to stable, rc, status, init, and new:
--dry-run: preview without writing files, committing, or tagging
--output <path>: where to write release.json (default release.json)
--notes <path>: write markdown release notes
--prerelease-label <label>: prerelease label such as alpha, beta, rc, or develop
--git-sha: append +g<sha> build metadata to prerelease tags
--root <path>: operate on another repository root
GitHub Action
The composite action wraps the CLI and exposes four modes:
- uses: OpenShock/release-tool@v1
with:
mode: stable # stable | beta | develop | status
dry-run: false
output: release.json
notes-output: release-notes.md
prerelease-label: beta # optional override for beta/develop
git-sha: false # append +g<sha> to prerelease tags
Mode behavior:
stable: consumes pending change files and updates CHANGELOG.md
beta: creates prerelease tags from changes since the last beta or stable tag
develop: creates prerelease tags from changes since the last develop, beta, or stable tag, always with git SHA metadata and allowing empty cuts
status: validates pending changes and prints the next version without creating a tag (useful as a PR check)
Action outputs:
tag: created tag, empty when skipped
prerelease: true for prerelease tags
skip: true when no release was created