Skip to content

chore: add release preflight validation and concurrency protection #560

@marcusburghardt

Description

@marcusburghardt

Summary

A comparison of our release workflow with the preflight pattern used in
unbound-force/gaze (PR unbound-force/gaze#100) and
unbound-force/unbound-force identified several improvement opportunities
to make the release process more robust.

Current State

The release workflow is a single workflow_dispatch job that runs GoReleaser
immediately on dispatch. It relies on branch protection to ensure code quality
before code reaches main. This works well but leaves room for additional
safety nets.

Improvement Opportunities

1. No CI verification

The workflow trusts branch protection to ensure CI passed on the commit being
released. Adding an explicit query to the GitHub Checks API for required check
run conclusions would provide defense in depth — catching edge cases where
branch protection is temporarily adjusted or bypassed by an admin.

2. No concurrency protection

No concurrency: group is defined. If two workflow_dispatch runs are
triggered in quick succession, they could race. A concurrency group would
serialize releases safely.

3. No semver ordering check

Nothing prevents releasing v1.1.0 after v1.2.0 has already been released,
which could confuse downstream consumers.

4. No unreleased commits guard

Nothing prevents triggering a release that produces the same artifacts as the
previous tag (no new commits). A simple git rev-list --count check would
catch this early.

5. No tag creation by workflow

The workflow uses GORELEASER_CURRENT_TAG to name the release but does not
create a git tag. The tag may or may not exist in git history depending on
whether the maintainer also pushed one separately. Having the workflow create
an annotated tag (idempotently) after validation would ensure consistency.

Suggested Improvements

  • Concurrency group (release-${{ github.ref }}, cancel-in-progress: false)
  • CI verification via GitHub Checks API (query required check run conclusions on HEAD)
  • Semver ordering check against latest existing tag
  • Unreleased commits guard (git rev-list --count)
  • Annotated tag creation by the workflow (idempotent)

Reference

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions