# vociferate [![Main Validation](https://git.hrafn.xyz/aether/vociferate/actions/workflows/push-validation.yml/badge.svg?branch=main&event=push)](https://git.hrafn.xyz/aether/vociferate/actions/runs/latest?workflow=push-validation.yml&branch=main&event=push) [![Prepare Release](https://git.hrafn.xyz/aether/vociferate/actions/workflows/prepare-release.yml/badge.svg?event=workflow_dispatch)](https://git.hrafn.xyz/aether/vociferate/actions/runs/latest?workflow=prepare-release.yml) [![Do Release](https://git.hrafn.xyz/aether/vociferate/actions/workflows/do-release.yml/badge.svg?event=push)](https://git.hrafn.xyz/aether/vociferate/actions/runs/latest?workflow=do-release.yml) [![Coverage](https://s3.hrafn.xyz/aether-workflow-report-artefacts/vociferate/branch/main/coverage-badge.svg)](https://s3.hrafn.xyz/aether-workflow-report-artefacts/vociferate/branch/main/coverage.html) `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.1`) instead of `@main`. For agentic coding partners, see [`AGENTS.md`](AGENTS.md) for a direct integration playbook, selection matrix, and copy-paste workflow patterns. ### `prepare` — update files, commit, and push tag ```yaml 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.1 with: version: ${{ inputs.version }} publish: needs: prepare uses: aether/vociferate/.gitea/workflows/do-release.yml@v1.0.1 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`: ```yaml - uses: git.hrafn.xyz/aether/vociferate/prepare@v1.0.1 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 ```yaml name: Do Release on: workflow_dispatch: inputs: tag: description: Semantic version to publish (for example v1.2.3) required: true jobs: release: uses: aether/vociferate/.gitea/workflows/do-release.yml@v1.0.1 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: ```yaml - id: publish uses: git.hrafn.xyz/aether/vociferate/publish@v1.0.1 - 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. ```yaml - name: Run tests with coverage run: go test -covermode=atomic -coverprofile=coverage.out ./... - id: coverage uses: git.hrafn.xyz/aether/vociferate/coverage-badge@v1.0.1 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. ```yaml - name: Run tests with coverage run: go test -covermode=atomic -coverprofile=coverage.out ./... - id: coverage uses: git.hrafn.xyz/aether/vociferate/coverage-badge@v1.0.1 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: git.hrafn.xyz/aether/vociferate/decorate-pr@v1.0.1 with: coverage-percentage: ${{ steps.coverage.outputs.total }} badge-url: ${{ steps.coverage.outputs.badge-url }} ``` 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: ```bash just go-build ``` Or directly with Go: ```bash go build -o dist/vociferate ./cmd/vociferate ``` ## Usage Prepare release files: ```bash 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: ```bash 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 ```bash 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.