Micheal Wilkinson c859a3fccb
All checks were successful
Push Validation / validate (push) Successful in 54s
ci: split prepare and publish into separate release pipelines
- Remove publish steps (release creation, binary build/upload) from the
  Prepare Release workflow; it now stops after committing and pushing the
  tag.
- Add Do Release workflow triggered on v*.*.* tag pushes; reads release
  notes from the tagged changelog section, creates or updates the release,
  builds linux/amd64 and linux/arm64 binaries, uploads assets, then
  smoke-tests both binaries in a follow-on validate job.
- Remove the standalone Action Validation workflow; binary validation now
  runs as a second job in Do Release after the release job succeeds, using
  the exact tag and version just published.
- Update README to document the two-workflow release model and add split
  prepare/publish usage examples for both the composite action and the
  reusable workflows.
- Update changelog unreleased section to reflect the new pipeline split
  and corrected artifact scope (linux/amd64 and linux/arm64 only).
2026-03-20 19:55:03 +00:00
2026-03-20 19:23:43 +00:00

vociferate

A reusable release preparation tool for Go repositories.

Build

Build with just:

just go-build

Or directly with Go:

go build -o dist/vociferate ./cmd/vociferate

Usage

Prepare release files:

go run ./cmd/vociferate --version v1.2.3 --date 2026-03-20 --root .

In the provided workflow and composite action, version is optional. When it is omitted, vociferate computes and uses the recommended next version automatically.

Recommend next release tag from changelog content:

go run ./cmd/vociferate --recommend --root .

Flags

  • --version semantic version to release (with or without leading v).
  • --date release date in YYYY-MM-DD format.
  • --recommend print recommended next tag based on ## [Unreleased].
  • --root repository root directory.
  • --version-file path to version source file relative to --root.
  • --version-pattern regexp with exactly one capture group for version value.
  • --changelog path to changelog file relative to --root.

Defaults:

  • version-file: release-version
  • version-pattern: ^\s*([^\r\n]+)\s*$
  • changelog: changelog.md

By default, vociferate reads and writes the release version as the sole content of a root-level release-version file. Repositories that keep the version inside source code should pass explicit version-file and version-pattern values.

Testing

just go-test

Release Flow

Releases use two workflows:

  • Prepare Release runs on demand, updates release-version and changelog.md, commits those changes back to main, and pushes the release tag.
  • Do Release runs from the pushed tag, reads the matching changelog section from that tagged revision, creates or updates the release, and uploads prebuilt binaries.

This split matters because release notes must be generated from the tagged commit that already contains the promoted changelog section.

Release Artifacts

The tag-driven Do Release workflow publishes prebuilt vociferate binaries for:

  • linux/amd64
  • linux/arm64

It also uploads checksums.txt for integrity verification. If a release already exists for the same tag, the workflow updates its release notes and replaces matching asset filenames so reruns stay in sync.

Reuse In Other Repositories

You can reuse vociferate in two ways.

Use the composite action directly in your prepare workflow:

- name: Prepare release files
  uses: git.hrafn.xyz/aether/vociferate@v1.0.0
  with:
    version-file: internal/myapp/version/version.go
    version-pattern: 'const Version = "([^"]+)"'
    changelog: changelog.md

Set version only when you want to override the recommended version. Pin the composite action to a released tag. It downloads a prebuilt Linux binary from vociferate releases and caches it on the runner, so it does not require installing Go. If your repository uses the default plain-text release-version file, you can omit version-file and version-pattern entirely.

A complete release setup should also split preparation from publication. For example:

name: Prepare Release

on:
  workflow_dispatch:
    inputs:
      version:
        description: Optional semantic version override.
        required: false

jobs:
  prepare:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Prepare release files
        id: prepare
        uses: git.hrafn.xyz/aether/vociferate@v1.0.0
        with:
          version: ${{ inputs.version }}

      - name: Commit and push prepared release
        run: |
          set -euo pipefail
          tag="${{ steps.prepare.outputs.version }}"
          git config user.name "gitea-actions[bot]"
          git config user.email "gitea-actions[bot]@users.noreply.local"
          git add changelog.md release-version
          git commit -m "release: prepare ${tag}"
          git tag "$tag"
          git push origin HEAD
          git push origin "$tag"

Then use a separate tag workflow to publish the release from the tagged revision:

name: Do Release

on:
  push:
    tags:
      - "v*.*.*"

jobs:
  release:
    uses: aether/vociferate/.gitea/workflows/do-release.yml@main
    secrets: inherit

Call the reusable prepare workflow:

name: Prepare Release

on:
  workflow_dispatch:
    inputs:
      version:
        description: Optional semantic version override.
        required: false

jobs:
  release:
    uses: aether/vociferate/.gitea/workflows/prepare-release.yml@main
    with:
      version: ${{ inputs.version }}
    secrets: inherit

And publish from tags with:

name: Do Release

on:
  push:
    tags:
      - "v*.*.*"

jobs:
  release:
    uses: aether/vociferate/.gitea/workflows/do-release.yml@main
    secrets: inherit
Description
No description provided
Readme GPL-3.0 1.9 MiB
v1.2.0 Latest
2026-03-21 23:15:26 +00:00
Languages
Go 96.8%
Shell 2.7%
Just 0.5%