Micheal Wilkinson 647d8cf76f feat: add prepare and publish composite actions
Add two focused subdirectory composite actions:

- prepare/action.yml: downloads the vociferate binary, runs it to update
  changelog and release-version, then commits, tags, and pushes — replacing
  the boilerplate git steps consumers previously had to write inline.

- publish/action.yml: extracts the matching changelog section and creates or
  updates the Gitea/GitHub release. Outputs release-id, tag, and version so
  consumers can upload their own assets after it runs.

Simplify the vociferate workflows to use ./prepare and ./publish directly,
validating both actions in the self-release pipeline.

Update README to show the clean two-action usage pattern.
2026-03-20 20:27:22 +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

When no --version-file flag is provided, vociferate derives the current version from the most recent released section heading in the changelog (## [x.y.z] - ...). If no prior releases exist, it defaults to 0.0.0 and recommends v1.0.0 as the first tag.

When running --version, the release-version file is created automatically if it does not exist, so new repositories do not need to pre-seed it.

Repositories that keep the version inside source code should pass explicit --version-file and --version-pattern values; in that case the version file is used directly instead of the changelog.

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

Vociferate ships two composite actions that together cover the full release flow. Pin both to the same released tag.

prepare — update files, commit, and push tag

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

      - uses: git.hrafn.xyz/aether/vociferate/prepare@v1.0.0
        with:
          version: ${{ inputs.version }}
          token: ${{ secrets.GITHUB_TOKEN }}

Downloads a prebuilt vociferate binary, runs it to update changelog.md and release-version, then commits those changes to the default branch and pushes the release tag. Does not require Go on the runner.

For repositories that embed the version inside source code, pass version-file and version-pattern:

- uses: git.hrafn.xyz/aether/vociferate/prepare@v1.0.0
  with:
    version-file: internal/myapp/version/version.go
    version-pattern: 'const Version = "([^"]+)"'
    git-add-files: changelog.md internal/myapp/version/version.go
    token: ${{ secrets.GITHUB_TOKEN }}

publish — create release with changelog notes

name: Do Release

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

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: git.hrafn.xyz/aether/vociferate/publish@v1.0.0
        with:
          token: ${{ secrets.GITHUB_TOKEN }}

Reads the matching section from changelog.md and creates or updates the Gitea/GitHub release with those notes. The version input is optional — when omitted it is derived from the current tag ref automatically.

The publish action outputs release-id so you can upload additional release assets after it runs:

- id: publish
  uses: git.hrafn.xyz/aether/vociferate/publish@v1.0.0
  with:
    token: ${{ secrets.GITHUB_TOKEN }}

- name: Upload my binary
  run: |
    curl --fail-with-body -X POST \
      -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
      -H "Content-Type: application/octet-stream" \
      "${{ github.api_url }}/repos/${{ github.repository }}/releases/${{ steps.publish.outputs.release-id }}/assets?name=myapp" \
      --data-binary "@dist/myapp"
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%