Skip to content

make: release workflow — notes, GH release, dry-run fixes#19

Merged
oubiwann merged 2 commits into
mainfrom
fix/release-dry-run-stdlib-only
May 8, 2026
Merged

make: release workflow — notes, GH release, dry-run fixes#19
oubiwann merged 2 commits into
mainfrom
fix/release-dry-run-stdlib-only

Conversation

@oubiwann

@oubiwann oubiwann commented May 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Improves the make release* workflow with three bug fixes and one new feature, all surfaced while preparing the v0.1.3 release.

  • Fix: make release-dry-run was broken on cascade's stdlib-only module — git diff --quiet go.mod go.sum errors with fatal: go.sum: no such path because cascade has no third-party deps, and is also fooled by stat-cache staleness after go mod tidy bumps go.mod's mtime without changing content. Switched to git status --porcelain which handles both.
  • Fix: VERSION as a CLI argument (make release VERSION=v0.1.0) was typo-prone and could mismatch the embedded internal/project/VERSION file. Now read from the file with override, so the source of truth is committed and CLI overrides are rejected.
  • Fix: make release now refuses on a dirty working tree — otherwise the build metadata embedded in the tagged binary would carry a -dirty suffix, invalidating the tag's reproducibility.
  • Feature: New make release-notes target generates a placeholder at ./workbench/release-notes-$(VERSION).md, and make release now auto-creates a GitHub release with those notes via gh release create --notes-file … after tagging.

Diff scope

1 file (Makefile), +87 / −27 across 2 commits:

  • 8f268f7 Fixed formatting. — banner spacing + moved the release banner above the version-check block (previous work)
  • ce08ed1 make: release workflow — notes, GH release, dry-run fixes — this PR's substantive work

What's new in detail

Top-of-file vars (after GIT_REMOTES)

# Release configuration
WORKBENCH = ./workbench
RELEASE_NOTES = $(WORKBENCH)/release-notes-$(VERSION).md
LAST_VERSION := $(shell git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
GH_PROJECT_URL := https://$(MODULE_PATH)

Plus override VERSION := … at line 17.

New targets

  • $(WORKBENCH)mkdir -p ./workbench
  • release-notes: $(WORKBENCH) — generates a placeholder markdown file with Overview, Details, and Change Log sections, plus a GitHub compare link from the last tag to the current VERSION. Refuses to overwrite an existing file.

Generated content for VERSION=0.1.3, last tag v0.1.2:

# v0.1.3 -- Release Notes

## Overview

TBD

## Details

TBD

## Change Log

 [v0.1.2..0.1.3](https://github.com/geomyidia/cascade/compare/v0.1.2...v0.1.3)

Updated release-dry-run

After the tidy check, reports release-notes status:

  • Present✓ Release notes found … will be used to auto-create a GitHub release during 'make release'
  • Absent⚠ No release notes at … 'make release' will only push the tag — no GitHub release will be created. Run 'make release-notes' to generate a placeholder if you want one.

Updated release

In order:

  1. VERSION readable from file (existing)
  2. Working tree clean (new) — refuses with porcelain output if not
  3. Tag v$(VERSION) doesn't already exist (existing)
  4. Confirm prompt
  5. release-dry-run (tidy + lint + test + release build)
  6. Tag and push to all GIT_REMOTES
  7. gh release create $(VERS) --notes-file $(RELEASE_NOTES) --title "Release $(VERS)" if the notes file exists; clear "skipping" notice if not.

Help text

Releasing:
  make release-dry-run  - Verify module is ready to tag (tidy + lint + test + build)
  make release-notes    - Generate placeholder release notes for the current VERSION
  make release          - Tag, push to all remotes, and (if release-notes exist) create a GitHub release

Design note: workbench/ is gitignored

Generated release notes live in ./workbench/, which is in .gitignore. That means:

  • ✓ The dirty-tree check in make release correctly ignores generated notes.
  • ✓ The GH release page becomes the canonical record for each release's notes.
  • ⚠ Release notes are not version-controlled — they live only on the maintainer's machine and on github.com.

If you'd rather have them tracked, options are: (1) add !workbench/release-notes-*.md to .gitignore, or (2) move them to docs/release-notes/. Current implementation matches the existing "workbench is local scratch" convention and the audit prompt's "out of scope" note.

Test plan

  • make help shows the new release-notes entry and updated release description
  • make release-dry-run (no notes file) — reports "⚠ No release notes" with the make release-notes hint; build + lint + test all green
  • make release-notes — generates ./workbench/release-notes-0.1.3.md with the expected format
  • make release-notes (file exists) — refuses to overwrite, exits 0 with a warning
  • make release-dry-run (notes file exists) — reports "✓ Release notes found … will be used"
  • make -n release — recipe parses cleanly through the new gh release create block and the no-notes fallback
  • Working-tree-clean check verified earlier (PR-internal: make release refused with M Makefile after the audit-doc commit)
  • Actual end-to-end make release (deferred until a clean tree + the user is ready to tag v0.1.3)

Followup

Once this lands, the v0.1.3 tag is unblocked. Suggested workflow:

make release-notes                                   # generates workbench/release-notes-0.1.3.md
$EDITOR workbench/release-notes-0.1.3.md             # fill in Overview / Details
make release-dry-run                                 # confirms notes will be used
make release                                         # tags + pushes + creates GH release

🤖 Generated with Claude Code

oubiwann and others added 2 commits May 8, 2026 10:13
Why:
- release-dry-run was broken on stdlib-only modules (cascade has no
  go.sum) and from stat-cache staleness after `go mod tidy` bumps
  mtime without changing content. `git status --porcelain` tolerates
  both: handles missing paths cleanly and is status-aware.
- VERSION as a CLI argument was typo-prone and could mismatch the
  embedded VERSION file. Reading from the file with `override` locks
  the source of truth and prevents accidental override.
- After tagging, the maintainer had to manually create each GH release.
  Auto-create via `gh release create --notes-file …` when a release
  notes file is present.
- Releasing from a dirty tree embeds `-dirty` in the build metadata,
  invalidating the tag's reproducibility. Refuse on dirty tree.

What:
- Bug fixes:
  - release-dry-run: use `git status --porcelain` instead of
    `git diff --quiet go.mod go.sum` (closes the stdlib-only failure
    and the stat-cache flap)
  - VERSION: `override` + `:=` from internal/project/VERSION
- New targets:
  - `$(WORKBENCH)` — `mkdir -p ./workbench`
  - `release-notes` — generates a placeholder at
    $(WORKBENCH)/release-notes-$(VERSION).md (no overwrite if exists)
- Updated `release-dry-run`: reports presence/absence of the release
  notes file with the corresponding "will be used" / "won't auto-
  create GH release" guidance.
- Updated `release`:
  - target-specific VERS = v$(VERSION); used everywhere a tag string
    is needed
  - VERSION-unknown guard
  - working-tree-clean refusal (new, via `git status --porcelain`)
  - tag-exists guard
  - after tag push: `gh release create` if RELEASE_NOTES exists, else
    a clear "skipping GH release" notice
- Help: lists `make release-notes` and the updated `make release`
  description.

Note: workbench/ is gitignored, so the generated release notes file
lives only on the maintainer's machine + on the GH release page. The
dirty-tree check correctly ignores the gitignored draft.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@oubiwann oubiwann merged commit 68077f0 into main May 8, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant