Skip to content

ci(release): auto-create GitHub Release after PyPI publish#27

Merged
amavashev merged 1 commit into
mainfrom
ci/auto-create-github-release
May 7, 2026
Merged

ci(release): auto-create GitHub Release after PyPI publish#27
amavashev merged 1 commit into
mainfrom
ci/auto-create-github-release

Conversation

@amavashev
Copy link
Copy Markdown
Contributor

Summary

Adds a create-release job to python-publish.yml that runs after publish-to-pypi succeeds and creates a GitHub Release with body extracted from the corresponding CHANGELOG.md section.

Eliminates the manual gh release create step every release. The recent v0.2.1 release exposed this gap — PyPI got the new package but no GitHub Release was created automatically; the release was backfilled by hand.

How it works

  1. Tag push (v*) triggers the workflow as before — buildpublish-to-pypi.
  2. New: create-release runs after PyPI publish succeeds (only on tag push, not on manual workflow_dispatch).
  3. Extracts the CHANGELOG section for the version using a portable awk script (string functions, no regex escape issues across awk variants).
  4. Calls softprops/action-gh-release@v3.0.0 with the extracted body.

Mirrors the same fix shipped in cycles-client-python PR #57

Same pattern, same action SHAs, same awk script. Tested locally on this repo's CHANGELOG.md:

Scenario Result
v0.2.1 (matches CHANGELOG entry) Clean extraction — body contains just the section between ## [0.2.1] and ## [0.2.0], no heading bleed
v9.9.9 (no matching CHANGELOG entry) Falls back to "Release v9.9.9. See commit history for changes." — does not fail the job

Edge cases handled

  • Missing CHANGELOG entry → fallback body, warning log line, job succeeds.
  • Prerelease versions (v0.3.0-rc.1) → auto-detected via contains(github.ref_name, '-'), marked as prerelease in GitHub.
  • Manual workflow_dispatchcreate-release skipped (only runs on tag push).

Permissions

  • Default contents: read preserved at workflow level.
  • contents: write granted only on the create-release job.

Action SHAs (pinned)

  • softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda (v3.0.0)
  • actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd (v6, matches existing job)

Test plan

  • Merge.
  • Verify on the next release. The next time a v* tag is pushed, the workflow should publish to PyPI AND create a GitHub Release with the corresponding CHANGELOG section as the body.

Same fix candidates elsewhere in the org

  • cycles-client-python — already done (PR #57)
  • cycles-openai-agents — this PR
  • cycles-spring-boot-starter — its publish.yaml already creates a GitHub Release as part of the workflow chain (different shape; no fix needed there)
  • cycles-client-typescript, cycles-openclaw-budget-guard — both have a release job in their ci.yml already

Adds a `create-release` job to `python-publish.yml` that runs after
`publish-to-pypi` succeeds and creates a GitHub Release with body
extracted from the corresponding CHANGELOG.md section.

Eliminates the manual `gh release create` step every release. The
recent v0.2.1 release exposed this gap — PyPI got the new package
but no GitHub Release was created automatically; the release was
backfilled by hand.

Mirrors the same pattern shipped in cycles-client-python PR #57:

- Triggered by tag push only (not manual workflow_dispatch
  republishes).
- Extracts the CHANGELOG section between `## [VERSION]` and the
  next `## [` heading using a portable string-based awk script
  (no regex escaping issues across awk variants).
- If no CHANGELOG entry is found for the version, falls back to a
  generic "see commit history" body — does not fail the job.
- Title is the tag name (e.g. `v0.2.2`); descriptive suffix on
  prior releases is convention, the user can edit titles after
  the fact.
- `prerelease: ${{ contains(github.ref_name, '-') }}` flags any
  tag with a hyphen (e.g. `v0.3.0-rc.1`) as prerelease
  automatically.

Pinned action SHAs match other repos in the org:
- softprops/action-gh-release@b430933... (v3.0.0)
- actions/checkout@de0fac2... (v6, matches existing job)

Tested locally — extraction produces clean body for v0.2.1 (no
heading bleed, no next-version boundary).

After this lands, future releases collapse to one step:
`git tag vX.Y.Z && git push origin vX.Y.Z`. PyPI publish + GitHub
Release both happen automatically.
@amavashev amavashev merged commit 15ea1a0 into main May 7, 2026
5 checks passed
@amavashev amavashev deleted the ci/auto-create-github-release branch May 7, 2026 10:35
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