Skip to content
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

Restrict versions to SemVer 2.0 only #720

Merged
merged 1 commit into from
Apr 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions MinVer.Lib/MinVer.Lib.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
<PackageReference Include="NuGet.Versioning" Version="6.1.0" />
</ItemGroup>

</Project>
160 changes: 24 additions & 136 deletions MinVer.Lib/Version.cs
Original file line number Diff line number Diff line change
@@ -1,128 +1,60 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using static System.Math;
using NuGet.Versioning;

namespace MinVer.Lib;

public class Version : IComparable<Version>
public class Version : SemanticVersion
{
private readonly int major;
private readonly int minor;
private readonly int patch;
private readonly List<string> preReleaseIdentifiers;
private readonly int height;
private readonly string buildMetadata;

public Version(string defaultPreReleasePhase) : this(0, 0, 0, new List<string> { defaultPreReleasePhase, "0", }, 0, "") { }

private Version(int major, int minor, int patch, List<string> preReleaseIdentifiers, int height, string buildMetadata)
private Version(int major, int minor, int patch, List<string> preReleaseIdentifiers, int height, string buildMetadata) :
base(
major,
minor,
patch,
height > 0
? preReleaseIdentifiers.Append(height.ToString(CultureInfo.InvariantCulture))
: preReleaseIdentifiers,
buildMetadata)
{
this.major = major;
this.minor = minor;
this.patch = patch;
this.preReleaseIdentifiers = preReleaseIdentifiers;
this.height = height;
this.buildMetadata = buildMetadata;
}

public override string ToString() =>
$"{this.major}.{this.minor}.{this.patch}{(this.preReleaseIdentifiers.Count == 0 ? "" : $"-{string.Join(".", this.preReleaseIdentifiers)}")}{(this.height == 0 ? "" : $".{this.height}")}{(string.IsNullOrEmpty(this.buildMetadata) ? "" : $"+{this.buildMetadata}")}";

public int CompareTo(Version? other)
{
if (other == null)
{
return 1;
}

var majorComparison = this.major.CompareTo(other.major);
if (majorComparison != 0)
{
return majorComparison;
}

var minorComparison = this.minor.CompareTo(other.minor);
if (minorComparison != 0)
{
return minorComparison;
}

var patchComparison = this.patch.CompareTo(other.patch);
if (patchComparison != 0)
{
return patchComparison;
}

if (this.preReleaseIdentifiers.Count > 0 && other.preReleaseIdentifiers.Count == 0)
{
return -1;
}

if (this.preReleaseIdentifiers.Count == 0 && other.preReleaseIdentifiers.Count > 0)
{
return 1;
}

var maxCount = Max(this.preReleaseIdentifiers.Count, other.preReleaseIdentifiers.Count);
for (var index = 0; index < maxCount; ++index)
{
if (this.preReleaseIdentifiers.Count == index && other.preReleaseIdentifiers.Count > index)
{
return -1;
}

if (this.preReleaseIdentifiers.Count > index && other.preReleaseIdentifiers.Count == index)
{
return 1;
}

if (int.TryParse(this.preReleaseIdentifiers[index], out var thisNumber) && int.TryParse(other.preReleaseIdentifiers[index], out var otherNumber))
{
var number = thisNumber.CompareTo(otherNumber);
if (number != 0)
{
return number;
}
}
else
{
var text = string.CompareOrdinal(this.preReleaseIdentifiers[index], other.preReleaseIdentifiers[index]);
if (text != 0)
{
return text;
}
}
}

return this.height.CompareTo(other.height);
}
public override string ToString(string format, IFormatProvider formatProvider) =>
$"{this.Major}.{this.Minor}.{this.Patch}{(string.IsNullOrEmpty(this.Release) ? "" : $"-{this.Release}")}{(string.IsNullOrEmpty(this.Metadata) ? "" : $"+{this.Metadata}")}";

public Version Satisfying(MajorMinor minMajorMinor, string defaultPreReleasePhase)
{
minMajorMinor = minMajorMinor ?? throw new ArgumentNullException(nameof(minMajorMinor));

return minMajorMinor.Major < this.major || (minMajorMinor.Major == this.major && minMajorMinor.Minor <= this.minor)
return minMajorMinor.Major < this.Major || (minMajorMinor.Major == this.Major && minMajorMinor.Minor <= this.Minor)
? this
: new Version(minMajorMinor.Major, minMajorMinor.Minor, 0, new List<string> { defaultPreReleasePhase, "0", }, this.height, this.buildMetadata);
: new Version(minMajorMinor.Major, minMajorMinor.Minor, 0, new List<string> { defaultPreReleasePhase, "0", }, this.height, this.Metadata);
}

public Version WithHeight(int newHeight, VersionPart autoIncrement, string defaultPreReleasePhase) =>
this.preReleaseIdentifiers.Count == 0 && newHeight > 0
? autoIncrement switch
{
VersionPart.Major => new Version(this.major + 1, 0, 0, new List<string> { defaultPreReleasePhase, "0", }, newHeight, ""),
VersionPart.Minor => new Version(this.major, this.minor + 1, 0, new List<string> { defaultPreReleasePhase, "0", }, newHeight, ""),
VersionPart.Patch => new Version(this.major, this.minor, this.patch + 1, new List<string> { defaultPreReleasePhase, "0", }, newHeight, ""),
VersionPart.Major => new Version(this.Major + 1, 0, 0, new List<string> { defaultPreReleasePhase, "0", }, newHeight, ""),
VersionPart.Minor => new Version(this.Major, this.Minor + 1, 0, new List<string> { defaultPreReleasePhase, "0", }, newHeight, ""),
VersionPart.Patch => new Version(this.Major, this.Minor, this.Patch + 1, new List<string> { defaultPreReleasePhase, "0", }, newHeight, ""),
_ => throw new ArgumentOutOfRangeException(nameof(autoIncrement)),
}
: new Version(this.major, this.minor, this.patch, this.preReleaseIdentifiers, newHeight, newHeight == 0 ? this.buildMetadata : "");
: new Version(this.Major, this.Minor, this.Patch, this.preReleaseIdentifiers, newHeight, newHeight == 0 ? this.Metadata : "");

public Version AddBuildMetadata(string newBuildMetadata)
{
var separator = !string.IsNullOrEmpty(this.buildMetadata) && !string.IsNullOrEmpty(newBuildMetadata) ? "." : "";
return new Version(this.major, this.minor, this.patch, this.preReleaseIdentifiers, this.height, $"{this.buildMetadata}{separator}{newBuildMetadata}");
var separator = !string.IsNullOrEmpty(this.Metadata) && !string.IsNullOrEmpty(newBuildMetadata) ? "." : "";
return new Version(this.Major, this.Minor, this.Patch, this.preReleaseIdentifiers, this.height, $"{this.Metadata}{separator}{newBuildMetadata}");
}

public static bool TryParse(string text, [NotNullWhen(returnValue: true)] out Version? version, string prefix = "")
Expand All @@ -137,56 +69,12 @@ public static bool TryParse(string text, [NotNullWhen(returnValue: true)] out Ve
return false;
}

var versionAndMeta = text[prefix.Length..].Split(new[] { '+', }, 2);
var numbersAndPre = versionAndMeta[0].Split(new[] { '-', }, 2);
var numbers = numbersAndPre[0].Split('.');

if (numbers.Length != 3 ||
!int.TryParse(numbers[0], out var major) ||
!int.TryParse(numbers[1], out var minor) ||
!int.TryParse(numbers[2], out var patch))
if (!SemanticVersion.TryParse(text[prefix.Length..], out var semanticVersion))
{
return false;
}

var pre = numbersAndPre.Length > 1 ? numbersAndPre[1].Split('.').ToList() : new List<string>();
var meta = versionAndMeta.Length > 1 ? versionAndMeta[1] : "";

version = new Version(major, minor, patch, pre, 0, meta);

version = new Version(semanticVersion.Major, semanticVersion.Minor, semanticVersion.Patch, semanticVersion.ReleaseLabels.ToList(), 0, semanticVersion.Metadata);
return true;
}

