diff --git a/GitIntegration.Test/Parsing/GitVersionParserTests.cs b/GitIntegration.Test/Parsing/GitVersionParserTests.cs index 028721e..752f533 100644 --- a/GitIntegration.Test/Parsing/GitVersionParserTests.cs +++ b/GitIntegration.Test/Parsing/GitVersionParserTests.cs @@ -29,6 +29,29 @@ public void ParsesTheWindowsBuildSuffix() Assert.AreEqual("2.50.1.windows.1", version.Raw); } + [TestMethod] + public void ParsesApplesBuildNoteAfterThePatchComponent() + { + // The stock git on macOS and GitHub's macOS runners. The note follows the patch number + // with a space, so the third component is "3 (Apple Git-145)", not "3". + GitVersion version = GitVersionParser.Parse("git version 2.39.3 (Apple Git-145)\n"); + + Assert.AreEqual(2, version.Major); + Assert.AreEqual(39, version.Minor); + Assert.AreEqual(3, version.Patch); + Assert.AreEqual("2.39.3 (Apple Git-145)", version.Raw); + } + + [TestMethod] + public void ParsesAReleaseCandidateSuffixOnThePatchComponent() + { + GitVersion version = GitVersionParser.Parse("git version 2.41.1-rc0\n"); + + Assert.AreEqual(2, version.Major); + Assert.AreEqual(41, version.Minor); + Assert.AreEqual(1, version.Patch); + } + [TestMethod] public void ParsesAVersionWithNoPatchComponent() { diff --git a/GitIntegration/Parsing/GitVersionParser.cs b/GitIntegration/Parsing/GitVersionParser.cs index 17f5fbf..f6e5904 100644 --- a/GitIntegration/Parsing/GitVersionParser.cs +++ b/GitIntegration/Parsing/GitVersionParser.cs @@ -49,9 +49,26 @@ internal static GitVersion Parse(string output) }; } - private static int ReadComponent(string[] components, int index) => - index < components.Length && - int.TryParse(components[index], NumberStyles.None, CultureInfo.InvariantCulture, out int value) + // Reads the component's leading digits, so a build note glued to the last component still + // leaves its number: Apple's git reports "2.39.3 (Apple Git-145)", whose third component is + // "3 (Apple Git-145)", and an rc build reports "0-rc0". A component with no leading digit, + // such as "windows", reads as zero. + private static int ReadComponent(string[] components, int index) + { + if (index >= components.Length) + { + return 0; + } + + string component = components[index]; + int length = 0; + while (length < component.Length && char.IsAsciiDigit(component[length])) + { + length++; + } + + return int.TryParse(component.AsSpan(0, length), NumberStyles.None, CultureInfo.InvariantCulture, out int value) ? value : 0; + } }