Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 27 additions & 27 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@
# form can't pre-fill a value computed from repo state) and is only
# validated to be greater than the current VERSION_STRING. The CHANGELOG
# heading is just "## vX.Y.Z (date)" — no separate title to type in; the
# Unreleased section's own content (used verbatim as the GitHub Release
# body too) already says what the release is about. The workflow refuses
# to overwrite an existing release/tag.
# Unreleased section's own content already says what the release is about.
# The GitHub Release body is never that content verbatim, though — see the
# "Extract changelog section for this version" step below for what
# actually gets published, and CLAUDE.md's "Changelog policy" for the
# entry convention it depends on. The workflow refuses to overwrite an
# existing release/tag.
name: Release

on:
Expand Down Expand Up @@ -144,23 +147,25 @@ jobs:
- name: Build
run: make

# Release notes come from CHANGELOG.md: the section for the version
# just cut above (from its "## vX.Y.Z ..." heading up to the next
# one). A short section (a quick fix, a handful of entries) is used
# in full, same as always. A long one (a big batch of work, like
# this repo's own v2.4.0) is abridged to just its "### " entry
# headings — each one is already written as a one-line summary by
# this file's own convention — plus a link to the matching
# CHANGELOG.md section for the full detail, rather than dumping
# hundreds of lines into the Release page. Either way, a link back
# to CHANGELOG.md is always included.
# Release notes are always just the significant-change highlights for
# this version, never the full changelog section. This project's
# CHANGELOG.md convention (see CLAUDE.md's "Changelog policy") is
# that every significant change is its own "### <Type>: <one-line
# summary>" heading, with any elaboration living in the paragraph/
# bullets underneath — so extraction is a straight pull of those
# heading lines, with no length-based judgment call, ever. A section
# written with no "### " headings at all falls back to publishing the
# whole section as-is instead — a structural fallback for a section
# with nothing to extract, not a size cutoff.
#
# The link's #fragment reproduces GitHub's own heading-anchor slug
# algorithm (lowercase; drop every character that isn't a-z, 0-9,
# space, underscore, or hyphen — this is what removes the periods
# inside a version number; then turn spaces into hyphens) — verified
# against this repo's actual rendered CHANGELOG.md anchors.
- name: Extract changelog section for this version
# Either way a link back to this file's matching section is always
# appended. The link's #fragment reproduces GitHub's own
# heading-anchor slug algorithm (lowercase; drop every character
# that isn't a-z, 0-9, space, underscore, or hyphen — this is what
# removes the periods inside a version number, not replaces them;
# then turn spaces into hyphens) — verified against this repo's
# actual rendered CHANGELOG.md anchors.
- name: Extract changelog highlights
id: changelog
env:
RELEASE_TAG: ${{ steps.version.outputs.tag }}
Expand All @@ -181,21 +186,16 @@ jobs:
SLUG=$(printf '%s' "$HEADING_TEXT" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9 _-]//g' | tr ' ' '-')
CHANGELOG_LINK="https://github.com/${GITHUB_REPOSITORY}/blob/main/CHANGELOG.md#${SLUG}"

LINE_COUNT=$(printf '%s\n' "$BODY" | wc -l)
HIGHLIGHTS=$(printf '%s\n' "$BODY" | grep '^### ' | sed -E 's/^###[[:space:]]*/- /')

{
if [ "$LINE_COUNT" -gt 40 ] && [ -n "$HIGHLIGHTS" ]; then
printf '%s\n' "$HEADING_LINE"
echo
if [ -n "$HIGHLIGHTS" ]; then
printf '%s\n' "$HIGHLIGHTS"
echo
echo "**Full changelog:** see [CHANGELOG.md]($CHANGELOG_LINK) for the complete details."
else
printf '%s\n' "$BODY"
echo
echo "**Full changelog:** [CHANGELOG.md]($CHANGELOG_LINK)"
fi
echo
echo "See [CHANGELOG.md]($CHANGELOG_LINK) for the full write-up."
} > /tmp/release_notes.md

