diff --git a/docs/design/versioning.md b/docs/design/versioning.md
index 76d57b39..4fb611af 100644
--- a/docs/design/versioning.md
+++ b/docs/design/versioning.md
@@ -23,7 +23,7 @@ Do not set `Version`, `FileVersion` or `InformationalVersion` in `Bravo.csproj`:
| `AssemblyInformationalVersion` | `X.Y.Z.{height}[-tag]+{commit}` | diagnostics |
| `AssemblyVersion` | `X.Y.0.0` | assembly identity (`assemblyVersion.precision: minor`) |
| `NBGV_SimpleVersion` | `X.Y.Z` | WiX `-dVersion` |
-| `NBGV_SemVer2` | `X.Y.Z[-tag]` | artifact names, git tag |
+| `NBGV_SemVer2` | `X.Y.Z[-tag]` | artifact names, git tag, `AppVersion.SemanticVersion` |
`{height}` is the number of commits since the numeric `X.Y.Z` last changed. It is a build counter: it makes
every build uniquely identifiable and orders builds that share the same `X.Y.Z`.
@@ -33,6 +33,12 @@ every build uniquely identifiable and orders builds that share the same `X.Y.Z`.
- **The prerelease tag never reaches a numeric field.** `AssemblyFileVersion` and `NBGV_SimpleVersion` stay
numeric in every state, so Windows Installer and `System.Version` keep working unchanged.
+- **`SemVer2` is the version that the application and the artifacts report.** The
+application reads it as `ThisAssembly.NuGetPackageVersion`, which equals `SemVer2` only while
+`nuGetPackageVersion.semVer` is `2` in `version.json` and `NBGV_ThisAssemblyIncludesPackageVersion` is set in
+`Bravo.csproj`. Without the first, the application reports the SemVer1 form `X.Y.Z-tag-0001-g{commit}`; without
+the second, it does not compile. A test in `AppVersionTests` checks the shape.
+
- **The height resets only when the numeric `X.Y.Z` changes.** Adding, changing or removing the prerelease tag
does not reset it. `AssemblyFileVersion` is therefore monotonic across `1.1.0-beta.1 → 1.1.0-beta.2 → 1.1.0`,
which is what makes a preview and its final release — identical on `X.Y.Z` — orderable.
@@ -43,12 +49,17 @@ to its final release changes `version.json` alone: such a filter would give the
`AssemblyFileVersion`.
- **`publicReleaseRefSpec` lists the branches that produce clean versions.** Outside them, `SemVer2` and
-`NuGetPackageVersion` carry a `.g{commit}` suffix; numeric fields are unaffected. A tag checkout runs in
+`NuGetPackageVersion` carry the commit id: `X.Y.Z-tag.g{commit}`, or `X.Y.Z-g{commit}` without a prerelease
+tag; numeric fields and `AssemblyInformationalVersion` are unaffected. A tag checkout runs in
detached HEAD and matches no branch pattern, so building from a tag requires adding the tag pattern.
- **Artifact names come from `SemVer2`, not from `SimpleVersion`.** The two are identical for a release and
differ only for a preview, where `SimpleVersion` drops the tag: naming artifacts from it would give a preview
and the release that follows it the same file names.
+- **NBGV reads `version.json` from `HEAD`, not from the working copy.** An edit takes effect from the commit
+that contains it: a build or a test run on a dirty `version.json` still reflects the committed values, and only
+the height resets.
+
- **The height needs full history.** Shallow clones make NBGV fail or compute a wrong number, so both
pipelines check out with unlimited depth.
diff --git a/src/Bravo.csproj b/src/Bravo.csproj
index db2588e4..58229c26 100644
--- a/src/Bravo.csproj
+++ b/src/Bravo.csproj
@@ -24,6 +24,7 @@
en-US
PerMonitorV2
true
+ true
diff --git a/src/Infrastructure/AppVersion.cs b/src/Infrastructure/AppVersion.cs
index e2de30bc..af44f33c 100644
--- a/src/Infrastructure/AppVersion.cs
+++ b/src/Infrastructure/AppVersion.cs
@@ -1,56 +1,27 @@
namespace Sqlbi.Bravo.Infrastructure;
///
-/// Application version, stamped from version.json by Nerdbank.GitVersioning.
+/// Provides application version information generated by Nerdbank.GitVersioning from version.json.
///
internal static class AppVersion
{
- static AppVersion()
- {
- IsPrerelease = ThisAssembly.IsPrerelease;
- IsPublicRelease = ThisAssembly.IsPublicRelease;
- FileVersion = ThisAssembly.AssemblyFileVersion;
- InformationalVersion = ThisAssembly.AssemblyInformationalVersion;
- SemanticVersion = System.Version.Parse(FileVersion).ToString(3) + GetPrereleaseTag(InformationalVersion);
- }
-
- ///
- /// True if the build is a prerelease, false if it is a release.
- ///
- public static bool IsPrerelease { get; }
-
- ///
- /// True if the build is a public release, false if it is a internal build (e.g. CI build).
- ///
- public static bool IsPublicRelease { get; }
-
///
- /// Four-part assembly file version Major.Minor.Patch.Height, where Height
- /// is the version height used to distinguish builds of the same release.
+ /// Four-part file version in the form Major.Minor.Patch.Height, where Height
+ /// distinguishes builds of the same version.
///
- public static string FileVersion { get; }
+ public static string FileVersion { get; } = ThisAssembly.AssemblyFileVersion;
///
- /// Semantic version of the application, including the prerelease label when present
- /// and excluding build metadata. e.g. 1.1.0-beta.1 or 1.1.0.
+ /// Semantic version of the application, including the prerelease label when present and
+ /// excluding build metadata, for example 1.1.0-beta.1 or 1.1.0.
+ /// Internal builds include the Git commit identifier, for example
+ /// 1.1.0-beta.1.g1c52e441d1, or 1.1.0-g1c52e441d1 without a prerelease label.
///
- public static string SemanticVersion { get; }
+ public static string SemanticVersion { get; } = ThisAssembly.NuGetPackageVersion;
///
- /// with the prerelease tag, if any, and the git commit id:
- /// 1.1.0.14-beta.1+1c52e441d1.
+ /// Informational version of the application, including the file version, prerelease label
+ /// when present, and Git commit identifier, for example 1.1.0.14-beta.1+1c52e441d1.
///
- public static string InformationalVersion { get; }
-
- internal static string GetPrereleaseTag(string informationalVersion)
- {
- var value = informationalVersion;
-
- var metadataIndex = value.IndexOf('+');
- if (metadataIndex >= 0)
- value = value[..metadataIndex];
-
- var prereleaseIndex = value.IndexOf('-');
- return prereleaseIndex < 0 ? string.Empty : value[prereleaseIndex..];
- }
+ public static string InformationalVersion { get; } = ThisAssembly.AssemblyInformationalVersion;
}
diff --git a/src/Infrastructure/AppWindow.cs b/src/Infrastructure/AppWindow.cs
index c7c86f5f..b345f86e 100644
--- a/src/Infrastructure/AppWindow.cs
+++ b/src/Infrastructure/AppWindow.cs
@@ -320,7 +320,6 @@ private MemoryStream GetConfigJs()
address = _serverAddressProvider.GetListeningAddress(),
token = AppEnvironment.ApiAuthenticationToken,
version = AppVersion.SemanticVersion,
- informationalVersion = AppVersion.InformationalVersion,
options = BravoOptions.CreateFromUserPreferences(),
policies = _policies,
culture = new
diff --git a/src/Infrastructure/Extensions/StringExtensions.cs b/src/Infrastructure/Extensions/StringExtensions.cs
index 0e475838..05cfc51b 100644
--- a/src/Infrastructure/Extensions/StringExtensions.cs
+++ b/src/Infrastructure/Extensions/StringExtensions.cs
@@ -16,14 +16,7 @@ internal static class StringExtensions
public static string AppendApplicationVersion(this string value)
{
- var result = $"{value} - v{AppVersion.SemanticVersion}";
-
- if (AppVersion.IsPrerelease || !AppVersion.IsPublicRelease)
- {
- result += $" ({AppVersion.InformationalVersion})";
- }
-
- return result;
+ return $"{value} - v{AppVersion.SemanticVersion}";
}
///
diff --git a/src/Scripts/@types/global.d.ts b/src/Scripts/@types/global.d.ts
index cf426624..d3749134 100644
--- a/src/Scripts/@types/global.d.ts
+++ b/src/Scripts/@types/global.d.ts
@@ -7,7 +7,6 @@ declare global {
debug?: boolean,
address: string
version: string,
- informationalVersion: string,
options: Options,
policies?: Policies,
token?: string,
diff --git a/src/Scripts/controllers/app.ts b/src/Scripts/controllers/app.ts
index 14a054ff..d311a31b 100644
--- a/src/Scripts/controllers/app.ts
+++ b/src/Scripts/controllers/app.ts
@@ -30,7 +30,6 @@ import { DialogResponse } from '../view/dialog';
export interface AppVersionInfo {
version: string
- informationalVersion?: string
downloadUrl?: string
changelogUrl?: string
}
diff --git a/src/Scripts/controllers/debug.ts b/src/Scripts/controllers/debug.ts
index 99ae05ca..b88fa0ce 100644
--- a/src/Scripts/controllers/debug.ts
+++ b/src/Scripts/controllers/debug.ts
@@ -38,7 +38,6 @@ export class Debug {
debug: true,
address: "http://localhost",
version: "0.0.0-debug",
- informationalVersion: "0.0.0.0-debug+0000000000",
options: null,
token: "",
culture: {
diff --git a/src/Scripts/main.ts b/src/Scripts/main.ts
index f782b547..6830bb70 100644
--- a/src/Scripts/main.ts
+++ b/src/Scripts/main.ts
@@ -31,8 +31,7 @@ let pbiDesktop = new PBIDesktop();
let notificationCenter = new NotifyCenter();
let app = new App(new AppVersion({
- version: CONFIG.version,
- informationalVersion: CONFIG.informationalVersion
+ version: CONFIG.version
}));
export { debug, host, optionsController, themeController, auth, telemetry, pbiDesktop, notificationCenter, logger, app };
\ No newline at end of file
diff --git a/src/Scripts/view/options-dialog-about.ts b/src/Scripts/view/options-dialog-about.ts
index 989704e5..6ae5ccba 100644
--- a/src/Scripts/view/options-dialog-about.ts
+++ b/src/Scripts/view/options-dialog-about.ts
@@ -83,7 +83,7 @@ export class OptionsDialogAbout {
_(".copy-version", element).addEventListener("click", e => {
e.preventDefault();
- navigator.clipboard.writeText(app.currentVersion.info.informationalVersion ?? app.currentVersion.toString());
+ navigator.clipboard.writeText(app.currentVersion.toString());
});
_(".auto-check-option input", element).addEventListener("change", e => {
diff --git a/test/Bravo.Tests/Infrastructure/AppVersionTests.cs b/test/Bravo.Tests/Infrastructure/AppVersionTests.cs
index b6f77063..daa252db 100644
--- a/test/Bravo.Tests/Infrastructure/AppVersionTests.cs
+++ b/test/Bravo.Tests/Infrastructure/AppVersionTests.cs
@@ -5,19 +5,6 @@ namespace Bravo.Tests.Infrastructure;
public class AppVersionTests
{
- [Theory]
- [InlineData("1.1.0.11+ed89094be9", "")]
- [InlineData("1.1.0.13-beta.1+57e453666e", "-beta.1")]
- [InlineData("1.1.0.13-beta.1", "-beta.1")]
- [InlineData("1.1.0.0-build.99+74e5ed577e", "-build.99")]
- [InlineData("1.1.0.13", "")]
- public void GetPrereleaseTag_ReadsTheTag(string informationalVersion, string expected)
- {
- var actual = AppVersion.GetPrereleaseTag(informationalVersion);
-
- Assert.Equal(expected, actual);
- }
-
[Fact]
public void FileVersion_IsNumericWithFourFields()
{
@@ -37,6 +24,36 @@ public void SemanticVersion_StartsWithTheNumericReleaseVersion()
Assert.StartsWith(releaseVersion, AppVersion.SemanticVersion);
}
+ [Fact]
+ public void SemanticVersion_HasNoBuildMetadata()
+ {
+ Assert.DoesNotContain("+", AppVersion.SemanticVersion);
+ }
+
+ [Fact]
+ public void SemanticVersion_CarriesTheCommitIdOnlyOutsideAPublicRelease()
+ {
+ // SemanticVersion must be NBGV SemVer2, the value used for artifact names and installer telemetry: outside
+ // publicReleaseRefSpec it ends with 'g{commit}', where the commit is the build metadata of the informational
+ // version.
+ var metadataIndex = AppVersion.InformationalVersion.IndexOf('+');
+ Assert.True(metadataIndex >= 0, $"'{AppVersion.InformationalVersion}' has no build metadata.");
+
+ var commitId = AppVersion.InformationalVersion[(metadataIndex + 1)..];
+ var isPublicRelease = ThisAssembly.IsPublicRelease;
+ var isPrerelease = ThisAssembly.IsPrerelease;
+
+ if (isPublicRelease)
+ {
+ Assert.DoesNotContain(commitId, AppVersion.SemanticVersion);
+ }
+ else
+ {
+ var separator = isPrerelease ? '.' : '-';
+ Assert.EndsWith($"{separator}g{commitId}", AppVersion.SemanticVersion);
+ }
+ }
+
[Fact]
public void InformationalVersion_StartsWithFileVersion()
{
diff --git a/test/Bravo.Tests/Infrastructure/Extensions/StringExtensionsTests.cs b/test/Bravo.Tests/Infrastructure/Extensions/StringExtensionsTests.cs
index 77580f6c..e636c999 100644
--- a/test/Bravo.Tests/Infrastructure/Extensions/StringExtensionsTests.cs
+++ b/test/Bravo.Tests/Infrastructure/Extensions/StringExtensionsTests.cs
@@ -64,8 +64,7 @@ public void AppendApplicationVersion_Test()
{
var actual = "Bravo for Power BI".AppendApplicationVersion();
- Assert.NotNull(actual);
- Assert.StartsWith("Bravo for Power BI", actual);
+ Assert.Equal($"Bravo for Power BI - v{AppVersion.SemanticVersion}", actual);
}
[Fact]
diff --git a/version.json b/version.json
index 5dc29a5e..052767bd 100644
--- a/version.json
+++ b/version.json
@@ -4,6 +4,10 @@
"assemblyVersion": {
"precision": "minor"
},
+ "nuGetPackageVersion": {
+ "semVer": 2,
+ "precision": "build"
+ },
"pathFilters": [
":/"
],