Repository navigation
Auto-remove manual NuGet.* version pins on future major versions
#666
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ITaluone
wants to merge
8
commits into
Fallout-build:develop
Choose a base branch
from
ITaluone:feat/migration/add-nuget.framework-pin
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
f2a6455
Move the explicit nuget framework pin into its own step
ITaluone 42bd532
Also match for other NuGet.* packages with a non-range pin
ITaluone 7ac1954
Add another migration step to remove explicit other `NuGet.*` packages
ITaluone 646e005
Add detailed regex for explicit NuGet pin pattern
ITaluone 6f3dba9
Update the RemoveNugetFrameworkPinStep summary to fit what it does
ITaluone 963b769
Update some method docs
ITaluone f9eae20
Add missing test case: prior 10.5.0 migration
ITaluone b173ded
Fix wrong tests
ITaluone File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
113 changes: 113 additions & 0 deletions
113
src/Fallout.Migrate/Steps/RemoveNugetFrameworkPinStep.cs
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| using System; | ||
| using System.Text.RegularExpressions; | ||
| using System.Threading.Tasks; | ||
| using Fallout.Migrate.Common; | ||
|
|
||
| namespace Fallout.Migrate.Steps; | ||
|
|
||
| /// <summary> | ||
| /// Removes explicit <c>NuGet.Frameworks</c> package pins from project files. The pins are no longer needed. | ||
| /// </summary> | ||
| internal sealed class RemoveNugetFrameworkPinStep : IMigrationStep | ||
| { | ||
| /// <summary> | ||
| /// Matches an entire single-line, self-closing | ||
| /// <c>PackageReference</c> element for <c>NuGet.Frameworks</c> | ||
| /// that explicitly declares a non-empty <c>Version</c> attribute, | ||
| /// including its indentation and trailing line ending. | ||
| /// </summary> | ||
| /// <remarks> | ||
| /// <para> | ||
| /// Intended for removing explicitly versioned | ||
| /// <c>NuGet.Frameworks</c> package references from MSBuild XML | ||
| /// files such as <c>.csproj</c>, <c>.props</c>, and <c>.targets</c>. | ||
| /// </para> | ||
| /// <para> | ||
| /// The <c>Include</c> and <c>Version</c> attributes may appear | ||
| /// in any order. Additional attributes, such as | ||
| /// <c>PrivateAssets</c>, are allowed before, between, or after | ||
| /// the required attributes. | ||
| /// </para> | ||
| /// <para> | ||
| /// Matching requirements: | ||
| /// </para> | ||
| /// <list type="bullet"> | ||
| /// <item> | ||
| /// <description> | ||
| /// The element must begin on a line containing only optional | ||
| /// leading spaces or tabs. | ||
| /// </description> | ||
| /// </item> | ||
| /// <item> | ||
| /// <description> | ||
| /// The element must contain | ||
| /// <c>Include="NuGet.Frameworks"</c>. | ||
| /// </description> | ||
| /// </item> | ||
| /// <item> | ||
| /// <description> | ||
| /// The element must contain a non-empty | ||
| /// <c>Version="..."</c> attribute. | ||
| /// </description> | ||
| /// </item> | ||
| /// <item> | ||
| /// <description> | ||
| /// The element must be self-closing and contained on one line. | ||
| /// </description> | ||
| /// </item> | ||
| /// </list> | ||
| /// <para> | ||
| /// The expression consumes the entire matching line, including | ||
| /// its indentation, optional trailing whitespace, and line | ||
| /// ending (if present). Replacing matches with an empty string | ||
| /// therefore removes the package reference without leaving | ||
| /// an empty line. | ||
| /// </para> | ||
| /// <para> | ||
| /// <b>Example:</b> | ||
| /// </para> | ||
| /// <code> | ||
| /// <PackageReference Version="7.9.0" PrivateAssets="all" Include="NuGet.Frameworks" /> | ||
| /// </code> | ||
| /// <para> | ||
| /// <b>Limitations:</b> | ||
| /// The expression is case-sensitive, supports double-quoted | ||
| /// attributes only, and does not match multiline elements. | ||
| /// It does not validate XML structure or NuGet version syntax | ||
| /// and may match package references inside XML comments. | ||
| /// </para> | ||
| /// </remarks> | ||
| private static readonly Regex explicitPinPattern = new( | ||
|
ITaluone marked this conversation as resolved.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think when #694 is merged this should work out of the box, doesn't it? |
||
| @"^[ \t]*<PackageReference\b(?=[^\r\n>]*[ \t]Include=""NuGet\.Frameworks"")(?=[^\r\n>]*[ \t]Version=""[^""]+"")[^\r\n>]*?/>[ \t]*(?:\r?\n|$)", | ||
| RegexOptions.Compiled | RegexOptions.Multiline); | ||
|
|
||
| /// <inheritdoc /> | ||
| public Task ExecuteAsync(MigrationContext context, Summary summary) | ||
|
ITaluone marked this conversation as resolved.
|
||
| { | ||
| Version.TryParse(context.FalloutVersion, out var versionGate); | ||
|
|
||
| if (versionGate < Version.Parse("10.5.0")) | ||
| { | ||
| return Task.CompletedTask; | ||
| } | ||
|
|
||
| foreach (var path in MigrationFileOperations.EnumerateFiles(context.RootDirectory, "_build.csproj")) | ||
| { | ||
| MigrationFileOperations.ApplyRewrite(context, path, Rewrite, summary); | ||
| } | ||
|
|
||
| return Task.CompletedTask; | ||
| } | ||
|
|
||
| private static RewriteResult Rewrite(string original) | ||
| { | ||
| var edits = 0; | ||
| var content = explicitPinPattern.Replace(original, _ => | ||
| { | ||
| edits++; | ||
| return string.Empty; | ||
| }); | ||
|
|
||
| return new RewriteResult(content, edits); | ||
| } | ||
| } | ||
151 changes: 151 additions & 0 deletions
151
src/Fallout.Migrate/Steps/RemoveRelatedNugetPinsStep.cs
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,151 @@ | ||
| using System.Globalization; | ||
| using System.Text.RegularExpressions; | ||
| using System.Threading.Tasks; | ||
| using Fallout.Migrate.Common; | ||
|
|
||
| namespace Fallout.Migrate.Steps; | ||
|
|
||
| /// <summary> | ||
| /// Removes explicit <c>NuGet.Protocol</c>, <c>NuGet.Packaging</c>, and <c>NuGet.Resolver</c> | ||
| /// package pins from project files when migrating to Fallout 11 or later. | ||
| /// </summary> | ||
| internal sealed class RemoveRelatedNugetPinsStep : IMigrationStep | ||
| { | ||
| /// <summary> | ||
| /// The minimum Fallout major version that requires this step. On migrations below that version ths step is skipped. | ||
| /// </summary> | ||
| private const int MinimumFalloutMajor = 11; | ||
|
|
||
| /// <summary> | ||
| /// Matches an entire single-line, self-closing | ||
| /// <c>PackageReference</c> element for <c>NuGet.Protocol</c>, | ||
| /// <c>NuGet.Packaging</c>, or <c>NuGet.Resolver</c> that explicitly | ||
| /// declares a non-empty <c>Version</c> attribute, including its | ||
| /// indentation and trailing line ending. | ||
| /// </summary> | ||
| /// <remarks> | ||
| /// <para> | ||
| /// Intended for removing explicitly versioned NuGet package | ||
| /// references from MSBuild XML files such as <c>.csproj</c>, | ||
| /// <c>.props</c>, and <c>.targets</c>. | ||
| /// </para> | ||
| /// <para> | ||
| /// The <c>Include</c> and <c>Version</c> attributes may appear | ||
| /// in any order. Additional attributes, such as | ||
| /// <c>PrivateAssets</c>, are allowed before, between, or after | ||
| /// the required attributes. | ||
| /// </para> | ||
| /// <para> | ||
| /// Matching requirements: | ||
| /// </para> | ||
| /// <list type="bullet"> | ||
| /// <item> | ||
| /// <description> | ||
| /// The element must begin on a line containing only optional | ||
| /// leading spaces or tabs. | ||
| /// </description> | ||
| /// </item> | ||
| /// <item> | ||
| /// <description> | ||
| /// The element must contain an <c>Include</c> attribute | ||
| /// identifying one of the following packages: | ||
| /// <c>NuGet.Protocol</c>, <c>NuGet.Packaging</c>, | ||
| /// or <c>NuGet.Resolver</c>. | ||
| /// </description> | ||
| /// </item> | ||
| /// <item> | ||
| /// <description> | ||
| /// The element must contain a non-empty | ||
| /// <c>Version="..."</c> attribute. | ||
| /// </description> | ||
| /// </item> | ||
| /// <item> | ||
| /// <description> | ||
| /// The element must be self-closing and contained on one line. | ||
| /// </description> | ||
| /// </item> | ||
| /// </list> | ||
| /// <para> | ||
| /// Two positive lookaheads independently verify the package name | ||
| /// and version attribute. Their positions allow either attribute | ||
| /// to appear first, with arbitrary additional attributes between | ||
| /// them. | ||
| /// </para> | ||
| /// <para> | ||
| /// The expression consumes the entire matching line, including | ||
| /// its indentation, optional trailing whitespace, and line | ||
| /// ending (if present). Replacing matches with an empty string | ||
| /// therefore removes the package reference without leaving | ||
| /// an empty line. | ||
| /// </para> | ||
| /// <para> | ||
| /// <b>Matching examples:</b> | ||
| /// </para> | ||
| /// <code> | ||
| /// <PackageReference Include="NuGet.Protocol" Version="6.0.0" /> | ||
| /// <PackageReference Version="7.9.0" Include="NuGet.Packaging" /> | ||
| /// <PackageReference Version="7.9.0" PrivateAssets="all" Include="NuGet.Resolver" /> | ||
| /// <PackageReference Include="NuGet.Protocol" PrivateAssets="all" Version="6.0.0" /> | ||
| /// </code> | ||
| /// <para> | ||
| /// <b>Limitations:</b> | ||
| /// Matching is case-sensitive and supports double-quoted | ||
| /// attributes only. Multiline elements are not supported. | ||
| /// The expression does not validate XML structure or NuGet | ||
| /// version syntax and may match elements inside XML comments. | ||
| /// </para> | ||
| /// </remarks> | ||
| private static readonly Regex explicitPinPattern = new( | ||
| @"^[ \t]*<PackageReference\b(?=[^\r\n>]*[ \t]Include=""NuGet\.(?:Protocol|Packaging|Resolver)"")(?=[^\r\n>]*[ \t]Version=""[^""]+"")[^\r\n>]*?/>[ \t]*(?:\r?\n|$)", | ||
| RegexOptions.Compiled | RegexOptions.Multiline); | ||
|
|
||
| /// <inheritdoc /> | ||
| public Task ExecuteAsync(MigrationContext context, Summary summary) | ||
| { | ||
| if (!RunsForMinimumRequiredVersion(context.FalloutVersion)) | ||
| { | ||
| return Task.CompletedTask; | ||
| } | ||
|
|
||
| foreach (var path in MigrationFileOperations.EnumerateFiles(context.RootDirectory, "_build.csproj")) | ||
| { | ||
| MigrationFileOperations.ApplyRewrite(context, path, Rewrite, summary); | ||
| } | ||
|
|
||
| return Task.CompletedTask; | ||
| } | ||
|
|
||
| /// <returns> | ||
| /// <see langword="true"/> if the major version can be parsed as a | ||
| /// non-negative integer and is greater than or equal to | ||
| /// <see cref="MinimumFalloutMajor"/>; otherwise, <see langword="false"/>. | ||
| /// Returns <see langword="false"/> for <see langword="null"/>, | ||
| /// empty, or unparseable version strings. | ||
| /// </returns> | ||
| /// <remarks> | ||
| /// The major version is parsed using <see cref="NumberStyles.None"/> | ||
| /// and <see cref="CultureInfo.InvariantCulture"/>. | ||
| /// Minor, patch, and subsequent version segments are ignored and | ||
| /// are not validated. | ||
| /// </remarks> | ||
| private static bool RunsForMinimumRequiredVersion(string version) | ||
| { | ||
| int separatorIndex = version?.IndexOf('.') ?? -1; | ||
| string majorSegment = separatorIndex == -1 ? version : version[..separatorIndex]; | ||
|
|
||
| return int.TryParse(majorSegment, NumberStyles.None, CultureInfo.InvariantCulture, out int major) && | ||
| major >= MinimumFalloutMajor; | ||
| } | ||
|
|
||
| private static RewriteResult Rewrite(string original) | ||
| { | ||
| var edits = 0; | ||
| var content = explicitPinPattern.Replace(original, _ => | ||
| { | ||
| edits++; | ||
| return string.Empty; | ||
| }); | ||
|
|
||
| return new RewriteResult(content, edits); | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.