Skip to content

Commit db23e17

Browse files
authored
Merge pull request #2880 from chris-codeflow/feature/Improve-ToString
Improve SemanticVersion.ToString implementation
2 parents e0b0ff7 + de8cbcf commit db23e17

File tree

4 files changed

+97
-176
lines changed

4 files changed

+97
-176
lines changed

src/GitVersion.Core.Tests/VersionCalculation/SemanticVersionTests.cs

+77-164
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ namespace GitVersion.Core.Tests;
88
[TestFixture]
99
public class SemanticVersionTests : TestBase
1010
{
11-
1211
[TestCase("1.2.3", 1, 2, 3, null, null, null, null, null, null, null, null)]
1312
[TestCase("1.2", 1, 2, 0, null, null, null, null, null, null, "1.2.0", null)]
1413
[TestCase("1.2.3-beta", 1, 2, 3, "beta", null, null, null, null, null, null, null)]
@@ -79,183 +78,97 @@ public void VersionSorting()
7978
}
8079

8180
[Test]
82-
public void ToStringJTests()
81+
public void ToStringWithInvalidFormatTest()
8382
{
84-
Assert.AreEqual("1.2.3", SemanticVersion.Parse("1.2.3", null).ToString("j"));
85-
Assert.AreEqual("1.2.3", SemanticVersion.Parse("1.2.3-beta.4", null).ToString("j"));
86-
var fullSemVer = new SemanticVersion
87-
{
88-
Major = 1,
89-
Minor = 2,
90-
Patch = 3,
91-
PreReleaseTag = new SemanticVersionPreReleaseTag("beta", 4),
92-
BuildMetaData = new SemanticVersionBuildMetaData
93-
{
94-
Sha = "theSha",
95-
Branch = "TheBranch",
96-
CommitsSinceTag = 5,
97-
OtherMetaData = "TheOtherMetaData"
98-
}
99-
};
100-
Assert.AreEqual("1.2.3", fullSemVer.ToString("j"));
83+
var semVer = BuildSemVer(1, 2, 3, "rc", 1, 1);
84+
Should.Throw<FormatException>(() => semVer.ToString("invalid"));
10185
}
102-
[Test]
103-
public void ToStringSTests()
86+
87+
[TestCase(1, 2, 3, null, null, null, null, null, null, ExpectedResult = "1.2.3")]
88+
[TestCase(1, 2, 3, "beta", 4, null, null, null, null, ExpectedResult = "1.2.3-beta.4")]
89+
[TestCase(1, 2, 3, "beta", 4, 5, "theBranch", "theSha", "theOtherMetaData", ExpectedResult = "1.2.3-beta.4")]
90+
[TestCase(1, 2, 3, "", 4, 5, "theBranch", "theSha", "theOtherMetaData", ExpectedResult = "1.2.3-4")]
91+
public string ToStringTests(int major, int minor, int patch, string preReleaseName, int preReleaseVersion, int? buildCount, string branchName, string sha, string otherMetadata)
10492
{
105-
Assert.AreEqual("1.2.3", SemanticVersion.Parse("1.2.3", null).ToString("s"));
106-
Assert.AreEqual("1.2.3-beta.4", SemanticVersion.Parse("1.2.3-beta.4", null).ToString("s"));
107-
var fullSemVer = new SemanticVersion
108-
{
109-
Major = 1,
110-
Minor = 2,
111-
Patch = 3,
112-
PreReleaseTag = new SemanticVersionPreReleaseTag("beta", 4),
113-
BuildMetaData = new SemanticVersionBuildMetaData
114-
{
115-
Sha = "theSha",
116-
Branch = "TheBranch",
117-
CommitsSinceTag = 5,
118-
OtherMetaData = "TheOtherMetaData"
119-
}
120-
};
121-
Assert.AreEqual("1.2.3-beta.4", fullSemVer.ToString("s"));
122-
var fullSemVerNoPreReleaseName = new SemanticVersion
123-
{
124-
Major = 1,
125-
Minor = 2,
126-
Patch = 3,
127-
PreReleaseTag = new SemanticVersionPreReleaseTag("", 4),
128-
BuildMetaData = new SemanticVersionBuildMetaData
129-
{
130-
Sha = "theSha",
131-
Branch = "TheBranch",
132-
CommitsSinceTag = 5,
133-
OtherMetaData = "TheOtherMetaData"
134-
}
135-
};
136-
Assert.AreEqual("1.2.3-4", fullSemVerNoPreReleaseName.ToString("s"));
93+
var semVer = BuildSemVer(major, minor, patch, preReleaseName, preReleaseVersion, buildCount, branchName, sha, otherMetadata);
94+
return semVer.ToString();
13795
}
138-
[Test]
139-
public void ToStringLTests()
96+
97+
[TestCase(1, 2, 3, null, null, null, null, null, null, ExpectedResult = "1.2.3")]
98+
[TestCase(1, 2, 3, "beta", 4, null, null, null, null, ExpectedResult = "1.2.3-beta.4")]
99+
[TestCase(1, 2, 3, "beta", 4, 5, "theBranch", "theSha", "theOtherMetaData", ExpectedResult = "1.2.3-beta.4")]
100+
[TestCase(1, 2, 3, "", 4, 10, "theBranch", "theSha", "theOtherMetaData", ExpectedResult = "1.2.3-4")]
101+
public string ToStringWithSFormatTests(int major, int minor, int patch, string preReleaseName, int preReleaseVersion, int? buildCount, string branchName, string sha, string otherMetadata)
140102
{
141-
Assert.AreEqual("1.2.3", SemanticVersion.Parse("1.2.3", null).ToString("l"));
142-
Assert.AreEqual("1.2.3-beta4", SemanticVersion.Parse("1.2.3-beta.4", null).ToString("l"));
143-
var fullSemVer = new SemanticVersion
144-
{
145-
Major = 1,
146-
Minor = 2,
147-
Patch = 3,
148-
PreReleaseTag = new SemanticVersionPreReleaseTag("beta", 4),
149-
BuildMetaData = new SemanticVersionBuildMetaData
150-
{
151-
Sha = "theSha",
152-
Branch = "TheBranch",
153-
CommitsSinceTag = 5,
154-
OtherMetaData = "TheOtherMetaData"
155-
}
156-
};
157-
Assert.AreEqual("1.2.3-beta4", fullSemVer.ToString("l"));
103+
var semVer = BuildSemVer(major, minor, patch, preReleaseName, preReleaseVersion, buildCount, branchName, sha, otherMetadata);
104+
return semVer.ToString("s");
158105
}
159-
[Test]
160-
public void ToStringLpTests()
106+
107+
[TestCase(1, 2, 3, null, null, null, null, null, null, ExpectedResult = "1.2.3")]
108+
[TestCase(1, 2, 3, "beta", 4, null, null, null, null, ExpectedResult = "1.2.3")]
109+
[TestCase(1, 2, 3, "beta", 4, 5, "theBranch", "theSha", "theOtherMetaData", ExpectedResult = "1.2.3")]
110+
public string ToStringWithFormatJTests(int major, int minor, int patch, string preReleaseName, int preReleaseVersion, int? buildCount, string branchName, string sha, string otherMetadata)
161111
{
162-
Assert.AreEqual("1.2.3", SemanticVersion.Parse("1.2.3", null).ToString("lp"));
163-
Assert.AreEqual("1.2.3-beta0004", SemanticVersion.Parse("1.2.3-beta.4", null).ToString("lp"));
164-
var fullSemVer = new SemanticVersion
165-
{
166-
Major = 1,
167-
Minor = 2,
168-
Patch = 3,
169-
PreReleaseTag = new SemanticVersionPreReleaseTag("beta", 4),
170-
BuildMetaData = new SemanticVersionBuildMetaData
171-
{
172-
Sha = "theSha",
173-
Branch = "TheBranch",
174-
CommitsSinceTag = 5,
175-
OtherMetaData = "TheOtherMetaData"
176-
}
177-
};
178-
Assert.AreEqual("1.2.3-beta0004", fullSemVer.ToString("lp"));
112+
var semVer = BuildSemVer(major, minor, patch, preReleaseName, preReleaseVersion, buildCount, branchName, sha, otherMetadata);
113+
return semVer.ToString("j");
179114
}
180-
[Test]
181-
public void ToStringTests()
115+
116+
[TestCase(1, 2, 3, null, null, null, null, null, null, ExpectedResult = "1.2.3")]
117+
[TestCase(1, 2, 3, "beta", 4, null, null, null, null, ExpectedResult = "1.2.3-beta4")]
118+
[TestCase(1, 2, 3, "beta", 4, 5, "theBranch", "theSha", "theOtherMetaData", ExpectedResult = "1.2.3-beta4")]
119+
public string ToStringWithFormatLTests(int major, int minor, int patch, string preReleaseName, int preReleaseVersion, int? buildCount, string branchName, string sha, string otherMetadata)
182120
{
183-
Assert.AreEqual("1.2.3", SemanticVersion.Parse("1.2.3", null).ToString());
184-
Assert.AreEqual("1.2.3-beta.4", SemanticVersion.Parse("1.2.3-beta.4", null).ToString());
185-
Assert.AreEqual("1.2.3-beta.4", SemanticVersion.Parse("1.2.3-beta.4+5", null).ToString());
186-
var fullSemVer = new SemanticVersion
187-
{
188-
Major = 1,
189-
Minor = 2,
190-
Patch = 3,
191-
PreReleaseTag = new SemanticVersionPreReleaseTag("beta", 4),
192-
BuildMetaData = new SemanticVersionBuildMetaData
193-
{
194-
Sha = "theSha",
195-
Branch = "TheBranch",
196-
CommitsSinceTag = 5,
197-
OtherMetaData = "TheOtherMetaData"
198-
}
199-
};
200-
Assert.AreEqual("1.2.3-beta.4", fullSemVer.ToString());
201-
var fullSemVerNoPreReleaseName = new SemanticVersion
202-
{
203-
Major = 1,
204-
Minor = 2,
205-
Patch = 3,
206-
PreReleaseTag = new SemanticVersionPreReleaseTag("", 4),
207-
BuildMetaData = new SemanticVersionBuildMetaData
208-
{
209-
Sha = "theSha",
210-
Branch = "TheBranch",
211-
CommitsSinceTag = 5,
212-
OtherMetaData = "TheOtherMetaData"
213-
}
214-
};
215-
Assert.AreEqual("1.2.3-4", fullSemVerNoPreReleaseName.ToString());
121+
var semVer = BuildSemVer(major, minor, patch, preReleaseName, preReleaseVersion, buildCount, branchName, sha, otherMetadata);
122+
return semVer.ToString("l");
216123
}
217-
[Test]
218-
public void ToStringFTests()
124+
125+
[TestCase(1, 2, 3, null, null, null, null, null, null, ExpectedResult = "1.2.3")]
126+
[TestCase(1, 2, 3, "beta", 4, null, null, null, null, ExpectedResult = "1.2.3-beta0004")]
127+
[TestCase(1, 2, 3, "beta", 4, 5, "theBranch", "theSha", "theOtherMetaData", ExpectedResult = "1.2.3-beta0004")]
128+
public string ToStringWithFormatLpTests(int major, int minor, int patch, string preReleaseName, int preReleaseVersion, int? buildCount, string branchName, string sha, string otherMetadata)
219129
{
220-
Assert.AreEqual("1.2.3", SemanticVersion.Parse("1.2.3", null).ToString("f"));
221-
Assert.AreEqual("1.2.3-beta.4", SemanticVersion.Parse("1.2.3-beta.4", null).ToString("f"));
222-
Assert.AreEqual("1.2.3-beta.4+5", SemanticVersion.Parse("1.2.3-beta.4+5", null).ToString("f"));
223-
var fullSemVer = new SemanticVersion
224-
{
225-
Major = 1,
226-
Minor = 2,
227-
Patch = 3,
228-
PreReleaseTag = new SemanticVersionPreReleaseTag("beta", 4),
229-
BuildMetaData = new SemanticVersionBuildMetaData
230-
{
231-
Sha = "theSha",
232-
Branch = "TheBranch",
233-
CommitsSinceTag = 5,
234-
OtherMetaData = "TheOtherMetaData"
235-
}
236-
};
237-
Assert.AreEqual("1.2.3-beta.4+5", fullSemVer.ToString("f"));
130+
var semVer = BuildSemVer(major, minor, patch, preReleaseName, preReleaseVersion, buildCount, branchName, sha, otherMetadata);
131+
return semVer.ToString("lp");
238132
}
239-
[Test]
240-
public void ToStringITests()
133+
134+
[TestCase(1, 2, 3, null, null, null, null, null, null, ExpectedResult = "1.2.3")]
135+
[TestCase(1, 2, 3, "beta", 4, null, null, null, null, ExpectedResult = "1.2.3-beta.4")]
136+
[TestCase(1, 2, 3, "beta", 4, 5, null, null, null, ExpectedResult = "1.2.3-beta.4+5")]
137+
[TestCase(1, 2, 3, "", 4, 5, "theBranch", "theSha", "theOtherMetaData", ExpectedResult = "1.2.3-4+5")]
138+
public string ToStringWithFormatFTests(int major, int minor, int patch, string preReleaseName, int preReleaseVersion, int? buildCount, string branchName, string sha, string otherMetadata)
241139
{
242-
Assert.AreEqual("1.2.3-beta.4", SemanticVersion.Parse("1.2.3-beta.4", null).ToString("i"));
243-
Assert.AreEqual("1.2.3", SemanticVersion.Parse("1.2.3", null).ToString("i"));
244-
Assert.AreEqual("1.2.3-beta.4+5", SemanticVersion.Parse("1.2.3-beta.4+5", null).ToString("i"));
245-
var fullSemVer = new SemanticVersion
140+
var semVer = BuildSemVer(major, minor, patch, preReleaseName, preReleaseVersion, buildCount, branchName, sha, otherMetadata);
141+
return semVer.ToString("f");
142+
}
143+
144+
[TestCase(1, 2, 3, null, null, null, null, null, null, ExpectedResult = "1.2.3")]
145+
[TestCase(1, 2, 3, "beta", 4, null, null, null, null, ExpectedResult = "1.2.3-beta.4")]
146+
[TestCase(1, 2, 3, "beta", 4, 5, null, null, null, ExpectedResult = "1.2.3-beta.4+5")]
147+
[TestCase(1, 2, 3, "beta", 4, 5, "theBranch", "theSha", "theOtherMetaData", ExpectedResult = "1.2.3-beta.4+5.Branch.theBranch.Sha.theSha.theOtherMetaData")]
148+
public string ToStringWithFormatITests(int major, int minor, int patch, string preReleaseName, int preReleaseVersion, int? buildCount, string branchName, string sha, string otherMetadata)
149+
{
150+
var semVer = BuildSemVer(major, minor, patch, preReleaseName, preReleaseVersion, buildCount, branchName, sha, otherMetadata);
151+
return semVer.ToString("i");
152+
}
153+
154+
private static SemanticVersion BuildSemVer(int major, int minor, int patch, string preReleaseName, int preReleaseVersion, int? buildCount, string branchName = null, string sha = null, string otherMetadata = null)
155+
{
156+
var semVer = new SemanticVersion(major, minor, patch);
157+
if (preReleaseName != null)
246158
{
247-
Major = 1,
248-
Minor = 2,
249-
Patch = 3,
250-
PreReleaseTag = new SemanticVersionPreReleaseTag("beta", 4),
251-
BuildMetaData = new SemanticVersionBuildMetaData
159+
semVer.PreReleaseTag = new SemanticVersionPreReleaseTag(preReleaseName, preReleaseVersion);
160+
}
161+
if (buildCount.HasValue)
162+
{
163+
semVer.BuildMetaData = new SemanticVersionBuildMetaData
252164
{
253-
Sha = "theSha",
254-
Branch = "TheBranch",
255-
CommitsSinceTag = 5,
256-
OtherMetaData = "TheOtherMetaData"
257-
}
258-
};
259-
Assert.AreEqual("1.2.3-beta.4+5.Branch.TheBranch.Sha.theSha.TheOtherMetaData", fullSemVer.ToString("i"));
165+
CommitsSinceTag = buildCount.Value,
166+
Sha = sha,
167+
Branch = branchName,
168+
OtherMetaData = otherMetadata
169+
};
170+
}
171+
172+
return semVer;
260173
}
261174
}

