Build identity: version + git hash synced to releases #24
No files matched your search
@@ -10,4 +10,14 @@
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Single version source. Local builds are 0.1.0-dev; release builds pass an
|
||||
explicit -p:Version=<tag-version>, which overrides both parts. The SDK's
|
||||
built-in SourceLink appends the git commit as "+<sha>" build metadata on
|
||||
AssemblyInformationalVersion, which the About dialog and the CLI's
|
||||
version output surface as the short hash. -->
|
||||
<PropertyGroup>
|
||||
<VersionPrefix>0.1.0</VersionPrefix>
|
||||
<VersionSuffix>dev</VersionSuffix>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
+1
-1
@@ -234,5 +234,5 @@ done
|
||||
|
||||
```console
|
||||
$ gclo --version
|
||||
0.1.0
|
||||
0.1.0-beta.6 (9ac6c2bde)
|
||||
```
|
||||
+4
-13
@@ -1,4 +1,4 @@
|
||||
using System.Reflection;
|
||||
using gclo.Engine;
|
||||
|
||||
namespace gclo.Cli;
|
||||
|
||||
@@ -102,16 +102,7 @@ internal static class Program
|
||||
}
|
||||
|
||||
private static string Version()
|
||||
{
|
||||
Assembly assembly = typeof(Program).Assembly;
|
||||
string version =
|
||||
assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion
|
||||
?? assembly.GetName().Version?.ToString()
|
||||
?? "unknown";
|
||||
|
||||
// Strip the '+<metadata>' suffix (e.g. a SourceLink commit hash); it is
|
||||
// noise for a scripted version check.
|
||||
int plus = version.IndexOf('+');
|
||||
return plus >= 0 ? version[..plus] : version;
|
||||
}
|
||||
// Shared with the GUI's About dialog: "0.1.0-beta.6 (9ac6c2b)" for
|
||||
// releases, "0.1.0-dev (<hash>)" for local builds.
|
||||
=> BuildVersion.Describe(typeof(Program).Assembly);
|
||||
}
|
||||
@@ -8,7 +8,6 @@
|
||||
<AssemblyName>gclo</AssemblyName>
|
||||
<RootNamespace>gclo.Cli</RootNamespace>
|
||||
<InvariantGlobalization>true</InvariantGlobalization>
|
||||
<Version>0.1.0</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
using gclo.Engine;
|
||||
|
||||
namespace gclo.Engine.Tests;
|
||||
|
||||
/// <summary>Formatting of the version + git-hash build identity string.</summary>
|
||||
public sealed class BuildVersionTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(null, "unknown")]
|
||||
[InlineData("", "unknown")]
|
||||
[InlineData(" ", "unknown")]
|
||||
[InlineData("1.2.3", "1.2.3")]
|
||||
[InlineData("0.1.0-dev", "0.1.0-dev")]
|
||||
[InlineData("0.1.0-beta.6+9ac6c2b1234567890abcdef", "0.1.0-beta.6 (9ac6c2b12)")]
|
||||
[InlineData("1.2.3+abc", "1.2.3 (abc)")]
|
||||
[InlineData("1.2.3+9ac6c2b1234567890.dirty", "1.2.3 (9ac6c2b12)")]
|
||||
[InlineData("1.2.3+", "1.2.3")]
|
||||
public void Format_ProducesReadableIdentity(string? informational, string expected)
|
||||
{
|
||||
Assert.Equal(expected, BuildVersion.Format(informational));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Describe_UsesThisAssembly_AndNeverThrows()
|
||||
{
|
||||
string described = BuildVersion.Describe(typeof(BuildVersionTests).Assembly);
|
||||
|
||||
Assert.False(string.IsNullOrWhiteSpace(described));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using System.Reflection;
|
||||
|
||||
namespace gclo.Engine;
|
||||
|
||||
/// <summary>
|
||||
/// Human-readable build identity shared by the app's About dialog and the CLI's
|
||||
/// version output: the semantic version plus the short git commit the build came
|
||||
/// from, e.g. "0.1.0-beta.6 (9ac6c2b)" for releases or "0.1.0-dev (3a87f9e)" for
|
||||
/// local builds.
|
||||
/// </summary>
|
||||
public static class BuildVersion
|
||||
{
|
||||
private const int ShortHashLength = 9;
|
||||
|
||||
/// <summary>Describes <paramref name="assembly"/>'s version and commit.</summary>
|
||||
public static string Describe(Assembly assembly)
|
||||
=> Format(assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion
|
||||
?? assembly.GetName().Version?.ToString());
|
||||
|
||||
/// <summary>
|
||||
/// Formats an informational version: the "+<metadata>" suffix that SourceLink
|
||||
/// appends becomes a parenthesized short commit hash.
|
||||
/// </summary>
|
||||
public static string Format(string? informationalVersion)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(informationalVersion))
|
||||
{
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
int plus = informationalVersion.IndexOf('+');
|
||||
if (plus < 0)
|
||||
{
|
||||
return informationalVersion;
|
||||
}
|
||||
|
||||
string version = informationalVersion[..plus];
|
||||
string metadata = informationalVersion[(plus + 1)..];
|
||||
// Metadata may carry more than the sha (dot-separated); the hash is first.
|
||||
int dot = metadata.IndexOf('.');
|
||||
string hash = dot >= 0 ? metadata[..dot] : metadata;
|
||||
if (hash.Length > ShortHashLength)
|
||||
{
|
||||
hash = hash[..ShortHashLength];
|
||||
}
|
||||
|
||||
return hash.Length == 0 ? version : $"{version} ({hash})";
|
||||
}
|
||||
}
|
||||
@@ -18,29 +18,13 @@ namespace gclo
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the app version formatted as "major.minor.build". Prefers the MSIX
|
||||
/// package version; Package.Current throws when the app runs unpackaged
|
||||
/// (no package identity), in which case the assembly version is used instead.
|
||||
/// Returns the build identity synced to the release pipeline: the semantic
|
||||
/// version CI injects for the tag (0.1.0-dev on local builds) plus the short
|
||||
/// git commit, e.g. "0.1.0-beta.6 (9ac6c2b)". The MSIX package version is
|
||||
/// deliberately not used — its numeric quad cannot carry prerelease tags or
|
||||
/// commit hashes, so it cannot distinguish a local build from a release.
|
||||
/// </summary>
|
||||
private static string GetAppVersion()
|
||||
{
|
||||
try
|
||||
{
|
||||
var packageVersion = Windows.ApplicationModel.Package.Current.Id.Version;
|
||||
return $"{packageVersion.Major}.{packageVersion.Minor}.{packageVersion.Build}";
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Version? assemblyVersion = Assembly.GetExecutingAssembly().GetName().Version;
|
||||
if (assemblyVersion is null)
|
||||
{
|
||||
return "1.0.0";
|
||||
}
|
||||
|
||||
// Version.Build is -1 when the assembly version has fewer than three parts.
|
||||
int build = assemblyVersion.Build < 0 ? 0 : assemblyVersion.Build;
|
||||
return $"{assemblyVersion.Major}.{assemblyVersion.Minor}.{build}";
|
||||
}
|
||||
}
|
||||
=> gclo.Engine.BuildVersion.Describe(Assembly.GetExecutingAssembly());
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user