[ENH] Comment on PRs/issues with their release tag#2437
Conversation
Closes #2436 After each GitHub release publication, post a "PR released in vX.Y.Z" comment on every PR included in the release and a "Issue fixed in vX.Y.Z" comment on every issue those PRs closed via Fixes/Closes. Modeled after the corresponding logic in datalad/release-action's make_release_comments. The check before posting matches on exact comment body, so re-runs of the workflow or of the script are idempotent (no duplicates, no edits). Components: - tools/announce_release.py: standalone `uv run` script that walks `git log <prev>..<tag> --first-parent` to discover PRs in a release (handles both `... (#NNN)` squash subjects and `Merge pull request #NNN` merges), then queries closing issues via GraphQL and posts comments via REST. Dry-run by default; --post to actually comment. Supports `--retroactive [--since TAG]` for back-filling past releases. Argument validation happens before the GITHUB_TOKEN check so --help and bogus invocations don't surface as confusing token errors. - .github/workflows/publish_schema.yml: rather than a new workflow, the existing release-adjacent workflow gets a `release: published` trigger and a new `announce_release` job that runs the script with --post. The existing `publish` job is gated to push events only so it doesn't run on release events. - Release_Protocol.md: documents the new auto-announcement step and points at the script for retroactive back-fills. - tools/tests/test_announce_release.py: pytest suite (28 tests) for the pure-logic units — tag-filter regex, comment-body and release-link formatting, PR-extraction from canned `git log` output, release-tag filtering, `select_tags` selection logic, and CLI argparse / token-check behaviour. Runs standalone via its own `# /// script` uv-run header, no project test infra required. Co-Authored-By: Claude Code 2.1.159 / Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
I have applied any labels matching special text in your title and description. Please review the labels and make any necessary changes. |
There was a problem hiding this comment.
I don't think it makes sense to use this workflow.
There was a problem hiding this comment.
initially the beast created a separate one but I thought it would make sense to incorporate with existing release one... remind me which one does releasing? or would you prefer an entirely separate?
There was a problem hiding this comment.
ok, with the last commit I moved it out -- it is all by itself now -- neat and reusable... should I make it a reusable action may be ? (uff -- long road to perfection)
Co-authored-by: Chris Markiewicz <markiewicz@stanford.edu>
research/comparison to "alternatives" potentially to adoptOff-the-shelf alternative:
|
| Action | Stars | Comments on PRs | Comments on closed issues | Notes |
|---|---|---|---|---|
apexskier/github-release-commenter |
27 | yes | yes | Closest match to #2436 |
rdlf0/comment-released-prs-action |
6 | yes | no | PR-only |
duncanmcclean/post-release-comments |
3 | yes | yes | Requires you to feed in a parsed CHANGELOG.md |
Blackjacx/backlog-notifier |
7 | n/a | n/a | Posts on external backlog-repo tickets via a custom ID prefix — different use case |
The intuit/auto "released" plugin referenced in the issue is part of a much
larger release-management framework — adopting it just for the comment side
is overkill.
How apexskier/github-release-commenter works (relevant to compare)
Discovery mechanism (read from src/index.ts):
- Fetches the two most recent releases via
repos.listReleases. - Calls
repos.compareCommits(prev_tag, current_tag). - For each commit in the comparison, one GraphQL query pulls
associatedPullRequestsand each PR'stimelineItemsfiltered to
ConnectedEvent/DisconnectedEvent. - The
ConnectedEventset is the union ofFixes/Closes #Nreferences
and the GitHub-UI "Linked issues" sidebar;DisconnectedEventhonors
un-links. - Posts the configured comment on every PR + every still-connected issue.
Minimal workflow integration:
on:
release:
types: [published]
permissions:
issues: write
pull-requests: write
jobs:
announce_release:
runs-on: ubuntu-latest
steps:
- uses: apexskier/github-release-commenter@v1
with:
comment-template: |
Released in {release_link}
skip-label: exclude-from-changelogComparison vs. this PR's tools/announce_release.py
apexskier/github-release-commenter |
tools/announce_release.py (this PR) |
|
|---|---|---|
| Comments on PRs in the release | yes | yes |
| Comments on issues closed by those PRs | yes (timeline ConnectedEvent) |
yes (GraphQL closingIssuesReferences) |
| Trigger | release: published |
same |
| Code we own / maintain | 0 lines | ~300 LOC + 28 tests |
| Idempotent on re-run | no — re-publishing duplicates | yes — exact-body check before posting |
| Skip-label support | built-in (default: dependencies) |
not implemented |
| Retroactive back-fill of past releases | no | yes (--retroactive [--since TAG]) |
| Linked-issues semantics | Fixes #N plus manual sidebar links |
Fixes #N only |
| First-ever release on a repo | intentionally ignored | works (no prev_tag ⇒ full history) |
Proposed compromise
Switch the recurring on-release path to apexskier/github-release-commenter
and keep tools/announce_release.py solely for the one-time retroactive
back-fill (which no marketplace action provides):
- Replace this PR's
announce_releasejob inpublish_schema.ymlwith a
singleuses: apexskier/github-release-commenter@v1step. - Keep
tools/announce_release.py(and its tests) in-tree, used by a
maintainer to run--retroactive --postonce to backfill comments on
past releases. After that, it can stay around as documentation /
recoverability tooling, or be removed.
That gives us:
- ~20-line workflow step instead of a Python script in CI;
- proven third-party action for the recurring path;
- a small in-repo tool for the historical sweep, with body-equality
idempotency that's actually useful while backfilling (since you might
iterate a few times).
Trade-offs worth weighing before switching
- No idempotency in the marketplace action. If a release is ever
un-published and re-published, every linked PR/issue gets a second
comment. Their codebase has no comment-existence check; it's not on
their roadmap. - Linked-issues semantics differ. The marketplace action picks up
bothFixes #Nand the GitHub-UI "Linked issues" sidebar; ours
picks up onlyclosingIssuesReferences. Theirs is arguably more
complete; whether maintainers ever populate the manual sidebar in this
repo is the question. - Third-party-action supply chain. We'd be pinning a non-Anthropic /
non-GitHub-published binary blob into our release path. Pinning by SHA
rather than@v1mitigates this. The MIT license is declared in
package.json(no top-levelLICENSEfile, FYI). - Comment template flexibility. We use a rich-Markdown body
PR released in [`vX.Y.Z`](https://.../releases/tag/vX.Y.Z); theirs
supports{release_link}/{release_name}/{release_tag}
templating, which can produce an equivalent body. No blocker.
Happy to push a follow-up commit that swaps the workflow job over and
trims Release_Protocol.md accordingly, if folks prefer the third-party
action.
Per @effigies's review on #2437: bolting `release: published` onto `publish_schema.yml` was a forced fit — that workflow is about schema publishing to JSR on push to master/maint, not about GitHub-release events. There is no existing "release workflow" in this repo (releases are manual per `Release_Protocol.md`), so the right answer is a small dedicated one. - Revert `.github/workflows/publish_schema.yml` to master state. - Add `.github/workflows/announce_release.yml`: triggers on `release: published`, runs `tools/announce_release.py --post` for the published tag. Same job content as before, just isolated. - Repoint `Release_Protocol.md` at the new workflow. Co-Authored-By: Claude Code 2.1.159 / Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes #2436.
Summary
After each GitHub release publication, post a comment on every PR included
in the release ("PR released in
vX.Y.Z") and on every issue those PRsclosed via
Fixes #N/Closes #N("Issue fixed invX.Y.Z"). Modeled onthe corresponding logic in
datalad/release-action'smake_release_comments— see e.g. datalad/datalad#7832 (comment)for the effect.
The component pieces:
tools/announce_release.py— standaloneuv runscript that walksgit log <prev>..<tag> --first-parentto discover PRs in a release(handles both squash
… (#NNN)subjects andMerge pull request #NNNmerges), queries closing issues via GraphQL, and posts comments via
REST. Dry-run by default;
--postactually comments.--retroactive [--since TAG]backfills past releases..github/workflows/publish_schema.yml— rather than a new workflow,the existing release-adjacent workflow gets a
release: publishedtrigger and a new
announce_releasejob. The existingpublishjob isgated to push events only so it doesn't fire on release events.
Release_Protocol.md— short note in step 8 + pointer to the scriptfor back-filling pre-existing releases.
tools/tests/test_announce_release.py— 28 pytest cases coveringtag-filter regex, comment/link formatting,
prs_in_rangeparsing ofboth commit-subject styles,
release_tagsfiltering,select_tagsselection logic, and CLI behaviour (argparse rejections,
--helpwithout token, missing-token error, unknown-tag reported before token).
Runs standalone via its own
# /// scriptuv-run header.Idempotency, live-tested
Before posting, the script checks for an existing comment with the exact
target body via GraphQL pagination, so re-runs (workflow or hand-run) do
not duplicate. I exercised this on
v1.11.1— the first run wasinterrupted partway through, the second one cleanly skipped the
already-annotated PRs/issues and processed the rest:
Live-test output (after interrupted initial run)
so can see the effect on e.g.
How to dry-run / backfill manually
URLs are inlined next to each
#NNNso terminals autolink them.Here is what I get if I run it for prior release
Test plan
v1.11.1lists the expected 10 PRs + 1 closing issue.--postonv1.11.1actually comments; re-run skips them all (idempotency verified live, see above).pytest tools/tests/test_announce_release.py— 28 passed.--helpworks withoutGITHUB_TOKEN; theuv run … -- --helpinvocation pattern reports "not a known release tag" rather than a misleading token error.release: publishedafter merge, confirm theannounce_releasejob fires and posts comments. Maintainers can also run the retroactive sweep (tools/announce_release.py --retroactive --post) to backfill prior releases.