src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersion.cs

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Diagnostics.CodeAnalysis;
2+
using System.Globalization;
23
using System.Text.RegularExpressions;
34
using GitVersion.Extensions;
45

@@ -221,18 +222,20 @@ public int CompareTo(SemanticVersion? value, bool includePrerelease)
221222
return 0;
222223
}
223224

224-
public override string ToString() => ToString(null);
225+
public override string ToString() => ToString("s");
226+
227+
public string ToString(string format) => ToString(format, CultureInfo.CurrentCulture);
225228

226229
/// <summary>
227-
/// <para>s - Default SemVer [1.2.3-beta.4+5]</para>
230+
/// <para>s - Default SemVer [1.2.3-beta.4]</para>
228231
/// <para>f - Full SemVer [1.2.3-beta.4+5]</para>
229232
/// <para>i - Informational SemVer [1.2.3-beta.4+5.Branch.main.BranchType.main.Sha.000000]</para>
230233
/// <para>j - Just the SemVer part [1.2.3]</para>
231234
/// <para>t - SemVer with the tag [1.2.3-beta.4]</para>
232235
/// <para>l - Legacy SemVer tag for systems which do not support SemVer 2.0 properly [1.2.3-beta4]</para>
233236
/// <para>lp - Legacy SemVer tag for systems which do not support SemVer 2.0 properly (padded) [1.2.3-beta0004]</para>
234237
/// </summary>
235-
public string ToString(string? format, IFormatProvider? formatProvider = null)
238+
public string ToString(string format, IFormatProvider formatProvider)
236239
{
237240
if (format.IsNullOrEmpty())
238241
format = "s";
@@ -271,7 +274,7 @@ public string ToString(string? format, IFormatProvider? formatProvider = null)
271274
return !buildMetadata.IsNullOrEmpty() ? $"{ToString("s")}+{buildMetadata}" : ToString("s");
272275
}
273276
default:
274-
throw new ArgumentException($"Unrecognised format '{format}'", nameof(format));
277+
throw new FormatException($"Unknown format '{format}'.");
275278
}
276279
}
277280

