diff --git a/GVFS/GVFS.Common/Git/GitVersion.cs b/GVFS/GVFS.Common/Git/GitVersion.cs index aecd02465..a3c6461a7 100644 --- a/GVFS/GVFS.Common/Git/GitVersion.cs +++ b/GVFS/GVFS.Common/Git/GitVersion.cs @@ -1,15 +1,18 @@ using System; -using System.Text; namespace GVFS.Common.Git { public class GitVersion { public GitVersion(int major, int minor, int build, string platform = null, int revision = 0, int minorRevision = 0) + : this(major, minor, build, null, platform, revision, minorRevision) { } + + public GitVersion(int major, int minor, int build, int? releaseCandidate = null, string platform = null, int revision = 0, int minorRevision = 0) { this.Major = major; this.Minor = minor; this.Build = build; + this.ReleaseCandidate = releaseCandidate; this.Platform = platform; this.Revision = revision; this.MinorRevision = minorRevision; @@ -18,6 +21,7 @@ public GitVersion(int major, int minor, int build, string platform = null, int r public int Major { get; private set; } public int Minor { get; private set; } public int Build { get; private set; } + public int? ReleaseCandidate { get; private set; } public string Platform { get; private set; } public int Revision { get; private set; } public int MinorRevision { get; private set; } @@ -37,31 +41,12 @@ public static bool TryParseGitVersionCommandResult(string input, out GitVersion return TryParseVersion(input, out version); } - public static bool TryParseInstallerName(string input, string installerExtension, out GitVersion version) - { - // Installer name is of the form - // Git-2.14.1.gvfs.1.1.gb16030b-64-bit.exe - - version = null; - - if (!input.StartsWith("Git-", StringComparison.InvariantCultureIgnoreCase)) - { - return false; - } - - if (!input.EndsWith("-64-bit" + installerExtension, StringComparison.InvariantCultureIgnoreCase)) - { - return false; - } - - return TryParseVersion(input.Substring(4, input.Length - 15), out version); - } - public static bool TryParseVersion(string input, out GitVersion version) { version = null; int major, minor, build, revision = 0, minorRevision = 0; + int? releaseCandidate = null; string platform = null; if (string.IsNullOrWhiteSpace(input)) @@ -73,10 +58,10 @@ public static bool TryParseVersion(string input, out GitVersion version) int numComponents = parsedComponents.Length; // We minimally accept the official Git version number format which - // consists of three components: "major.minor.build". + // consists of three components: "major.minor.build[.rcN]". // // The other supported formats are the Git for Windows and Microsoft Git - // formats which look like: "major.minor.build.platform.revision.minorRevision" + // formats which look like: "major.minor.build[.rcN].platform.revision.minorRevision" // 0 1 2 3 4 5 // len 1 2 3 4 5 6 // @@ -103,25 +88,54 @@ public static bool TryParseVersion(string input, out GitVersion version) return false; } - // Take the platform component verbatim + // Release candidate and/or platform + // Both of these are optional, but the release candidate is expected to be of the format 'rcN' + // where N is a number, helping us distinguish it from a platform string. + int platformIdx = 3; if (numComponents >= 4) { - platform = parsedComponents[3]; + string tag = parsedComponents[3]; + + // Release candidate 'rcN' + if (tag.StartsWith("rc", StringComparison.OrdinalIgnoreCase) && + tag.Length > 2 && int.TryParse(tag.Substring(2), out int rc) && rc >= 0) + { + releaseCandidate = rc; + + // The next component will now be the (optional) platform. + // Subsequent components will be revision and minor revision so we need to adjust + // the platform index to account for the release candidate. + platformIdx = 4; + if (numComponents >= 5) + { + platform = parsedComponents[4]; + } + } + else // Platform string only + { + platform = tag; + } } // Platform revision - if (numComponents < 5 || !TryParseComponent(parsedComponents[4], out revision)) + if (numComponents > platformIdx + 1) { - revision = 0; + if (!TryParseComponent(parsedComponents[platformIdx + 1], out revision)) + { + revision = 0; + } } // Minor platform revision - if (numComponents < 6 || !TryParseComponent(parsedComponents[5], out minorRevision)) + if (numComponents > platformIdx + 2) { - minorRevision = 0; + if (!TryParseComponent(parsedComponents[platformIdx + 2], out minorRevision)) + { + minorRevision = 0; + } } - version = new GitVersion(major, minor, build, platform, revision, minorRevision); + version = new GitVersion(major, minor, build, releaseCandidate, platform, revision, minorRevision); return true; } @@ -142,7 +156,12 @@ public bool IsLessThan(GitVersion other) public override string ToString() { - return string.Format("{0}.{1}.{2}.{3}.{4}.{5}", this.Major, this.Minor, this.Build, this.Platform, this.Revision, this.MinorRevision); + if (ReleaseCandidate is null) + { + return $"{Major}.{Minor}.{Build}.{Platform}.{Revision}.{MinorRevision}"; + } + + return $"{Major}.{Minor}.{Build}.rc{ReleaseCandidate}.{Platform}.{Revision}.{MinorRevision}"; } private static bool TryParseComponent(string component, out int parsedComponent) @@ -182,6 +201,18 @@ private int CompareVersionNumbers(GitVersion other) return this.Build.CompareTo(other.Build); } + if (this.ReleaseCandidate != other.ReleaseCandidate) + { + if (this.ReleaseCandidate.HasValue && other.ReleaseCandidate.HasValue) + { + return this.ReleaseCandidate.Value.CompareTo(other.ReleaseCandidate.Value); + } + + // If one version has a release candidate and the other does not, + // the one without a release candidate is considered "greater than" the one with. + return other.ReleaseCandidate.HasValue ? 1 : -1; + } + if (this.Revision != other.Revision) { return this.Revision.CompareTo(other.Revision); diff --git a/GVFS/GVFS.UnitTests/Common/GitVersionTests.cs b/GVFS/GVFS.UnitTests/Common/GitVersionTests.cs index a69bd8f7e..3d349ad00 100644 --- a/GVFS/GVFS.UnitTests/Common/GitVersionTests.cs +++ b/GVFS/GVFS.UnitTests/Common/GitVersionTests.cs @@ -1,5 +1,4 @@ -using GVFS.Common; -using GVFS.Common.Git; +using GVFS.Common.Git; using GVFS.Tests.Should; using NUnit.Framework; @@ -8,14 +7,6 @@ namespace GVFS.UnitTests.Common [TestFixture] public class GitVersionTests { - [TestCase] - public void TryParseInstallerName() - { - this.ParseAndValidateInstallerVersion("Git-1.2.3.gvfs.4.5.gb16030b-64-bit" + GVFSPlatform.Instance.Constants.InstallerExtension); - this.ParseAndValidateInstallerVersion("git-1.2.3.gvfs.4.5.gb16030b-64-bit" + GVFSPlatform.Instance.Constants.InstallerExtension); - this.ParseAndValidateInstallerVersion("Git-1.2.3.gvfs.4.5.gb16030b-64-bit" + GVFSPlatform.Instance.Constants.InstallerExtension); - } - [TestCase] public void Version_Data_Null_Returns_False() { @@ -118,6 +109,46 @@ public void Compare_Version_Minor_Greater() version1.IsEqualTo(version2).ShouldEqual(false); } + [TestCase] + public void Compare_ReleaseCandidate_Less() + { + GitVersion version1 = new GitVersion(1, 2, 3, 1, "test", 4, 1); + GitVersion version2 = new GitVersion(1, 2, 3, 2, "test", 4, 1); + + version1.IsLessThan(version2).ShouldEqual(true); + version1.IsEqualTo(version2).ShouldEqual(false); + } + + [TestCase] + public void Compare_ReleaseCandidate_Greater() + { + GitVersion version1 = new GitVersion(1, 2, 3, 2, "test", 4, 1); + GitVersion version2 = new GitVersion(1, 2, 3, 1, "test", 4, 1); + + version1.IsLessThan(version2).ShouldEqual(false); + version1.IsEqualTo(version2).ShouldEqual(false); + } + + [TestCase] + public void Compare_ReleaseCandidate_NonRC_Less() + { + GitVersion version1 = new GitVersion(1, 2, 3, 0, "test", 4, 1); + GitVersion version2 = new GitVersion(1, 2, 3, null, "test", 4, 1); + + version1.IsLessThan(version2).ShouldEqual(true); + version1.IsEqualTo(version2).ShouldEqual(false); + } + + [TestCase] + public void Compare_ReleaseCandidate_NonRC_Greater() + { + GitVersion version1 = new GitVersion(1, 2, 3, null, "test", 4, 1); + GitVersion version2 = new GitVersion(1, 2, 3, 0, "test", 4, 1); + + version1.IsLessThan(version2).ShouldEqual(false); + version1.IsEqualTo(version2).ShouldEqual(false); + } + [TestCase] public void Compare_Version_Build_Less() { @@ -187,6 +218,7 @@ public void Allow_Blank_Minor_Revision() version.Major.ShouldEqual(1); version.Minor.ShouldEqual(2); version.Build.ShouldEqual(3); + version.ReleaseCandidate.ShouldEqual(null); version.Platform.ShouldEqual("test"); version.Revision.ShouldEqual(4); version.MinorRevision.ShouldEqual(0); @@ -201,21 +233,23 @@ public void Allow_Invalid_Minor_Revision() version.Major.ShouldEqual(1); version.Minor.ShouldEqual(2); version.Build.ShouldEqual(3); + version.ReleaseCandidate.ShouldEqual(null); version.Platform.ShouldEqual("test"); version.Revision.ShouldEqual(4); version.MinorRevision.ShouldEqual(0); } - private void ParseAndValidateInstallerVersion(string installerName) + [TestCase] + public void Allow_ReleaseCandidates() { GitVersion version; - bool success = GitVersion.TryParseInstallerName(installerName, GVFSPlatform.Instance.Constants.InstallerExtension, out version); - success.ShouldBeTrue(); + GitVersion.TryParseVersion("1.2.3.rc2.test.4.5", out version).ShouldEqual(true); version.Major.ShouldEqual(1); version.Minor.ShouldEqual(2); version.Build.ShouldEqual(3); - version.Platform.ShouldEqual("gvfs"); + version.ReleaseCandidate.ShouldEqual(2); + version.Platform.ShouldEqual("test"); version.Revision.ShouldEqual(4); version.MinorRevision.ShouldEqual(5); }