Skip to content

Releases are done by hand, so a refused commit can still be followed by a tag and a push #41

Closed

Description

@jetomev

What happened (2026-10-01, releasing v0.1.6)

The release was done by hand, as every mindForge release has been: commit, version bump, annotated tag, push. The scrub hook refused the docs commit, correctly (a private word had gone into a TODO line). But the tag and push were on the next line of the same command. A here-document ends a command line, so the && chain stopped at the refused commit and the next line ran anyway.

v0.1.6 went public on the wrong commit, the code commit whose VERSION still said 0.1.5, for a few minutes. No release page existed yet and mindForge is not packaged anywhere, so nobody could have installed it. With the maintainer's OK the tag was deleted and put on the right commit.

Why a script, not more care

The order of a release is the same every time and checkable every time. A refused commit should make a wrong tag impossible, not merely unlikely. Asking for more care is the "better reminder" this method's own doctrine rejects: when a rule keeps breaking, change the shape of the work.

The fix: scripts/release.sh <version>

Runs under set -euo pipefail and refuses, with a reason and before anything is tagged or pushed, when:

  • the version is not X.Y.Z
  • the working tree has uncommitted or untracked changes
  • the branch is not main, or it is behind or has diverged from origin/main
  • VERSION in bin/mindforge is not the version being released
  • docs/CHANGELOG.md has no ## vX.Y.Z entry
  • the tag already exists, here or on GitHub
  • bash testing/run-tests.sh does not pass

Only then does it make the annotated tag (its message is the changelog entry) and push main and the tag. The GitHub Release page, closing issues and the Vault entry stay human steps; the script prints them as a checklist at the end. Its output goes to logs/ with a -latest link and an OK last line.

Tests, in the failing direction: each refusal is triggered on a sandbox repo and must leave no tag, locally or on the remote; the one good run must tag the commit whose VERSION matches.

Activity

  1. jetomev commented on Oct 1, 2026

    @jetomev
    OwnerAuthor

    Fixed on main in 629d029; it ships in the next release (listed under Unreleased in the changelog).

    scripts/release.sh X.Y.Z runs under set -euo pipefail and refuses, before anything is tagged or pushed, on: a version that is not X.Y.Z, any uncommitted or untracked file, not being on main, main behind or diverged from origin/main, VERSION in bin/mindforge not matching, no ## vX.Y.Z changelog entry, a tag that already exists here or on origin, or failing tests. Then it makes the annotated tag (its message is the changelog entry), pushes main and the tag, and prints the steps that stay human: the Release page, closing issues, About, Vault/memory/TODO. Each run is logged to logs/ with a -latest link and an OK last line.

    Tests: 14 new checks (160 total). Each refusal is triggered on a throwaway repo and must leave no tag locally or on its remote; the good run must end OK, put the tag on origin, on the commit whose VERSION matches, with the changelog entry (and only that entry) as its message. Proven in the failing direction: three planted copies of the script, each missing one guard (version match, clean tree, tests), were each caught by the suite.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions