Description: relctl is a provider-agnostic release management CLI for CI/CD pipelines. It supports three versioning schemes – SemVer (branch-prefix driven), SemVer via Conventional Commits (commit-message driven), and CalVer – and integrates with GitHub, GitHub Enterprise, GitLab, and Jenkins.
- Technology stack: Go, Cobra CLI
- Status: Stable
- Supported environments:
- GitHub & GitHub Enterprise (GitHub Actions)
- GitLab (GitLab CI)
- Jenkins Pipelines
- Versioning schemes: SemVer (branch-prefix driven) · Conventional Commits (commit-message driven SemVer) · CalVer (date-based, git-tag driven)
Download the latest release
and add it to your PATH, or use the
layer87-labs/relctl-action in GitHub Actions.
relctl derives the SemVer bump level from the source branch name:
| Branch prefix | Bump |
|---|---|
bugfix/, fix/, patch/, dependabot/ |
Patch |
feature/, feat/, minor/ |
Minor |
major/ |
Major |
relctl derives the SemVer bump level from the commit messages between the last published release (not draft, not prerelease) and the target commit, following the Conventional Commits specification:
| Rule | Bump |
|---|---|
any commit with ! after type/scope (feat!:, fix(api)!:), or a BREAKING CHANGE: / BREAKING-CHANGE: footer in the body |
Major |
otherwise, at least one feat commit |
Minor |
otherwise, at least one commit of a recognised Conventional Commits type (fix, perf, refactor, docs, style, test, chore, ci, build, revert) |
Patch |
| no commit matches any of the above | No release – relctl release create fails with a clear error |
The commit range and messages come exclusively from the local Git history – no SCM API call
for the commits themselves, fully provider-agnostic. Finding the last published release still
uses the SCM API, the same way the existing --hotfix flag does.
Prerequisite: the repository must be checked out with full history (
fetch-depth: 0), same as CalVer.
Squash merges only: relctl walks the first-parent chain from HEAD down to the last published release. With a squash-merge workflow that chain is the sequence of PR title / squash commit messages, one per merge, each carrying its type directly – this is the supported case. If relctl finds a commit with more than one parent (a real merge commit) in that range, it fails with a clear error (
ErrMergeCommitInRange) instead of guessing – a merge commit means the first-parent chain no longer represents "one commit per PR", and silently walking past it could understate the bump. Repositories that bring in multi-commit PRs via a merge commit (rather than squashing) are not supported by this scheme.
--version as an explicit override always takes precedence, exactly like for SemVer and CalVer.
Format: YYYY.MM.DD.N – e.g. 2026.06.01.3
YYYY.MM.DD– current date in UTCN– monotonically increasing counter per day, 1-based
N is calculated exclusively from local Git tags – no SCM API call, fully provider-agnostic.
relctl lists all tags matching YYYY.MM.DD.* for today and sets N to max(N) + 1 (or 1 if no tag exists yet).
Prerequisite: the repository must be checked out with full tag history (
fetch-depth: 0). This is already a general relctl requirement.
Place a .relctl.yaml in your repository root to set project-wide defaults:
version_scheme: calver # semver (default) | calver | conventional-commits
default_branch: mainThe file is optional. When absent, relctl behaves exactly as before (SemVer, main).
Priority: --version-scheme flag > .relctl.yaml > built-in default (SemVer)
| Flag | Scope | Description |
|---|---|---|
--config <path> |
relctl, release |
Override config file path (default: .relctl.yaml) |
--version-scheme <scheme> |
release |
semver, calver or conventional-commits; overrides config file |
# After merging a PR – relctl reads the PR branch and GitHub API
relctl release create
relctl release publish --release-id "$RELCTL_RELEASE_ID" --asset "file=dist/binary"relctl release create --version-scheme conventional-commits --dry-run
# Would create new release with version: 1.3.0# .relctl.yaml
version_scheme: calver# No branch prefix or PR context required
relctl release create
# → e.g. 2026.06.01.1
relctl release publish --release-id "$RELCTL_RELEASE_ID" --asset "file=dist/binary"relctl release create --version-scheme calver
# → e.g. 2026.06.01.1
# Second release on the same day (git tag 2026.06.01.1 already exists)
relctl release create --version-scheme calver
# → 2026.06.01.2relctl release create --version-scheme calver --dry-run
# Would create new release with version: 2026.06.01.1- uses: actions/checkout@v4
with:
fetch-depth: 0 # required: full tag history for N calculation
- name: Create CalVer release
run: relctl release create --version-scheme calver
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}More examples are available in the examples section of the documentation.
See the Q&A section.
Please file an issue in this repository's Issue Tracker.
relctl is licensed under the Apache License, Version 2.0. See LICENSE.