echo "notes_file=/tmp/release_notes.md" >> "$GITHUB_OUTPUT"
Expand Down
34 changes: 19 additions & 15 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ release is a manual, deliberate step: trigger the `Release` GitHub Actions
workflow (`.github/workflows/release.yml`) with just a version number —
it renames this file's `## Unreleased` section to `## vX.Y.Z (date)`,
bumps `VERSION_STRING` to match, builds, and publishes the result as a
GitHub Release using that section verbatim as the release notes. Keep
the `## vX.Y.Z` heading format exact.
GitHub Release using highlights extracted from that section (see
`CLAUDE.md`'s "Changelog policy" for the entry convention this depends
on — always just this section's `### ` headings plus a link back here,
never the full write-up). Keep the `## vX.Y.Z` heading format exact.

**Policy:** every change gets a `CHANGELOG.md` entry under a `## Unreleased`
section at the top of this file when it's made (create the section if it
Expand All @@ -16,19 +18,21 @@ accurate at all times instead of being reconstructed from memory later.

## Unreleased

### Changed: release notes stay short for a big changelog entry
`v2.4.0`'s own GitHub Release ended up as a ~200-line wall of text, since
`.github/workflows/release.yml` always dumped the full `## Unreleased`
section verbatim into the Release body. Now: a short section (a quick
fix, a handful of entries — 40 lines or fewer) still gets used in full,
same as before; a long one is abridged to just its `### ` entry headings
(each already written as a one-line summary by this file's own
convention) as a bullet list. Either way, the Release body now always
ends with a link back to this file's matching dated section for the full
detail — computed to match GitHub's actual heading-anchor slug algorithm
(verified against this repo's own real rendered anchors, e.g. `v2.4.0
(2026-08-19)` → `#v240-2026-08-19` — GitHub drops the periods from the
version number, it doesn't turn them into hyphens).
### Changed: release notes always show only the changelog's headings, never the full section
`.github/workflows/release.yml`'s "Extract changelog section for this
version" step used to hand the whole cut section to
`softprops/action-gh-release` verbatim for a short entry (40 lines or
fewer) and only fell back to a headings-only highlight list past that
size. It now always uses just the `### ` headings (each already a
one-line summary by this file's convention) as the Release body, with no
line-count judgment call — a version written with no headings at all
falls back to the full section instead, a structural fallback rather
than a size one. Either way a link back to this file's matching dated
section is always appended. Same change applied to CoverDex's and
ThePatientGamerHelper's `release.yml`, and each project's `CLAUDE.md`
now documents the bullet/heading convention its own release notes depend
on, so the highlights are always ready in this file rather than computed
by trimming or reflowing prose at release time.

## v2.4.0 (2026-08-19)

Expand Down
18 changes: 15 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,9 +190,8 @@ Actions tab when the user actually asks to cut a release. It validates the
input, renames `CHANGELOG.md`'s `## Unreleased` section to
`## vX.Y.Z (date)`, bumps `VERSION_STRING` in `source/types.h` to match,
commits and pushes that bump to `main`, builds, and publishes the
`.3dsx`/`.smdh` as a GitHub Release using that section verbatim as the
release notes — there's no separate title to type in; the Unreleased
section's own content is the release notes.
`.3dsx`/`.smdh` as a GitHub Release using highlights extracted from that
section (see "Changelog policy" below).

## Changelog policy

Expand All @@ -202,6 +201,19 @@ not deferred until a release is cut. Don't rename it to a `## vX.Y.Z`
heading or bump `VERSION_STRING` yourself — that rename/bump is what the
`Release` workflow above does, on request, as one atomic step.

**Entry convention:** every significant change is its own `### <Type>:
<one-line summary>` heading (`Fix:`/`Added:`/`Changed:`/`Removed:` are
this file's established types) — write the heading itself as a
complete, skimmable summary, with any further detail in a paragraph (and
optional sub-bullets) underneath. This isn't just for readability:
`.github/workflows/release.yml`'s "Extract changelog highlights" step
publishes exactly those `### ` heading lines as the GitHub Release
body — always, for every release, never the full section text and never
gated by a length cutoff — followed by a link back to this file's
matching section for the full write-up. A sloppy or vague heading ships
straight to the Release page as-is, so write it as if it were the only
sentence a reader sees.

## Code conventions

- No comments explaining *what* code does — only the non-obvious *why*
Expand Down
Loading