src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersionBuildMetaData.cs

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Globalization;
12
using System.Text.RegularExpressions;
23
using GitVersion.Extensions;
34
using GitVersion.Helpers;
@@ -59,15 +60,17 @@ public SemanticVersionBuildMetaData(SemanticVersionBuildMetaData? buildMetaData)
5960

6061
public override int GetHashCode() => EqualityHelper.GetHashCode(this);
6162

62-
public override string ToString() => ToString(null);
63+
public override string ToString() => ToString("b");
64+
65+
public string ToString(string format) => ToString(format, CultureInfo.CurrentCulture);
6366

6467
/// <summary>
6568
/// <para>b - Formats just the build number</para>
6669
/// <para>s - Formats the build number and the Git Sha</para>
6770
/// <para>f - Formats the full build metadata</para>
6871
/// <para>p - Formats the padded build number. Can specify an integer for padding, default is 4. (i.e., p5)</para>
6972
/// </summary>
70-
public string ToString(string? format, IFormatProvider? formatProvider = null)
73+
public string ToString(string format, IFormatProvider formatProvider)
7174
{
7275
if (formatProvider != null)
7376
{
@@ -100,7 +103,7 @@ public string ToString(string? format, IFormatProvider? formatProvider = null)
100103
"b" => this.CommitsSinceTag.ToString(),
101104
"s" => $"{this.CommitsSinceTag}{(this.Sha.IsNullOrEmpty() ? null : ".Sha." + this.Sha)}".TrimStart('.'),
102105
"f" => $"{this.CommitsSinceTag}{(this.Branch.IsNullOrEmpty() ? null : ".Branch." + FormatMetaDataPart(this.Branch))}{(this.Sha.IsNullOrEmpty() ? null : ".Sha." + this.Sha)}{(this.OtherMetaData.IsNullOrEmpty() ? null : "." + FormatMetaDataPart(this.OtherMetaData))}".TrimStart('.'),
103-
_ => throw new ArgumentException("Unrecognised format", nameof(format))
106+
_ => throw new FormatException($"Unknown format '{format}'.")
104107
};
105108
}
106109

