Repository navigation
chore: write each package's changelog section into its NuGet release notes - #347
Open
CaffeinatedCoder wants to merge 1 commit into
Open
CaffeinatedCoder wants to merge 1 commit into
CaffeinatedCoder wants to merge 1 commit into
Conversation
…notes PackageReleaseNotes linked blob/main/src/<package>/CHANGELOG.md, so nuget.org's Release Notes tab and Visual Studio's Updates tab sent a reader of any version to today's file. Pack now writes the version's section of the package's own changelog (Directory.Build.targets, before GenerateNuspec), in plain text because nuget.org renders release notes as typed and links only bare URLs, with a footer linking the changelog at the version's tag. Pack fails naming the file on a missing, empty, doubled or over-35,000-character section. PackagingConventionTests generates every package's nuspec through NuGet's pack task and compares releaseNotes with the section; the smoke test checks the .nupkg itself. Refs #346 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 20, 2026
Owner
Author
|
10.x cherry-pick: #348 |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #346
Problem
PackageReleaseNoteswas a link toblob/main/src/<package>/CHANGELOG.md. nuget.org's Release Notes tab and Visual Studio's Updates tab show that field, frozen per version, so a reader of any version saw a link to today's file instead of the notes for the version in front of them.How nuget.org renders release notes (measured)
The documentation does not say, so I fetched real package pages and read NuGetGallery's renderer:
### Fixed,-bullets, backticks,[@user](https://github.com/user)), renders on https://www.nuget.org/packages/bunit/2.12.5 as<p>Changes in bUnit 2.12.5<br /><br /><br />### Fixed<br /><br />- \WrapperBase.WrappedElement` … Reported by [@psu-prog](https://github.com/psu-prog) …. Headings, bullets, backticks and link brackets appear exactly as typed. Only the bare URL is linked, and the link stops before the closing)`.## v35.6.5,* PR 622: …) renders the same way:##and*shown literally, newlines turned into<br />.See https://… for details): the bare URL becomes<a href="…" rel="nofollow">.NuGetGallery/Helpers/HtmlExtensions.csPreFormattedText(used byViews/Packages/DisplayPackage.cshtmlforModel.ReleaseNotes), HTML-encodes the text, turns\ninto<br />, turns runs of spaces into , and links only matches of((http|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?).#fragments are part of a link.(,)and a trailing.or,are not.So release notes on nuget.org are plain text with auto-linked bare URLs. The chosen form: a link
[text](url)is writtentext (url)(the URL still links, and the)stays outside it), backticks and**are dropped, and a### Addedheading becomesAdded. The-bullets and blank lines stay, since they read as plain text. I could not measure Visual Studio's Updates tab here. Plain text is the safe form there too.Change
Directory.Build.targets(new): the targetSetPackageReleaseNotesFromChangelogrunsBeforeTargets="GenerateNuspec"on every packable project. An inline task (RoslynCodeTaskFactory) reads the section under## [$(Version)], previews included, up to the next##, from$(MSBuildProjectDirectory)/CHANGELOG.md. It trims the blank lines around the section, writes it in the plain form above, and adds one footer line:Full changelog: https://github.com/CaffeinatedCoder/CodoMetis.ValueRanges/blob/v$(Version)/src/<package>/CHANGELOG.md. The footer links the version's tag, notmain: release tags are immutable and are pushed beforerelease.ymlpublishes, so the link resolves for every published version on either line and shows the changelog as it was at that version. The changelog is added toNuGetPackInput, so an edit to the changelog alone repacks (checked: an edited section shows up in the nextdotnet pack --no-build).Directory.Build.props: the link is gone. Nothing setsPackageReleaseNotesstatically any more.PackagingConventionTests:EveryPackage_LinksItsReleaseNotesToItsOwnChangelogis replaced by two tests:EveryPackage_ShipsItsVersionsChangelogSectionAsReleaseNotesruns NuGet's own pack up to the nuspec for every package (dotnet msbuild -t:_GetRestoreProjectStyle;GenerateNuspec -p:NoBuild=true -p:IncludeBuildOutput=false, about 0.3 s each). It readsreleaseNotesfrom the generated nuspec and compares it with the section, transformed by the test's own code rather than the target's. It also checks that no](, backtick,**or#heading is left.Pack_FailsNamingTheChangelog_WhenTheSectionCannotBeTheReleaseNotescovers four rows (missing, empty, doubled, too long). Each points the target at a temporary changelog through-p:ReleaseNotesChangelog=…and requires a failed pack whose error names that file.test/consumer-smoke-test.sh: before the consumers, the script reads each.nupkg's nuspec. The release notes must open with the plain form of the section's first line, end with the tag-pinned footer, and hold no backtick or](. In the release workflow's mode, those are the packages about to be pushed.AGENTS.md(the packaging rule under Commands, plus the conventions and smoke-test bullets),CONTRIBUTING.md#changelog(a package's section is its NuGet release notes;Packagingadded to the area order) anddocs/testing.md.Packaging:line under### Changedin## [11.0.0-preview.1]of the root and all four package changelogs.test/oracles/claims.jsonor waiver insurface-waivers.jsoncovers release notes or packaging metadata, so nothing changes there (dotnet run tools/oracles.cs statuslists none).Tests
Unit and convention suites as CI runs them, locally on SDK 11.0.100-rc.2: 2,512 passed, 0 failed (Conventions 411, core 1,397, EF 291, NodaTime 238, AspNetCore 92, EF NodaTime 83). The smoke test's new block ran locally against a fresh
dotnet packfeed (16 ok); the full smoke test (AOT and the consumers) runs in CI.Each guard proven by seeding (apply, run,
git reset --hard):EveryPackage_…("does not carry the '## [11.0.0-preview.1]' section", 133 characters where 885 were expected), all fourPack_Fails…rows ("Pack succeeded…"), and the smoke check: all 8 "opens with" and "ends with" assertions10.1.0'sEveryPackage_…(885 characters expected, 385 found, first difference at index 0), and the smoke check's 4 "opens with its '## [11.0.0-preview.1]' section"src/CodoMetis.ValueRanges.NodaTime/CHANGELOG.mdEveryPackage_…: "Packing CodoMetis.ValueRanges.NodaTime's nuspec failed: … CHANGELOG.md has no '## [11.0.0-preview.1]' section"EveryPackage_…(first difference at index 156), and the smoke check's 4 "hold no Markdown backticks"Pack_Fails…("missing"): "Pack succeeded with a changelog whose section is missing"Pack_Fails…("too long")blob/mainEveryPackage_…(first difference at index 802, the footer)AfterTargets)EveryPackage_…: "nuspec has no release notes; nothing set PackageReleaseNotes before it was written". The first run hit aSingle()exception, so I added the null assertion that now reports itThe cherry-pick to
release/10.xfollows in its own PR, which links this one.🤖 Generated with Claude Code