brel
v0.12.0
Published
better-releases cli tool
Readme
brel
brel is a CLI that scaffolds and runs the better-releases workflow.
Install
Choose the install path that fits how you want to use brel:
Install from crates.io:
cargo install brelInstall with Homebrew:
brew install better-releases/tap/brelRun the published npm package once with npx:
npx brel@latest --helpInstall the latest prebuilt binary with the release shell script:
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/better-releases/brel/releases/latest/download/brel-installer.sh | shDownload a platform archive directly from the latest release page.
Install from this checkout while developing locally:
cargo install --path .Quick Start
Create a brel.toml for the most basic release-pr setup:
# GitHub is the default provider, but keeping it explicit makes the file clearer.
provider = "github"
# Release PRs target this branch.
default_branch = "main"
[release_pr.version_updates]
# Update the root package version in package.json on each release PR.
"package.json" = ["version"]Then validate the config and generate the managed workflow:
brel validate
brel init --yesCommands
brel initgenerates a managed GitHub Actions workflow or GitLab CI pipeline.brel changelogcomputes the next version and runs the configured changelog provider.brel release-prcomputes the next version, updates configured files, commits, pushes, and creates/updates a release PR.brel tagcreates and pushes a release tag, either from explicit--tag/--targetargs or from provider merge event data.brel next-versioncomputes the next releasable version and prints it as plain SemVer.brel validatevalidates a config file and prints warnings for ignored keys.
Command Prerequisites
gitmust be available.- With
provider = "github",brel release-prrequiresgh(GitHub CLI). - With
provider = "github",brel release-prrequires a GitHub token inGH_TOKENorGITHUB_TOKEN.- The workflow generated by
brel initsetsGH_TOKEN: ${{ github.token }}automatically.
- The workflow generated by
- With
provider = "gitlab",brel release-prand GitLab event-mode tagging requireBREL_GITLAB_TOKEN.- In GitLab CI, add
BREL_GITLAB_TOKENas a masked CI/CD variable with API and repository write access. - GitLab CI provides the project and commit metadata through predefined
CI_*variables.
- In GitLab CI, add
brel changelogrequires the configured provider runtime:git-cliffforprovider = "git-cliff"npxforprovider = "changelogen"
- The workflow generated by
brel initinstalls the needed changelog runtime before runningbrel changelog.
Config File
brel discovers config in this order:
--config <path>(when provided)brel.toml.brel.toml
Use brel validate to check that an existing config file parses and satisfies the current schema before running other commands.
Minimal release-pr config
# GitHub is the default provider, but keeping it explicit makes the file clearer.
provider = "github"
# Release PRs target this branch.
default_branch = "main"
[release_pr.version_updates]
# Update the root package version in package.json on each release PR.
"package.json" = ["version"]Full release_pr config
[release_pr.version_updates]
"package.json" = ["version"]
"Cargo.toml" = ["package.version"]
"release.yaml" = ["release.version"]
[release_pr.format_overrides]
"Cargo.toml" = "toml"
[release_pr]
release_branch_pattern = "brel/release/v{{version}}"
pr_template_file = ".github/brel/release-pr-body.hbs"
[release_pr.changelog]
enabled = true
provider = "git-cliff"
output_file = "CHANGELOG.md"
[release_pr.changelog.changelogen]
version = "0.6.2"
[release_pr.tagging]
enabled = false
tag_template = "v{version}"
[release_pr.commit_author]
name = "brel[bot]"
email = "brel[bot]@users.noreply.github.com"How Versioning Works
When you run brel release-pr:
- It finds the highest stable SemVer tag that matches
release_pr.tagging.tag_template(defaultv{version}). - If no valid tag exists, it uses
0.0.0. - It scans commits since that tag (or all commits when no tag exists).
- It picks one bump level from Conventional Commit signals:
- major:
BREAKING CHANGEin body/footer, or!in the type/scope prefix. - minor:
feat: ... - patch:
fix: ...
- major:
- If no releasable commits are found, it exits successfully with no changes.
brel next-version uses the same versioning rules:
- when releasable commits exist, it prints the next version (for example
1.2.3) - when none exist, it prints nothing and exits successfully
How File Updates Work
release_pr.version_updatesmaps exact repo-relative file paths to selector paths.- Selector syntax:
- key:
version - nested key:
package.version - index selector:
packages[0].version - filter selector:
package[name=brel].version
- key:
- Supported file formats:
- inferred from extension (
.json,.toml,.yaml,.yml) - or forced via
release_pr.format_overrides
- inferred from extension (
- Updates are fail-fast. The command errors if:
- a file is missing,
- format cannot be determined,
- parse fails,
- a selector is invalid,
- a selector matches no values,
- a selector uses index/filter on a non-array segment,
- a matched value is not a string,
- a YAML matched value uses block scalar syntax (
|or>).
- Match behavior:
- all values matched by a selector are updated
- selectors do not create missing keys/paths
Example selectors:
- JSON:
"package.json" = ["version", "tooling.release.version"] - JSON with filter:
"package.json" = ["package[name=brel].version"] - TOML:
"Cargo.toml" = ["package.version"] - YAML:
"release.yaml" = ["release.version", "packages[name=brel].version"] - Cargo.lock (explicit format override required):
[release_pr.version_updates]
"Cargo.lock" = ["package[name=brel].version"]
[release_pr.format_overrides]
"Cargo.lock" = "toml"Changelog Generation
brel changelogcomputes the next release using the same versioning rules asbrel next-version.- If changelog generation is disabled, or if no releasable commits exist,
brel changelogexits successfully without changing files. - Configure changelog behavior with
[release_pr.changelog]:enabled(defaulttrue)provider(default"git-cliff", also supports"changelogen")output_file(default"CHANGELOG.md")
- Configure changelogen-specific behavior with
[release_pr.changelog.changelogen]:version(default"0.6.2"; omitted or empty uses the default; explicit values must be SemVer)
git-cliffbehavior:- runs
git-cliff --config cliff.toml --unreleased --tag <rendered-tag> --prepend <output_file> - the generated workflow installs
git-cliffwithtaiki-e/install-action@git-cliff
- runs
changelogenbehavior:- runs
npx --yes changelogen@<configured-version> --to HEAD -r <next-version> --output <output_file> - the generated workflow sets up Node with
actions/setup-node@v6 - does not ask changelogen to bump versions, commit, tag, push, publish, or create GitHub releases
- runs
- If changelog generation is enabled,
brel release-prstagesoutput_filein the release commit when that file exists. - Enable changelogen:
[release_pr.changelog]
provider = "changelogen"
[release_pr.changelog.changelogen]
version = "0.6.2"- Disable changelog generation:
[release_pr.changelog]
enabled = falsebrel initdoes not create or manage changelog tool config files. Keepcliff.tomlin your repository for customgit-cliffrules, or use changelogen's supported config files (changelog.config.*,.changelogrc, orpackage.json'schangelogfield) for custom changelogen behavior.
Branch / Commit / PR Behavior
- Default branch pattern:
brel/release/v{{version}}- Only
{{version}}is supported as a token.
- Only
release_pr.tagging.tag_templatecontrols rendered release tags (defaultv{version}).tag_templateaccepts{version}and legacy{{version}}(normalized to{version}).tag_templatemust include exactly one version token.
- Commit message:
chore(release): <rendered-tag> - PR title:
Release <rendered-tag> - Commit author defaults to:
name = "brel[bot]"email = "brel[bot]@users.noreply.github.com"
- Push strategy:
--force-with-leasetoorigin.
For PRs/MRs:
- On GitHub,
brelusesgh pr listto find an open managed release PR. - On GitLab,
breluses GitLab's REST API to find an open managed release MR. - If found on the current rendered release branch, it updates that PR/MR.
- If found on a stale release branch, it creates or updates the current rendered-branch PR/MR first, closes the stale PR/MR, and best-effort deletes the stale remote branch.
- If not found, it creates a new PR/MR.
Tagging on Merge
- Optional config:
[release_pr.tagging] enabled = true(defaultfalse). - Tag format config:
[release_pr.tagging] tag_template = "v{version}"(default shown). - When enabled, the generated GitHub workflow listens for merged pull requests into the configured default branch.
- The generated GitLab pipeline runs
brel tagon default-branch push pipelines and uses GitLab's commit-to-MR API to detect managed merged release MRs. - If the merged PR/MR is managed by
breland titledRelease <rendered-tag>,brel tagcreates the release tag. brel tagvalidates the tag againsttag_template, creates it at the merge commit when missing, and pushesrefs/tags/<tag>toorigin.- For GitHub, create repository secret
BREL_TAG_PUSH_TOKENbefore using tagging-on-merge.- Use a PAT that can push tags to the repository (fine-grained PAT with
Contents: Read and write). - This is required because pushes done with
GITHUB_TOKENdo not trigger downstream tag-push workflows.
- Use a PAT that can push tags to the repository (fine-grained PAT with
- For GitLab, the generated pipeline uses
BREL_GITLAB_TOKENfor API calls and git pushes. brel initprints the relevant token requirement for the configured provider.
Manual tag creation:
brel tag --tag v1.2.3 --target <git-rev>Manual mode can be used even when tagging-on-merge is disabled. If --target is omitted, HEAD is tagged.
PR Body Templates
If release_pr.pr_template_file is set, brel renders that Handlebars template.
Available variables:
versiontagbase_branchrelease_branchcommits(array of{ sha_short, subject })
Important: include this marker in your template so future runs can detect and update the same PR:
<!-- managed-by: brel -->If rendering fails, brel release-pr exits with an error.
Typical Usage
Generate workflow once:
brel init --yesRun release locally:
git-cliff --version # or ensure npx is available when using changelogen
brel changelog
GH_TOKEN=... brel release-prFor GitLab local runs, provide the same metadata normally supplied by GitLab CI:
BREL_GITLAB_TOKEN=... CI_API_V4_URL=https://gitlab.com/api/v4 CI_PROJECT_ID=123 brel release-prRun with explicit config:
brel changelog --config ./configs/release.toml
brel release-pr --config ./configs/release.tomlValidate config:
brel validatePreview the next release version:
brel next-versionCreate a tag manually:
brel tag --tag v1.2.3 --target HEAD