Skip to content

release.yml: create a GitHub Release from the CHANGELOG section on tag push - #4

Merged
nathanschepers merged 1 commit into
mainfrom
release-github-release-object
Jul 23, 2026
Merged

release.yml: create a GitHub Release from the CHANGELOG section on tag push#4
nathanschepers merged 1 commit into
mainfrom
release-github-release-object

Conversation

@nathanschepers

Copy link
Copy Markdown
Member

Adds GitHub Release creation to the templated release workflow.

What it does

A new release job runs after the publish jobs succeed. It derives the version from the pushed tag (stripping the leading v; house convention is ## <version> headings, so v0.1.0 maps to ## 0.1.0), extracts that section from CHANGELOG.md, and runs gh release create "$TAG" --verify-tag --title "$TAG" --notes-file <extracted> with GH_TOKEN: ${{ github.token }}.

The section extraction is POSIX awk: it prints the body between the matching ## <version> heading and the next ## heading, and handles the last-section-in-file case (body runs to EOF).

Fail-on-missing-section gate

The job fails if CHANGELOG.md has no section for the version, and equally if CHANGELOG.md is absent. This is a deliberate release-discipline gate, not a skip.

Permissions and needs

  • Top-level workflow permissions stay contents: read; only the release job gets contents: write.
  • The job needs: the build job(s) plus whichever publish jobs the answer set produces, so no release object is created when a publish job fails. Resolved combinations (native × pypi × web):
    • library + pypi: [build, check-version, publish]
    • library + pypi + web: [build, check-version, publish, image]
    • library, no pypi: [build, check-version]
    • native + pypi: [wheels, sdist, check-version, publish]

CHANGELOG scaffold

The template did not scaffold a CHANGELOG.md. Added template/CHANGELOG.md.jinja with an initial ## 0.0.1.dev0 section matching the hardcoded pyproject version, so a freshly generated project passes the gate on its first release.

Docs

Documented the release-object behavior in README.md (Release pipeline) and template/SETUP.md.jinja (release step), in the existing register.

Validation

Rendered the template with copier for library, web-service, and no-pypi answer sets; yaml.safe_load on the generated release.yml for all eight flag combinations; every needs entry references a real job. Exercised the extraction shell for middle, date-suffixed, last, and missing sections plus a missing file.

Tracker: workspace#66 (private).

🤖 Generated with Claude Code

…g push
Add an unconditional release job that runs after the publish jobs succeed.
It extracts the section for the released version from CHANGELOG.md (tags
carry a leading v, headings do not: v0.1.0 -> ## 0.1.0) and runs
gh release create with those lines as the notes. A missing section or a
missing CHANGELOG.md fails the job.
The job needs whichever build and publish jobs the answer set produces
(wheels+sdist or build, plus publish and/or image), so no release object
is created when a publish job fails. It is the only job with
contents: write; the workflow default stays contents: read.
Scaffold template/CHANGELOG.md.jinja with an initial ## 0.0.1.dev0 section
matching the pyproject version so a generated project passes the gate on
its first release. Document the release-object step in README.md and
SETUP.md.jinja.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@nathanschepers
nathanschepers merged commit cc28f0a into mainJul 23, 2026
6 checks passed
@nathanschepers
nathanschepers deleted the release-github-release-object branch July 23, 2026 13:05
Sign up for freeto 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

@nathanschepers