2026-03-21 14:14:52 +00:00
2026-03-21 13:35:24 +00:00

vociferate

Main Validation Prepare Release Do Release Coverage

vociferate is an Æther release orchestration tool written in Go for repositories that want changelog-driven versioning, automated release preparation, and repeatable tag publication.

It started as release preparation glue, but it now covers the full release path: recommend the next semantic version, promote Unreleased changelog entries, commit and tag a release, and publish release notes/assets from the tagged revision.

Use In Other Repositories

Vociferate ships composite actions covering release preparation, release publication, coverage badge publishing, and pull request decoration. Release tags now exist; pin all action and reusable-workflow references to the same released tag (for example, @v1.0.2) instead of @main.

For agentic coding partners, see AGENTS.md for a direct integration playbook, selection matrix, and copy-paste workflow patterns.

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: https://git.hrafn.xyz/aether/vociferate/prepare@v1.0.2
        with:
          version: ${{ inputs.version }}

  publish:
    needs: prepare
    uses: https://git.hrafn.xyz/aether/vociferate/.gitea/workflows/do-release.yml@v1.0.2
    with:
      tag: ${{ needs.prepare.outputs.version }}
    secrets: inherit

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: https://git.hrafn.xyz/aether/vociferate/prepare@v1.0.2
  with:
    version-file: internal/myapp/version/version.go
    version-pattern: 'const Version = "([^"]+)"'
    git-add-files: CHANGELOG.md internal/myapp/version/version.go

prepare uses github.token internally for authenticated fetch/push operations, so no token input is required.

publish — create release with changelog notes

name: Do Release

on:
  workflow_dispatch:
    inputs:
      tag:
        description: Semantic version to publish (for example v1.2.3)
        required: true

jobs:
  release:
    uses: https://git.hrafn.xyz/aether/vociferate/.gitea/workflows/do-release.yml@v1.0.2
    with:
      tag: ${{ inputs.tag }}
    secrets: inherit

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 reusable Do Release workflow now runs preflight checks before publish to fail fast when the release token is missing or lacks API access. On self-hosted Gitea, set secrets.GITEA_TOKEN; on GitHub, secrets.GITHUB_TOKEN is used automatically.

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

- id: publish
  uses: https://git.hrafn.xyz/aether/vociferate/publish@v1.0.2

- 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"

coverage-badge - publish coverage report and badge

Run your coverage tests first, then call the action to generate coverage.html, coverage-badge.svg, and coverage-summary.json, upload them to S3-compatible storage, and emit output URLs.

- name: Run tests with coverage
  run: go test -covermode=atomic -coverprofile=coverage.out ./...

- id: coverage
  uses: https://git.hrafn.xyz/aether/vociferate/coverage-badge@v1.0.2
  with:
    artefact-bucket-name: ${{ vars.ARTEFACT_BUCKET_NAME }}
    artefact-bucket-endpoint: ${{ vars.ARTEFACT_BUCKET_ENDPONT }}

- name: Print coverage links
  run: |
    echo "Report: ${{ steps.coverage.outputs.report-url }}"
    echo "Badge: ${{ steps.coverage.outputs.badge-url }}"

decorate-pr - annotate pull requests with coverage and changes

Decorate pull requests with coverage badges, coverage percentages, and unreleased changelog entries. The action creates a new comment or updates an existing one on each run.

decorate-pr also runs a preflight comment API check so workflows fail early with a clear message when token permissions are insufficient.

Basic Usage

- name: Run tests with coverage
  run: go test -covermode=atomic -coverprofile=coverage.out ./...

- id: coverage
  uses: https://git.hrafn.xyz/aether/vociferate/coverage-badge@v1.0.2
  with:
    artefact-bucket-name: ${{ vars.ARTEFACT_BUCKET_NAME }}
    artefact-bucket-endpoint: ${{ vars.ARTEFACT_BUCKET_ENDPONT }}

- name: Decorate pull request
  if: github.event_name == 'pull_request'
  uses: https://git.hrafn.xyz/aether/vociferate/decorate-pr@v1.0.2
  with:
    coverage-percentage: ${{ steps.coverage.outputs.total }}
    badge-url: ${{ steps.coverage.outputs.badge-url }}

Changelog Gate (Strict Mode)

Enable changelog validation to enforce that code changes include Unreleased changelog entries. The gate fails the workflow in strict mode, or warns in soft mode:

- name: Decorate pull request with changelog gate
  if: github.event_name == 'pull_request'
  uses: https://git.hrafn.xyz/aether/vociferate/decorate-pr@v1.0.2
  with:
    coverage-percentage: ${{ steps.coverage.outputs.total }}
    badge-url: ${{ steps.coverage.outputs.badge-url }}
    enable-changelog-gate: true
    changelog-gate-mode: strict
    changelog-gate-required-for: "code,behavior,security,workflow,tooling"
    changelog-gate-allow-docs-only: true
    changelog-gate-docs-globs: "docs/**,**.md,**.txt,**.rst"
    changelog-gate-skip-labels: "skip-changelog"

The gate automatically:

  • Parses diffs to detect docs-only PRs (skips requirement for doc-only changes)
  • Counts Unreleased additions using section-aware parsing (ignores edits outside the section)
  • Checks PR labels for skip exemptions (for example, skip-changelog)
  • Outputs decision status and remediation guidance in the PR comment
  • Handles both strict (fail) and soft (warn) modes

Decision outputs enable downstream workflow logic:

- name: Decorate PR and check gate
  id: decorate
  if: github.event_name == 'pull_request'
  uses: https://git.hrafn.xyz/aether/vociferate/decorate-pr@v1.0.2
  with:
    coverage-percentage: ${{ steps.coverage.outputs.total }}
    badge-url: ${{ steps.coverage.outputs.badge-url }}
    enable-changelog-gate: true
    changelog-gate-mode: soft

- name: Gate decision
  run: |
    echo "Gate passed: ${{ steps.decorate.outputs.gate-passed }}"
    echo "Is docs-only PR: ${{ steps.decorate.outputs.docs-only }}"
    echo "Unreleased additions: ${{ steps.decorate.outputs.unreleased-additions-count }}"
    if [[ "${{ steps.decorate.outputs.gate-passed }}" == "false" ]]; then
      echo "Gate failure reason: ${{ steps.decorate.outputs.gate-failure-reason }}"
    fi

The action automatically finds existing vociferate comments by their marker and updates them instead of creating duplicates. This keeps PR timelines clean while keeping review information current.

Why The Name

vociferate (verb): to cry out loudly or forcefully.

Long story short: vociferating into the Æther is synonymous screaming into the void.

If updating changelogs and documenting releases has ever felt like that, this tool is for you.

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.

During prepare, vociferate can normalize changelog heading links when it can determine the repository URL (from CI environment variables or origin git remote). Actions automatically forward ${{ vars.VOCIFERATE_REPOSITORY_URL }} to VOCIFERATE_REPOSITORY_URL, which has highest priority for changelog link generation. This value should be the server/base URL only, for example https://git.hrafn.xyz or https://git.hrafn.xyz/git, not a full repository URL.

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.
  • Prepare Release then calls Do Release directly via reusable workflow_call with the resolved tag.
  • Do Release reads the matching changelog section from that tagged revision, creates or updates the release, and uploads prebuilt binaries.

Calling Do Release directly avoids environments where tag pushes from workflow tokens do not emit a follow-up workflow trigger event.

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.

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%