Skip to content

The release PR converts an Unreleased heading instead of orphaning it - #41

Merged
bdbarnett merged 1 commit into
mainfrom
housekeeping/changelog-unreleased
Sep 22, 2026
Merged

bdbarnett merged 1 commit into
mainfrom
housekeeping/changelog-unreleased

Conversation

@bdbarnett

Copy link
Copy Markdown
Contributor

Fixes #40.

reusable-prepare-release-pr.yml prepended its ## vX.Y.Z (date) section to
the top of CHANGELOG.md. Where a repository keeps a ## Unreleased block
between releases, that left the block stranded below a released version, and
the notes written for the release being cut shipped under "Unreleased" in the
published artifact.

Now the first level-2 heading decides what happens:

  • If it is ## Unreleased, that heading becomes ## vX.Y.Z (date) and the
    generated git log bullets are appended under the notes already written.
  • Otherwise a new section is inserted above the first level-2 heading
    rather than at the top of the file. That also fixes a second case nobody had
    hit yet: audiocomponents opens with a # Changelog title and a paragraph,
    and the old code would have pushed both below the release section.

How it was proved

The logic has to live inline in the workflow — a reusable workflow runs
against the caller's checkout, so it has no copy of this repository's
scripts/. tests/test_prepare_release_pr.py therefore lifts the exact
heredoc out of the YAML and runs it, the same trick
tests/test_synchronize_mip_package.py already uses for the lockfile step.
Eight fixtures: the reported bug, the title-and-preamble shape, no changelog
at all, no Unreleased block, an empty one, no commits since the tag, and an
Unreleased heading that sits below a release (left alone — only the first
level-2 heading is the block being released).

$ python3 -m unittest discover -s tests -v
Ran 21 tests in 1.069s

OK

The old shell run against the same fixture, to show the test is not passing
vacuously:

## v0.5.2 (2026-09-22)

- Second commit
- First commit

## Unreleased            <- stranded

- A note written between releases

## v0.5.1 (2026-09-21)

actionlint is clean on every workflow, every workflow still parses as YAML,
and ruff check scripts/ tests/ passes.

I also swept every CHANGELOG.md in the workspace for headings already
orphaned by past releases — the thing the issue asked to check. There are
none left; the two in audiodsp were the ones fixed by hand on the v0.5.1
release branch.

A repository that accumulates notes under `## Unreleased` between releases
means that block: the release being cut IS those notes. The step prepended a
new `## vX.Y.Z` section above it instead, which left `## Unreleased` stranded
below a released version and filed the release's own notes under "Unreleased"
in the published CHANGELOG.md. audiodsp had two such headings by the time
v0.5.1 was cut.

Now the first level-2 heading decides. If it is `## Unreleased`, that heading
becomes the version and the generated git log joins the section under the
notes already written. Otherwise the new section is inserted above the first
level-2 heading, which also stops a `# Changelog` title and its preamble --
audiocomponents' shape -- being pushed below the release.

The logic has to live in the workflow, because a reusable workflow runs
against the caller's checkout and has no copy of this repository's scripts/.
So tests/test_prepare_release_pr.py lifts the heredoc out of the YAML and runs
it over fixture changelogs, the same way the mip synchronize tests do.

Closes #40
@bdbarnett
bdbarnett merged commit 29f432c into main Sep 22, 2026
5 checks passed
@bdbarnett
bdbarnett deleted the housekeeping/changelog-unreleased branch September 22, 2026 02:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

The release PR prepends its version heading above an existing ## Unreleased, orphaning it

1 participant