Skip to content

Build pull request changelogs from release membership - #15

Merged
cjbarth merged 3 commits into
masterfrom
feat/pr-release-membership
Sep 16, 2026
Merged

cjbarth merged 3 commits into
masterfrom
feat/pr-release-membership

Conversation

@cjbarth

@cjbarth cjbarth commented Sep 16, 2026

Copy link
Copy Markdown
Owner

The problem

With --data-source=prs, a section was built by comparing a tag with the tag before it, using only tags reachable from the branch gren happened to run on. Three things followed from that:

  • Sections depended on the branch. Running on master in a repository with a 6.x line left out every section for tags that are not ancestors of master. In xml-crypto that is 6.0.1–6.1.2, 3.2.x, 2.1.5–2.1.6 and 1.5.4–1.5.6.
  • Commits without a pull request vanished, with nothing said about them. The 6.0.1 security fix is one.
  • Pull requests were only ever looked up in the current repository, so a project carrying another project's history — node-saml carries passport-saml's — could not link its older entries.

What this changes

A release contains the commits reachable from its tag but not from any tag of a lower version, read from the local clone with git rev-list. Each commit belongs to the lowest release that contains it. That rule follows both parents of a merge and ignores the current branch, so a section comes out the same wherever it is generated, and sections are ordered by semver rather than by date.

Three options come with it:

Option What it does
--pull-request-repos Other repositories to look for pull requests in: an upstream, a fork, or where the project used to live.
commitNotes (config only) What to say about a commit that has no pull request. An entry can carry its own title, labels, link and author, or name a pull request with pr: 330 — including owner/repo#330 — and take all of that from it. That is the entry to use for a cherry-pick pushed without a pull request of its own.
--frozen-before A date, tag or commit. Releases older than it keep the sections already in CHANGELOG.md, so a version bump only has to review what is new.

A commit matching neither a pull request nor a commitNotes entry is now reported after generating, with an entry to paste into the configuration, instead of disappearing.

Compatibility

The new options are additive and the other data sources are untouched, so this is a minor release. Existing prs users should expect a large diff on their first regeneration: sections that were missing appear, entries move to the release that actually contains them, and commits without a pull request are reported rather than dropped. Generate to a scratch file and read the diff before letting it write CHANGELOG.md.

gren now reads the local clone, so it needs the tags fetched and the full history — git fetch --unshallow, or fetch-depth: 0 for actions/checkout. It stops rather than generating a thin changelog from a shallow one.

Verification

  • 120 tests, 91% of statements. The fixture builds a throwaway repository with two release lines, a real cross-line merge, a merge-commit pull request, a rebase-merged one and direct commits, with GitHub stubbed across two repositories — including the 422 that GitHub answers for a commit it cannot find, which is what a pullRequestRepos lookup gets most of the time.
  • Regenerated against xml-crypto (46 sections, frozen at v6.0.0) and node-saml (11 sections, 172 passport-saml pull requests resolved through pullRequestRepos). Both byte-identical across every round of review fixes.

🤖 Generated with Claude Code

cjbarth and others added 3 commits September 16, 2026 07:29
The prs data source compared adjacent tags reachable from the current
branch, so what a section contained depended on where it was generated
from, and commits without a pull request were dropped in silence. A
repository with more than one release line, such as a 6.x branch beside
master, lost whole sections.

A release now contains the commits reachable from its tag but not from
any tag of a lower version, read from the local clone. Each commit
belongs to the lowest release that contains it, so a section comes out
the same on every branch, and sections are ordered by semver.

Three options go with it:

  pullRequestRepos  other repositories to look for pull requests in,
                    such as an upstream, a fork, or where the project
                    used to live
  commitNotes       what to say about a commit with no pull request, or
                    which pull request a cherry-pick came from
  frozenBefore      keep the sections of older releases as they are

A commit that matches neither a pull request nor a commitNotes entry is
reported with an entry to paste into the configuration, rather than
disappearing from the changelog.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
git writes an ISO 8601 date for UTC as either Z or +00:00, depending on
its version, so tests that compared the string failed on a newer git
than the one they were written on. The dates are only ever read as
instants, so normalise them where they are read and the tool behaves
the same on every version of git.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@cjbarth
cjbarth merged commit 051914d into master Sep 16, 2026
2 checks passed
@cjbarth
cjbarth deleted the feat/pr-release-membership branch September 16, 2026 15:50
@cjbarth cjbarth added the enhancement New feature or request label Sep 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant