Add changelog generation tool for GitHub milestones - #13063
Conversation
|
hmm, the uv.lock file is making the RAT check mad. Should I remove uv.lock? |
I think it's recommended to add uv.lock to ensure the exact packages are added. Let's add it back. The problem wasn't your patch adding the lock, the problem is the RAT check incorrectly failing on the lock file. I'll update CI to allow it. Update |
2b949cf to
44f4931
Compare
There was a problem hiding this comment.
Pull request overview
This PR introduces a new Python-based changelog generator under tools/changelog/ to produce CHANGELOG-*-style output from GitHub milestones (via direct REST API calls or the gh CLI), and updates the release-process documentation to use it.
Changes:
- Add
tools/changelog/changelog.pywith text/YAML output and an extended--docmode for richer metadata. - Add
tools/changelog/pyproject.tomlandtools/changelog/uv.lockfor dependency management/execution viauv. - Update release-process docs to use the new tool (with
--use-gh).
Reviewed changes
Copilot reviewed 3 out of 4 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
| tools/changelog/changelog.py | Implements milestone PR collection via REST API or gh, plus output formatting. |
| tools/changelog/pyproject.toml | Defines the Python project and console script entry point. |
| tools/changelog/uv.lock | Pins Python dependencies for uv-managed execution. |
| doc/developer-guide/release-process/index.en.rst | Updates the documented release workflow to generate changelogs via the new tool. |
e208668 to
cd07fa5
Compare
There was a problem hiding this comment.
Pull request overview
Replaces the legacy Perl-based milestone changelog generator with a new Python tool under tools/changelog/ that can pull merged PRs for a milestone via the GitHub REST API or the gh CLI, and updates the release process docs accordingly.
Changes:
- Removed
tools/git/changelog.pl(Perl implementation). - Added a Python-based changelog generator (
tools/changelog/changelog.py) with apyproject.toml+uv.lockfor dependency management. - Updated release-process documentation to use the new tool.
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/git/changelog.pl | Removes the old Perl changelog generator. |
| tools/changelog/changelog.py | New Python tool for generating milestone changelogs via GitHub API or gh, with optional doc/YAML output. |
| tools/changelog/pyproject.toml | Defines the Python tool project and dependencies. |
| tools/changelog/uv.lock | Locks Python dependencies for reproducible runs via uv. |
| doc/developer-guide/release-process/index.en.rst | Updates release instructions to use the new Python tool. |
|
[approve ci autest 2] |
bryancall
left a comment
There was a problem hiding this comment.
Nice to see this move off Perl. The default httpx path looks solid: explicit rate-limit checks, raise_for_status, distinct exit codes, and a good unauthenticated-token warning.
One thing I want fixed before merge. In the --use-gh path, the per-PR merge check treats any non-zero gh api .../merge exit as "not merged" and skips the PR (changelog.py L130). That collapses a genuine 404 (really not merged) together with 403 secondary rate limiting, 5xx, and network errors into the same outcome. Since this makes one API call per PR across a whole milestone, secondary rate limiting is exactly the failure to expect, and when it hits you get a silently incomplete release changelog with a zero exit code. The httpx path already does this right in _is_merged (204 vs 404 vs raise_for_status). Please have the gh path distinguish 404 from other failures and error out on the rest instead of silently skipping. Same goes for the --doc detail fetch, which substitutes empty sha/body on failure rather than surfacing it.
Smaller items, not blocking:
--dochelp and the module docstring say "full commit message" but the code stores the PR body. Fix the wording (or fetch the actual commit message).- The
-a/--authtoken is visible inpsand shell history. Carried over from the old script, but for new code prefer GH_TOKEN only and mark-aas discouraged. pyproject.tomlis missinglicense = "Apache-2.0"that the other tool packages set, andmain()is missing a-> Nonereturn annotation.
The Copilot notes about milestone state=all and a --format yaml JSON fallback are already handled in the current code: both milestone lookups use state=all, and yaml exits with a clear error when PyYAML is missing.
Replaces tools/git/changelog.pl with a Python implementation that generates changelogs from merged PRs in a milestone using the GitHub API or gh CLI. Default output matches the existing CHANGELOG-* file format. The --doc mode includes merge SHAs, labels, and full PR descriptions to guide AI-assisted release documentation updates. Supports text and YAML output formats. Co-Authored-By: Claude <noreply@anthropic.com>
Replace reference to tools/git/changelog.pl with the new tools/changelog/changelog.py invocation using uv run. Co-Authored-By: Claude <noreply@anthropic.com> fix python formatting
copilot review
Any non-zero `gh api .../merge` exit was read as "not merged", so 403 secondary rate limiting or a 5xx silently dropped merged PRs from a release changelog while still exiting 0. That is the failure to expect, since the check runs once per PR across a whole milestone. Use --include so the status line separates a real 404 from a transport or rate-limit error, and exit on anything else. The --doc detail fetch fails the same way now rather than substituting an empty sha and body. Also correct the --doc wording, which stores the PR body and not the commit message; discourage -a, since it exposes the token in ps output and shell history; and declare the Apache-2.0 license that the sibling tool packages set.
060a524 to
298c1fd
Compare
There was a problem hiding this comment.
🟡 Changes recommended
The committed uv.lock is tied to an internal package registry and the new tool has a couple of correctness/UX issues called out in review comments that should be resolved before merge.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 4/5 changed files
- Comments generated: 2
- Review effort level: Lite
The committed uv.lock resolved through an internal Apple package mirror, so every artifact URL and the registry itself were unreachable for anyone outside that network. Rewritten to pypi.org and files.pythonhosted.org; package versions, sizes and sha256 hashes are unchanged, since the mirror serves the same artifacts. The --from-git PR-number regex matched "#N" anywhere in the subject, not the trailing "(#N)" its docstring describes, so an issue reference could be captured as a PR number and merge unrelated entries in merge_changelogs(). Now anchored. _check_rate_limit() reported a rate limit for every 403, but GitHub also uses 403 for a missing token or insufficient scopes, where that advice is wrong and hides the cause. It now exits only on a primary limit (x-ratelimit-remaining: 0), a secondary limit (retry-after) or a 429, and lets anything else fall through to the raise_for_status() that follows each call site.
|
Rebuilt this branch on current Why the diff looked absurd. The branch had been rebased backwards at some point — @bryancall's review (
Copilot's follow-up plus one thing it caught that mattered (
All 15 checks were green on the previous head. Ready for another look. |
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Pull request overview
Copilot reviewed 4 out of 5 changed files in this pull request and generated 6 comments.
pyproject.toml declares pyyaml as a required dependency, but the code guarded the import and failed at runtime if it was missing. httpx is imported unconditionally and is just as much a third-party dependency, so the guarded path could only be reached by an install that pyproject.toml does not describe. YAML output is a documented mode, so the dependency is required: import it like httpx and drop the dead branch. merge_changelogs() documented deduplication by PR number but only avoided collisions between the git and milestone sources, not within the git range itself. A revert and reapply, or the same commit cherry-picked twice, carries the same trailing "(#N)" and produced two entries for one PR. Now deduplicated on the git side too, keeping the first occurrence so the surviving entry is the chronological one.
|
@bryancall — went through Copilot's six comments; they're four distinct points (the PyYAML one is repeated three times). Two fixed in Fixed:
Declined (detail on the threads): the suggestion to drop the merge check in Verification on this round: the dedup case tested directly (first occurrence kept, labels grafted onto the survivor, milestone extras and unnumbered security commits intact), plus an authenticated end-to-end |
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Pull request overview
Copilot reviewed 4 out of 5 changed files in this pull request and generated 4 comments.
yaml.safe_dump() instead of yaml.dump(), so the output cannot grow Python
object tags if a non-primitive ever reaches the entry dicts.
Removed [project.scripts]. Without a [build-system] table this is a uv
virtual project -- uv.lock records source = { virtual = "." } -- so the
package is never built and the console script it declares is never created:
$ uv run --project tools/changelog changelog --help
error: Failed to spawn: `changelog`
The declaration described an interface that does not exist, and reviewers
read it as the supported entry point twice. Documented the actual
invocation in its place rather than adding a build backend for a
single-file in-tree script.
The release guide now names its prerequisites: uv, and for --use-gh an
authenticated gh. It also documents the GH_TOKEN alternative, since an
unauthenticated run exceeds the API rate limit partway through a
release-sized milestone and exits without writing a changelog.
|
Latest round of Copilot comments handled in Fixed:
Declined, with reasoning on the thread: batching the @bryancall I'll wait for Copilot to have another pass at this before asking you to look again, so you're not reviewing into a moving target. |
There was a problem hiding this comment.
Warning
Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.
Pull request overview
Copilot reviewed 4 out of 5 changed files in this pull request and generated 5 comments.
Replaces tools/git/changelog.pl with a Python implementation that generates changelogs from merged PRs in a milestone using the GitHub API or gh CLI. Default output matches the existing CHANGELOG-* file format. The --doc mode includes merge SHAs, labels, and full PR descriptions to guide AI-assisted release documentation updates. Supports text and YAML output formats.