Skip to content

Conversation

@Mrtenz
Copy link
Member

@Mrtenz Mrtenz commented Dec 17, 2025

Explanation

This fixes an issue in changelogs where changelog entries may be incorrectly moved after merging into the main branch. Given the following (partial) changelog for example:

## [Unreleased]

### Changed

- Changelog entry A ([#1234](...))
- Changelog entry B ([#5678](...))
- Changelog entry C ([#1337](...))

After a release, this changelog may look like this:

  ## [Unreleased]

+ ## [1.0.0]

  ### Changed

  - Changelog entry A ([#1234](...))
  - Changelog entry B ([#5678](...))
  - Changelog entry C ([#1337](...))

But if another PR based on the original changelog also adds an entry to the unreleased section like this:

  ## [Unreleased]

  ### Changed

  - Changelog entry A ([#1234](...))
  - Changelog entry B ([#5678](...))
  - Changelog entry C ([#1337](...))
+ - Changelog entry D ([#0000](...))

The final changelog will look like this, since Git can merge the entry based on the other entries around it:

## [Unreleased]

## [1.0.0]

### Changed

- Changelog entry A ([#1234](...))
- Changelog entry B ([#5678](...))
- Changelog entry C ([#1337](...))
- Changelog entry D ([#0000](...))

Here it appears that the release included "entry D", but in reality that was meant to be under the unreleased section.

To address this issue, I've added a simple workflow that checks for changelog diffs. It uses a minimal algorithm to parse the markdown files, find entries that are included in unreleased originally, and checks if they still are after merging. If not, the workflow will fail and show an error such as this:

Checking changelog file: packages/some-package/CHANGELOG.md
The following lines added in the PR are missing from the "Unreleased" section after merge:

  • Changelog entry D (#0000)

Please update your pull request and ensure that new changelog entries remain in the "Unreleased" section.

Long term we should solve this problem by using changesets instead, in which case the unreleased changes will never be merged or conflict with each other, but until we figure out how to implement those in our release workflows, we can use this workflow.

References

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed
  • I've introduced breaking changes in this PR and have prepared draft pull requests for clients and consumer packages to resolve them

Note

Adds a CI action and job that verify PR-added changelog entries remain in the Unreleased section after merge (including merge queue).

  • CI:
    • New composite action ./.github/actions/check-merge-queue-changelogs:
      • Determines PR number/branch (supports pull_request and merge_group).
      • Computes merge-base with base branch and diffs CHANGELOG.md files.
      • Runs check-changelog-diff.cjs to ensure PR-added lines stay in [Unreleased] after merge.
    • Workflow update ./.github/workflows/lint-build-test.yml:
      • Adds validate-changelog-diffs job (PRs and merge groups) that uses the new action.

Written by Cursor Bugbot for commit 04224ca. This will update automatically on new commits. Configure here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a plain JS file so we can just call node check-changelog-diff.cjs without installing dependencies etc.

@Mrtenz Mrtenz marked this pull request as ready for review December 18, 2025 09:39
@Mrtenz Mrtenz requested a review from a team as a code owner December 18, 2025 09:39
id: changelog-check
shell: bash
env:
HEAD_REF: ${{ github.event.pull_request.head.ref || github.event.merge_group.head_ref }}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be unused

Suggested change
HEAD_REF: ${{ github.event.pull_request.head.ref || github.event.merge_group.head_ref }}

HEAD_REF: ${{ github.event.pull_request.head.ref || github.event.merge_group.head_ref }}
BASE_REF: ${{ github.event.pull_request.base.ref || github.event.merge_group.base_ref }}
PR_BRANCH: ${{ steps.pr-branch.outputs.pr-branch }}
REPOSITORY: ${{ github.repository }}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be unused

Suggested change
REPOSITORY: ${{ github.repository }}

BASE_REF="${BASH_REMATCH[1]}"
fi

TARGET_REF=$(git merge-base "origin/$BASE_REF" "origin/$PR_BRANCH")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not following how this ref will help us find changelog updates. It looks like we're always getting the same diff we see in the PR here, so it would miss changes due to updates on the base branch.

e.g. if I'm fixing a bug in the network-controller, then a release happens and moves that under a release header, we won't see that here. The TARGET_REF will be the commit on main before the release, and the PR_BRANCH won't have the release on it either (the branch wasn't updated since the release; if it was, the pre-existing changelog linter would have caught this!), so we're comparing two commits here that are both too old to catch the problem.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like what we want here is to compare the changelog in the PR with what it would be after merge.

The "before" case here would be PR_BRANCH, and the "after" would be the commit that triggered the workflow (which is post-merge for both merge_group and pull_request)

}

/* eslint-disable n/no-sync */
// The type of these is inferred as `Buffer` when using "utf-8" directly instead
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment from an earlier draft when this was written in TypeScript?

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.

3 participants