Skip to main content

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 CHANGE or feat!: 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_TOKEN don't trigger new workflow runs, so the version-bump commit won't start another release.
  • If main requires pull requests, the version-bump commit from [[manifest]] targets is rejected. Either let the workflow's token bypass the rule, or drop [[manifest]] so release only pushes a tag.
  • With [[manifest]] targets, HEAD must be on a branch, not detached. actions/checkout does this for push events; for pull_request or SHA checkouts, run git 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"