Release Workflows
First release
When no tags match the version pattern, explicitly choose the first version:
flopha next-version --initial-version 0.2.0 --pattern 'mobile@{semver}' --create --push
# Creates mobile@0.2.0 and pushes it to origin
The initial version is a bare MAJOR.MINOR.PATCH, with no prefix, suffix, build metadata, or leading zeros. Each component must fit an unsigned 32-bit integer. The pattern must contain all three placeholders (or {semver}) and supplies the tag name. --source branch also supports --initial-version with a branch pattern such as release/{semver}.
For the config-driven release pipeline, set the version under [version]:
[version]
pattern = "mobile@{semver}"
initial_version = "0.2.0"
[[manifest]]
path = "package.json"
type = "npm"
flopha release --dry-run # preview mobile@0.2.0 without writing files
flopha release --prepare # update manifests to 0.2.0 for review
# After committing the prepared files:
flopha release --require-version-match --dry-run
release --initial-version 0.3.0 overrides the configured initial version. Neither auto = true nor an explicit increment bumps the initial version. Once a stable tag matches the pattern, normal bump behavior resumes, so the setting can stay in the config. Without a matching version and an initial version, both commands fail with instructions for supplying one. First-release changelogs include all commits reachable from HEAD.
For an initial pre-release, add --pre beta to next-version, or pre = "beta" under [version]. This produces mobile@0.2.0-beta.1 and manifest version 0.2.0-beta.1. Existing pre-release tags advance the channel counter. Keep the same initial version for subsequent pre-releases; omit the channel to create the first stable mobile@0.2.0 tag.
Conventional commits
Use --auto to infer the next bump from commit messages since the latest version:
flopha next-version --auto
Built-in behavior:
BREAKING CHANGEorfeat!:style commits produce a major bump.feat:style commits produce a minor bump.- Any other history falls back to patch.
Custom bump rules
If your team uses a different convention, replace the built-in rules with --rule:
flopha next-version \
--auto \
--rule 'major:BREAKING CHANGE' \
--rule 'minor:^feature'
Each rule uses the format level:regex, where level is major, minor, or patch.
Branch-based release streams
Some teams publish from branches instead of tags. In that case, use --source branch consistently:
flopha last-version --source branch --pattern "release/{major}.{minor}.{patch}"
flopha next-version --source branch --pattern "release/{major}.{minor}.{patch}"
flopha next-version --source branch --pattern "release/{major}.{minor}.{patch}" --create
Auditing release history
Use log to confirm what has already been published:
flopha log --pattern "desktop@{semver}" --limit 20
The log output includes the version, the release date, and the number of commits since the previous matching version.
Using flopha in CI
All flopha commands output plain text by default and --format json for machine consumption, making them easy to integrate into any CI pipeline.
Minimal release pipeline (shell)
# 1. Compute the next version without creating it yet
NEXT=$(flopha next-version --auto --format json | jq -r '.version')
# 2. Generate changelog headed with the upcoming version
flopha changelog --title "Changes in $NEXT" --output CHANGELOG.md
# 3. Commit the updated changelog
git add CHANGELOG.md
git commit -m "chore: release $NEXT"
# 4. Tag and push
flopha next-version --auto --create
git push origin "$NEXT"
--title stamps the upcoming version into the changelog heading before the tag exists. Use --to only when limiting the changelog to an existing tag or ref.
GitHub Actions — using the action
The sjquant/flopha action wraps the common tag-and-release flow with a single step.
name: Release
on:
push:
branches: [main]
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # full history so flopha can walk commits
- name: Tag and release
uses: sjquant/flopha@v1
with:
auto: true
create-release: true
changelog: true # generate changelog and use it as the release body
GitHub Actions — full changelog pipeline
For full control over the changelog before tagging:
name: Release
on:
push:
branches: [main]
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install flopha
run: |
curl -fsSL https://raw.githubusercontent.com/sjquant/flopha/main/scripts/install.sh | sh
echo "$HOME/.flopha/bin" >> $GITHUB_PATH
- name: Compute next version
id: version
run: echo "tag=$(flopha next-version --auto --format json | jq -r '.version')" >> $GITHUB_OUTPUT
- name: Generate changelog
run: flopha changelog --title "Changes in ${{ steps.version.outputs.tag }}" --output CHANGELOG.md
- name: Commit changelog
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add CHANGELOG.md
git diff --staged --quiet || git commit -m "chore: release ${{ steps.version.outputs.tag }}"
git push
- name: Create tag and release
uses: sjquant/flopha@v1
with:
auto: true
create-release: true
Prepare a release PR
Separate version changes from publication when they need PR review:
flopha release --prepare
# Review and commit the modified manifests, then open a PR.
flopha release --require-version-match --dry-run # validate the PR without publishing
flopha release --require-version-match # publish after merge
--prepare uses the rules in flopha.toml to update manifests, including the local Cargo package's lock entry. It leaves changes unstaged and does not commit, tag, push, or create a GitHub Release. --prepare --dry-run previews the plan without writing files. Both preparation and verification require at least one configured manifest target.
--require-version-match fails if any manifest would need an update to match the calculated version. On success it releases the committed version without creating a version commit, including from a detached CI checkout. Add --dry-run for PR validation without credentials or publication. The two options cannot be combined.
If new commits change the required bump after preparation, update the version branch from its base branch, run --prepare again, and commit the corrected versions. If the version PR already merged, use a follow-up PR. Use a neutral commit message for the version PR so it does not itself trigger a major or minor bump.
This repository follows that flow: a version PR changes Cargo.toml and Cargo.lock; merge triggers a draft release only when the Cargo version is unpublished. Existing build jobs build the tag and upload binaries before publishing. Rerun the original failed workflow if a draft was created but the build or upload failed.
flopha release in GitHub Actions
With a checked-in flopha.toml, flopha release handles the bump, manifest sync, tag, changelog, and GitHub Release in one step. It's safe to run on every push and to re-run: with no new commits it does nothing, and on an already-tagged commit it only finishes what an interrupted run left undone (pushing the tag, creating the GitHub Release).
name: Release
on:
push:
branches: [main]
concurrency: release # back-to-back pushes would race for the same tag
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # full history and tags to detect the bump
- name: Install flopha
run: |
curl -fsSL https://raw.githubusercontent.com/sjquant/flopha/main/scripts/install.sh | sh
echo "$HOME/.flopha/bin" >> $GITHUB_PATH
- name: Release
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
flopha release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # used to create the GitHub Release
- Pushes made with the default
GITHUB_TOKENdon't trigger new workflow runs, so the version-bump commit won't start another release. - If
mainrequires pull requests, the version-bump commit from[[manifest]]targets is rejected. Either let the workflow's token bypass the rule, or drop[[manifest]]soreleaseonly pushes a tag. - With
[[manifest]]targets, HEAD must be on a branch, not detached.actions/checkoutdoes this forpushevents; forpull_requestor SHA checkouts, rungit checkout -B <branch>first.
Scripting with JSON output
Every command supports --format json for safe, jq-parseable output:
# Extract version string
flopha next-version --auto --format json | jq -r '.version'
# List recent releases as JSON array
flopha log --limit 5 --format json
# Generate changelog as structured data for a historical range
flopha changelog --from "v1.9.0" --to "v2.0.0" --format json | jq '.groups[].title'
Reusable release script
A self-contained script suitable for any CI:
#!/usr/bin/env bash
set -euo pipefail
NEXT=$(flopha next-version --auto --format json | jq -r '.version')
echo "Releasing $NEXT"
flopha changelog --title "Changes in $NEXT" --output CHANGELOG.md
git add CHANGELOG.md
git diff --staged --quiet || git commit -m "chore: release $NEXT"
git push
flopha next-version --auto --create
git push origin "$NEXT"