src/GitVersion.Core/VersionCalculation/SemanticVersioning/SemanticVersionPreReleaseTag.cs

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Globalization;
12
using System.Text.RegularExpressions;
23
using GitVersion.Extensions;
34
using GitVersion.Helpers;
@@ -93,23 +94,24 @@ public int CompareTo(SemanticVersionPreReleaseTag? other)
9394
return -1;
9495
}
9596

96-
9797
var nameComparison = StringComparerUtils.IgnoreCaseComparer.Compare(Name, other?.Name);
9898
if (nameComparison != 0)
9999
return nameComparison;
100100

101101
return Nullable.Compare(Number, other?.Number);
102102
}
103103

104-
public override string? ToString() => ToString(null);
104+
public override string ToString() => ToString("t");
105+
106+
public string ToString(string format) => ToString(format, CultureInfo.CurrentCulture);
105107

106108
/// <summary>
107109
/// Default formats:
108110
/// <para>t - SemVer 2.0 formatted tag [beta.1]</para>
109111
/// <para>l - Legacy SemVer tag with the tag number padded. [beta1]</para>
110112
/// <para>lp - Legacy SemVer tag with the tag number padded. [beta0001]. Can specify an integer to control padding (i.e., lp5)</para>
111113
/// </summary>
112-
public string? ToString(string? format, IFormatProvider? formatProvider = null)
114+
public string ToString(string format, IFormatProvider formatProvider)
113115
{
114116
if (formatProvider != null)
115117
{
@@ -139,9 +141,9 @@ public int CompareTo(SemanticVersionPreReleaseTag? other)
139141

140142
return format switch
141143
{
142-
"t" => (Number.HasValue ? Name.IsNullOrEmpty() ? $"{Number}" : $"{Name}.{Number}" : Name),
144+
"t" => (Number.HasValue ? Name.IsNullOrEmpty() ? $"{Number}" : $"{Name}.{Number}" : Name ?? string.Empty),
143145
"l" => (Number.HasValue ? FormatLegacy(GetLegacyName(), Number.Value.ToString()) : FormatLegacy(GetLegacyName())),
144-
_ => throw new ArgumentException("Unknown format", nameof(format))
146+
_ => throw new FormatException($"Unknown format '{format}'.")
145147
};
146148
}
147149

0 commit comments

Comments
 (0)