public override bool Equals(object? obj) =>
ReferenceEquals(this, obj) ||
(obj is Version version && this.CompareTo(version) == 0);

public override int GetHashCode()
{
unchecked
{
var code = 17;

code = (code * 23) + this.major.GetHashCode();
code = (code * 23) + this.minor.GetHashCode();
code = (code * 23) + this.patch.GetHashCode();
code = (code * 23) + this.preReleaseIdentifiers.GetHashCode();
code = (code * 23) + this.height.GetHashCode();
code = (code * 23) + this.buildMetadata.GetHashCode(StringComparison.Ordinal);

return code;
}
}

public static bool operator ==(Version? left, Version? right) => left?.Equals(right) ?? right is null;

public static bool operator !=(Version? left, Version? right) => !(left == right);

public static bool operator <(Version? left, Version? right) => left is null ? right is not null : left.CompareTo(right) < 0;

public static bool operator <=(Version? left, Version? right) => left is null || left.CompareTo(right) <= 0;

public static bool operator >(Version? left, Version? right) => left is not null && left.CompareTo(right) > 0;

public static bool operator >=(Version? left, Version? right) => left is null ? right is null : left.CompareTo(right) >= 0;
}
2 changes: 1 addition & 1 deletion MinVer.Lib/Versioner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ private static (Version Version, int? Height) GetVersion(string workDir, string

var selectedCandidate = orderedCandidates.Last();

_ = string.IsNullOrEmpty(selectedCandidate.Tag) && log.IsInfoEnabled && log.Info($"No commit found with a version tag{(string.IsNullOrEmpty(tagPrefix) ? "" : $" prefixed with '{tagPrefix}'")}. Using default version {selectedCandidate.Version}.");
_ = string.IsNullOrEmpty(selectedCandidate.Tag) && log.IsInfoEnabled && log.Info($"No commit found with a valid SemVer 2.0 version{(string.IsNullOrEmpty(tagPrefix) ? "" : $" prefixed with '{tagPrefix}'")}. Using default version {selectedCandidate.Version}.");
_ = log.IsInfoEnabled && log.Info($"Using{(log.IsDebugEnabled && orderedCandidates.Count > 1 ? " " : " ")}{selectedCandidate.ToString(tagWidth, versionWidth, heightWidth)}.");

return (selectedCandidate.Version, selectedCandidate.Height);
Expand Down
39 changes: 0 additions & 39 deletions MinVerTests.Packages/BuildMetadataWithMultiplePlusSigns.cs

This file was deleted.