Skip to content

Commit cfd0fae

Browse files
Copilotmatt-goldman
andcommitted
Refactor version comparison logic into VersionUtils utility class
Co-authored-by: matt-goldman <[email protected]>
1 parent 8178b41 commit cfd0fae

File tree

3 files changed

+55
-80
lines changed

3 files changed

+55
-80
lines changed

src/Blake.BuildTools/Utils/PluginLoader.cs

Lines changed: 2 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -169,46 +169,9 @@ private static bool IsNuGetPluginValid(NuGetPluginInfo plugin, ILogger? logger)
169169
}
170170

171171
// For NuGet packages, the file version should match the package version
172-
// Compare versions component-wise for leniency, but avoid false positives
173-
if (Version.TryParse(plugin.Version, out var expectedVersion) && Version.TryParse(fileVersion, out var actualVersion))
172+
if (VersionUtils.AreVersionsCompatible(plugin.Version, fileVersion))
174173
{
175-
// Compare only as many components as are present in plugin.Version
176-
bool matches = true;
177-
if (expectedVersion.Major != actualVersion.Major) matches = false;
178-
if (expectedVersion.Minor != -1 && expectedVersion.Minor != actualVersion.Minor) matches = false;
179-
180-
// Handle Build component: if expected doesn't specify Build (=-1), actual should be 0 or -1
181-
if (expectedVersion.Build == -1)
182-
{
183-
if (actualVersion.Build != 0 && actualVersion.Build != -1) matches = false;
184-
}
185-
else
186-
{
187-
if (expectedVersion.Build != actualVersion.Build) matches = false;
188-
}
189-
190-
// Handle Revision component: if expected doesn't specify Revision (=-1), actual should be 0 or -1
191-
if (expectedVersion.Revision == -1)
192-
{
193-
if (actualVersion.Revision != 0 && actualVersion.Revision != -1) matches = false;
194-
}
195-
else
196-
{
197-
if (expectedVersion.Revision != actualVersion.Revision) matches = false;
198-
}
199-
200-
if (matches)
201-
{
202-
return true;
203-
}
204-
}
205-
else
206-
{
207-
// Fallback: exact string match
208-
if (fileVersion == plugin.Version)
209-
{
210-
return true;
211-
}
174+
return true;
212175
}
213176

214177
logger?.LogDebug("Version mismatch for NuGet plugin {packageName}: expected {expectedVersion}, found {actualVersion}",
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
namespace Blake.BuildTools.Utils;
2+
3+
/// <summary>
4+
/// Utility methods for version comparison and validation.
5+
/// </summary>
6+
public static class VersionUtils
7+
{
8+
/// <summary>
9+
/// Compares two version strings with component-wise comparison to prevent false positives.
10+
/// This method provides leniency for legitimate version matches while being strict about preventing false positives.
11+
/// </summary>
12+
/// <param name="expectedVersion">The expected version (e.g., from package metadata)</param>
13+
/// <param name="actualVersion">The actual version (e.g., from file version info)</param>
14+
/// <returns>True if the versions match according to semantic versioning rules</returns>
15+
public static bool AreVersionsCompatible(string expectedVersion, string actualVersion)
16+
{
17+
// Compare versions component-wise for leniency, but avoid false positives
18+
if (Version.TryParse(expectedVersion, out var expected) && Version.TryParse(actualVersion, out var actual))
19+
{
20+
// Compare only as many components as are present in expectedVersion
21+
bool matches = true;
22+
if (expected.Major != actual.Major) matches = false;
23+
if (expected.Minor != -1 && expected.Minor != actual.Minor) matches = false;
24+
25+
// Handle Build component: if expected doesn't specify Build (=-1), actual should be 0 or -1
26+
if (expected.Build == -1)
27+
{
28+
if (actual.Build != 0 && actual.Build != -1) matches = false;
29+
}
30+
else
31+
{
32+
if (expected.Build != actual.Build) matches = false;
33+
}
34+
35+
// Handle Revision component: if expected doesn't specify Revision (=-1), actual should be 0 or -1
36+
if (expected.Revision == -1)
37+
{
38+
if (actual.Revision != 0 && actual.Revision != -1) matches = false;
39+
}
40+
else
41+
{
42+
if (expected.Revision != actual.Revision) matches = false;
43+
}
44+
45+
return matches;
46+
}
47+
48+
// Fallback: exact string match for non-parseable versions
49+
return expectedVersion == actualVersion;
50+
}
51+
}

tests/Blake.BuildTools.Tests/Utils/PluginLoaderTests.cs

Lines changed: 2 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -256,47 +256,8 @@ public void IsNuGetPluginValid_WithVersionMismatch_ReturnsFalse()
256256
[InlineData("different", "other", false)] // String fallback should fail for different strings
257257
public void IsNuGetPluginValid_VersionComparison_WorksCorrectly(string pluginVersion, string fileVersion, bool expectedResult)
258258
{
259-
// This test verifies the version comparison logic directly
260-
// Since we can't easily control FileVersionInfo.GetVersionInfo in unit tests,
261-
// we'll test the version comparison logic by calling a helper method
262-
263-
// For now, let's test the Version parsing logic separately
264-
bool result;
265-
if (Version.TryParse(pluginVersion, out var expectedVersion) && Version.TryParse(fileVersion, out var actualVersion))
266-
{
267-
// Compare only as many components as are present in pluginVersion
268-
bool matches = true;
269-
if (expectedVersion.Major != actualVersion.Major) matches = false;
270-
if (expectedVersion.Minor != -1 && expectedVersion.Minor != actualVersion.Minor) matches = false;
271-
272-
// Handle Build component: if expected doesn't specify Build (=-1), actual should be 0 or -1
273-
if (expectedVersion.Build == -1)
274-
{
275-
if (actualVersion.Build != 0 && actualVersion.Build != -1) matches = false;
276-
}
277-
else
278-
{
279-
if (expectedVersion.Build != actualVersion.Build) matches = false;
280-
}
281-
282-
// Handle Revision component: if expected doesn't specify Revision (=-1), actual should be 0 or -1
283-
if (expectedVersion.Revision == -1)
284-
{
285-
if (actualVersion.Revision != 0 && actualVersion.Revision != -1) matches = false;
286-
}
287-
else
288-
{
289-
if (expectedVersion.Revision != actualVersion.Revision) matches = false;
290-
}
291-
292-
result = matches;
293-
}
294-
else
295-
{
296-
// Fallback: exact string match
297-
result = fileVersion == pluginVersion;
298-
}
299-
259+
// This test verifies the version comparison logic directly using the VersionUtils utility
260+
var result = VersionUtils.AreVersionsCompatible(pluginVersion, fileVersion);
300261
Assert.Equal(expectedResult, result);
301262
}
302263

0 commit comments

Comments
 (0)