fix(updater): ensure full changelog includes only release notes up to the latest release#9573
Conversation
… the latest release Make sure that the GitHub provider only collects release notes up to the latest release when `autoUpdater.fullChangelog` is set to `true`.
🦋 Changeset detectedLatest commit: f1d4f1c The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Thanks for the PR and contribution! I see what you're trying to do. I'm going to make a few edits to this PR via |
…ion fails to be parsed
There was a problem hiding this comment.
Pull request overview
This PR fixes electron-updater’s “full changelog” generation for GitHub Releases so it only includes release notes up to the version that will actually be installed (the “latest” release), addressing #9570.
Changes:
- Update
computeReleaseNotesinGitHubProviderto bound collected notes by the latest release’s version. - Improve Atom feed tag parsing robustness by reusing a shared regex and skipping entries that can’t be parsed.
- Add a changeset to publish a patch release of
electron-updater.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| packages/electron-updater/src/providers/GitHubProvider.ts | Adds latest-version bounding to full changelog computation and refactors tag parsing. |
| .changeset/clever-candles-cut.md | Declares a patch changeset for the updater fix. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@AbdulrhmanGoni would you mind giving a quick review? |
Sure! I see your idea of making sure to parse release versions from links correctly before proceeding to the comparisons, Regarding this Copilot comment: #9573 (comment), There is indeed an issue occurs with the target update version when |
|
@AbdulrhmanGoni would you mind implementing those changes? Particularly since you can reproduce one of the logic flows. |
Sure, I will update the PR now |
|
I updated the logic that would fix the issue this PR mainly tries to resolve. I didn't touch anything about this yet:
I included the fix of #9573 (comment), could you take a look? |
When the logic enters the branch where prereleases are promoted to be the target version to be installed (when allowPrerelease is true), make sure to set `latestRelease` variable as well as `tag` variable to the picked pre-release to be installed. This ensures that `computeReleaseNotes` always receives the release that is actually going to be installed as `latestRelease` variable so it can collect release notes only up to the version of `latestRelease`
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@AbdulrhmanGoni I've added tests. Turns out that |
Weird 🤔, I just run the following with import * as semver from "semver@7.7.3"
const result = semver.gt("v3.0.0", new semver.SemVer("v2.0.0"))
console.log(result) // trueAlso tested the change locally before pushing it, I think what caused the error is the parameter to |
…refix This is the previous behavior and there are already some tests that expect `ReleaseNoteInfo.version` to contain only the version without the "v" prefix.
|
I don't get if that failed test shard (Test / Test Windows Shard 1) fails randomly or there is something in this pr that causes it to fail! 🤔 I wonder if it's random because I see the same test has succeeded here: Test / Test Windows Shard 1 @mmaietta do you have an idea? |
|
You can ignore it. It's a flaky test due to the heavy system-level integration it handles for an noninteractive installation e2e update test. Kicking off CI again. |
|
I think i spotted something that could go wrong here: At line 75, if In line 69, The fix could just be falling back to same logic that runs to get latest release tag/version from github when electron-builder/packages/electron-updater/src/providers/GitHubProvider.ts Lines 110 to 119 in 9c67fd3 I actually was able to reproduce the issue and apply the fix locally with this testing electron app @mmaietta what do you say about this? |
Hi, apologies on the delayed reply/review! I'm curious what you mean by this? There was another report recently of not-latest releases are selected if a draft already exists (PrivateGithubProvider). Is the issue you're mentioning similar? |
No problem, it's your time. What i mean is that currently, if for example Regarding the issue you mentioned, If you mean this issue: #9691, I do see it reports the same problem i mentioned here, which is a case where the wrong release is picked as the "latest release" when checking for updates, but i don't see it has the same cause, specially because of the fact that it happens in |
…ut the app is in a stable version
|
Hi @mmaietta Take a look at the commit I just pushed to fix the problem I talked about last time, maybe it helps you understand what i am trying to address. |
|
Thanks @AbdulrhmanGoni! Just checked it all out locally and added several more tests to cover the logic paths. Kicking off Copilot review now and CI in parallel I can take it from here I think. I'll ping/tag you if there are any follow-ups needed from your side 🙃 |
Fixes #9570
Summary
When
fullChangelog: trueis set and the GitHub atom feed contains releases above the marked "latest" release (e.g. a draft, a staging release, or a release from another package in a monorepo),electron-updaterincorrectly included those newer release notes in the changelog shown to the user — notes for changes they would never actually receive.This PR fixes the root cause, closes two additional code-quality issues found during review, and adds a comprehensive unit test suite for
computeReleaseNotes.Bug: incorrect full changelog range (fixes #9570)
What was wrong
computeReleaseNotesaccumulated all feed entries whereversion > currentVersion, with no upper bound. If GitHub's atom feed contained a release newer than the "latest" marked one, its notes leaked into the changelog.Example:
2.0.02.3.0,2.2.0(latest),2.1.02.3.0,2.2.0,2.1.02.2.0,2.1.0onlyFix
computeReleaseNotesnow extracts the version fromlatestRelease's link, validates it withsemver.valid, and applies an upper-bound filter (semver.lte(entry, latestVersion)). Entries abovelatestVersionare excluded.When the
latestReleaselink cannot be parsed to a valid semver version, the function returnsnull(no notes) rather than an unbounded list.Improvements to
allowPrerelease=truetag selectionWhen
allowPrerelease=truewith an explicit channel set (e.g."beta"or"alpha"), the code walks the Atom feed to find the best matching entry. Two improvements were made to this feed-iteration loop while preserving its existing behaviour:semver.validguard: non-semver tags (docs, website, other package releases in monorepos) are now skipped, preventingsemver.prereleasefrom operating on garbage input.latestReleaseassignment: the matched feedelementis now assigned back tolatestReleaseso that the release name and notes sourced later are consistent with the tag that was chosen (previouslylatestReleasecould point to a different entry than the resolvedtag).The
allowPrerelease=truewith no explicit channel (stable current version) case is unchanged: the first Atom feed entry is still used as the candidate, preserving the existing behaviour where a prerelease can be picked when it is the newest release.Code quality fixes
Null guard in stable-release feed lookup (line 114)
The loop that maps a resolved tag back to its feed entry used:
The
!non-null assertion is TypeScript-only — at runtime, if a feed entry's link doesn't match the pattern,null[1]throwsTypeError. This is caught by the outertry/catchbut produces an opaqueERR_UPDATER_INVALID_RELEASE_FEEDerror instead of silently skipping the entry. Now matches the defensive pattern already used in the prerelease loop:TypeScript type narrowing in
computeReleaseNotesversionReleasewas declared asstring | undefined(assignment inside atryblock) but passed tosemver.gt()after only a runtimesemver.valid()guard — TypeScript cannot narrow the type from that call signature. Restructured the try block soversionReleaseisstringor the iterationcontinues, removing the type mismatch.Misleading comment
The comment
// If we cannot parse the latest version, cntinue and return all release notes without filtering by versionhad a typo ("cntinue") and was factually wrong (the code returnsnull, not "all notes"). Fixed to:// If we cannot parse the latest release version, return null — notes cannot be determined.Tests
Added
test/src/updater/updateUtilTest.tswith 23 unit tests forcomputeReleaseNotescovering:isFullChangelog=false"No content."handling""in both single-note and array paths<content>element""(not an error)latestVersionare excluded from changeloglatestVersion === currentVersion[]latestVersion < currentVersion[]currentVersiongt, notgte)latestVersionlatestReleasev-prefix strippingReleaseNoteInfo.versionnever containsvNo content.in array result""per entrylatestReleaselink missing/tag/null[]semver.rcompare