From db458e6e4d33e8c3a79c5b375a8a8810303c771b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Feb 2026 16:26:57 +0000 Subject: [PATCH 1/4] Initial plan From 06f35602781012fa5d6ad96afeec822260673615 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Feb 2026 16:32:37 +0000 Subject: [PATCH 2/4] Implement from-version selection rules for pre-release and release versions Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com> --- .../RepoConnectors/GitHubRepoConnector.cs | 54 +++-- .../GitHubRepoConnectorTests.cs | 187 ++++++++++++++++++ 2 files changed, 230 insertions(+), 11 deletions(-) diff --git a/src/DemaConsulting.BuildMark/RepoConnectors/GitHubRepoConnector.cs b/src/DemaConsulting.BuildMark/RepoConnectors/GitHubRepoConnector.cs index ea5f6c1..7f2def5 100644 --- a/src/DemaConsulting.BuildMark/RepoConnectors/GitHubRepoConnector.cs +++ b/src/DemaConsulting.BuildMark/RepoConnectors/GitHubRepoConnector.cs @@ -87,7 +87,7 @@ public override async Task GetBuildInformationAsync(Version? v var (toVersion, toHash) = DetermineTargetVersion(version, currentCommitHash.Trim(), lookupData); // Determine the starting release for comparing changes - var (fromVersion, fromHash) = DetermineBaselineVersion(toVersion, lookupData); + var (fromVersion, fromHash) = DetermineBaselineVersion(toVersion, toHash, lookupData); // Get commits in range var commitsInRange = GetCommitsInRange(gitHubData.Commits, fromHash, toHash); @@ -348,10 +348,12 @@ private static (Version toVersion, string toHash) DetermineTargetVersion( /// Determines the baseline version for comparing changes. /// /// Target version. + /// Commit hash of target version. /// Lookup data structures. /// Tuple of (fromVersion, fromHash). private static (Version? fromVersion, string? fromHash) DetermineBaselineVersion( Version toVersion, + string toHash, LookupData lookupData) { // Return null baseline if no releases exist @@ -365,7 +367,7 @@ private static (Version? fromVersion, string? fromHash) DetermineBaselineVersion // Determine baseline version based on whether target is pre-release var fromVersion = toVersion.IsPreRelease - ? DetermineBaselineForPreRelease(toIndex, lookupData.ReleaseVersions) + ? DetermineBaselineForPreRelease(toIndex, toHash, lookupData) : DetermineBaselineForRelease(toIndex, lookupData.ReleaseVersions); // Get commit hash for baseline version if one was found @@ -382,26 +384,56 @@ private static (Version? fromVersion, string? fromHash) DetermineBaselineVersion /// /// Determines the baseline version for a pre-release. + /// Pre-release versions pick the previous tag (release or pre-release) that isn't the same commit-hash. /// /// Index of target version in release history. - /// List of release versions. + /// Commit hash of target version. + /// Lookup data structures. /// Baseline version or null. - private static Version? DetermineBaselineForPreRelease(int toIndex, List releaseVersions) + private static Version? DetermineBaselineForPreRelease(int toIndex, string toHash, LookupData lookupData) { - // Pre-release versions use the immediately previous (older) release as baseline + var releaseVersions = lookupData.ReleaseVersions; + + // Determine starting index for search + int startIndex; if (toIndex >= 0 && toIndex < releaseVersions.Count - 1) { - // Target version exists in history, use next older release (higher index) - return releaseVersions[toIndex + 1]; + // Target exists, start from next older release + startIndex = toIndex + 1; + } + else if (toIndex == -1 && releaseVersions.Count > 0) + { + // Target not in history, start from most recent + startIndex = 0; + } + else + { + // No valid starting point + startIndex = -1; } - // Target version not in history, use most recent release as baseline - if (toIndex == -1 && releaseVersions.Count > 0) + // If no valid starting point, return null + if (startIndex < 0) { - return releaseVersions[0]; + return null; + } + + // Search forward through older releases (incrementing index) for previous version with different commit hash + for (var i = startIndex; i < releaseVersions.Count; i++) + { + var candidateVersion = releaseVersions[i]; + + // Get commit hash for candidate version + if (lookupData.TagToRelease.TryGetValue(candidateVersion.Tag, out var candidateRelease) && + lookupData.TagsByName.TryGetValue(candidateRelease.TagName!, out var candidateTag) && + candidateTag.Commit.Sha != toHash) + { + // Found a version with a different commit hash - use it + return candidateVersion; + } } - // If toIndex is last in list, this is the oldest release, no baseline + // No version with different commit hash found return null; } diff --git a/test/DemaConsulting.BuildMark.Tests/GitHubRepoConnectorTests.cs b/test/DemaConsulting.BuildMark.Tests/GitHubRepoConnectorTests.cs index dfa3a36..163f158 100644 --- a/test/DemaConsulting.BuildMark.Tests/GitHubRepoConnectorTests.cs +++ b/test/DemaConsulting.BuildMark.Tests/GitHubRepoConnectorTests.cs @@ -265,4 +265,191 @@ public async Task GitHubRepoConnector_GetBuildInformationAsync_WithOpenIssues_Id var hasExpectedIssue = knownIssueTitles.Exists(t => t.Contains("Known bug") || t.Contains("Feature request")); Assert.IsTrue(hasExpectedIssue, "Should have at least one of the open issues as a known issue"); } + + /// + /// Test that pre-release baseline selection skips tags with the same commit hash. + /// Example: 1.1.2-rc.1 (hash a1b2c3d4) and 1.1.2-beta.2 (hash a1b2c3d4) are re-tags. + /// When processing 1.1.2-rc.1, it should skip 1.1.2-beta.2 and use 1.1.2-beta.1 (hash 734713bc). + /// + [TestMethod] + public async Task GitHubRepoConnector_GetBuildInformationAsync_PreReleaseWithSameCommitHash_SkipsToNextDifferentHash() + { + // Arrange - Create mock responses with multiple pre-releases on same and different hashes + using var mockHandler = new MockGitHubGraphQLHttpMessageHandler() + .AddCommitsResponse("a1b2c3d4", "734713bc", "commit1") + .AddReleasesResponse( + new MockRelease("1.1.2-rc.1", "2024-03-03T00:00:00Z"), // Same hash as beta.2 + new MockRelease("1.1.2-beta.2", "2024-03-02T00:00:00Z"), // Same hash as rc.1 + new MockRelease("1.1.2-beta.1", "2024-03-01T00:00:00Z"), // Different hash + new MockRelease("v1.1.1", "2024-02-01T00:00:00Z")) + .AddPullRequestsResponse() + .AddIssuesResponse() + .AddTagsResponse( + new MockTag("1.1.2-rc.1", "a1b2c3d4"), // rc.1 and beta.2 on same hash + new MockTag("1.1.2-beta.2", "a1b2c3d4"), // Same hash as rc.1 + new MockTag("1.1.2-beta.1", "734713bc"), // Different hash + new MockTag("v1.1.1", "commit1")); + + using var mockHttpClient = new HttpClient(mockHandler); + var connector = new MockableGitHubRepoConnector(mockHttpClient); + + // Set up mock command responses + connector.SetCommandResponse("git remote get-url origin", "https://github.com/test/repo.git"); + connector.SetCommandResponse("git rev-parse --abbrev-ref HEAD", "main"); + connector.SetCommandResponse("git rev-parse HEAD", "a1b2c3d4"); + connector.SetCommandResponse("gh auth token", "test-token"); + + // Act - Process 1.1.2-rc.1 + var buildInfo = await connector.GetBuildInformationAsync(Version.Create("1.1.2-rc.1")); + + // Assert + Assert.IsNotNull(buildInfo); + Assert.AreEqual("1.1.2-rc.1", buildInfo.CurrentVersionTag.VersionInfo.FullVersion); + Assert.AreEqual("a1b2c3d4", buildInfo.CurrentVersionTag.CommitHash); + + // Should have skipped 1.1.2-beta.2 (same hash) and selected 1.1.2-beta.1 (different hash) + Assert.IsNotNull(buildInfo.BaselineVersionTag); + Assert.AreEqual("1.1.2-beta.1", buildInfo.BaselineVersionTag.VersionInfo.FullVersion); + Assert.AreEqual("734713bc", buildInfo.BaselineVersionTag.CommitHash); + + // Should have changelog link between beta.1 and rc.1 + Assert.IsNotNull(buildInfo.CompleteChangelogLink); + Assert.Contains("1.1.2-beta.1...1.1.2-rc.1", buildInfo.CompleteChangelogLink.TargetUrl); + } + + /// + /// Test that release baseline selection skips all pre-release versions. + /// Example: 1.1.2 should skip 1.1.2-rc.1, 1.1.2-beta.2, 1.1.2-beta.1 and use 1.1.1. + /// + [TestMethod] + public async Task GitHubRepoConnector_GetBuildInformationAsync_ReleaseVersion_SkipsAllPreReleases() + { + // Arrange - Create mock responses with release and multiple pre-releases + using var mockHandler = new MockGitHubGraphQLHttpMessageHandler() + .AddCommitsResponse("commit5", "commit4", "commit3", "commit2", "commit1") + .AddReleasesResponse( + new MockRelease("1.1.2", "2024-03-05T00:00:00Z"), + new MockRelease("1.1.2-rc.1", "2024-03-04T00:00:00Z"), + new MockRelease("1.1.2-beta.2", "2024-03-03T00:00:00Z"), + new MockRelease("1.1.2-beta.1", "2024-03-02T00:00:00Z"), + new MockRelease("v1.1.1", "2024-02-01T00:00:00Z")) + .AddPullRequestsResponse() + .AddIssuesResponse() + .AddTagsResponse( + new MockTag("1.1.2", "commit5"), + new MockTag("1.1.2-rc.1", "commit4"), + new MockTag("1.1.2-beta.2", "commit3"), + new MockTag("1.1.2-beta.1", "commit2"), + new MockTag("v1.1.1", "commit1")); + + using var mockHttpClient = new HttpClient(mockHandler); + var connector = new MockableGitHubRepoConnector(mockHttpClient); + + // Set up mock command responses + connector.SetCommandResponse("git remote get-url origin", "https://github.com/test/repo.git"); + connector.SetCommandResponse("git rev-parse --abbrev-ref HEAD", "main"); + connector.SetCommandResponse("git rev-parse HEAD", "commit5"); + connector.SetCommandResponse("gh auth token", "test-token"); + + // Act - Process 1.1.2 + var buildInfo = await connector.GetBuildInformationAsync(Version.Create("1.1.2")); + + // Assert + Assert.IsNotNull(buildInfo); + Assert.AreEqual("1.1.2", buildInfo.CurrentVersionTag.VersionInfo.FullVersion); + Assert.AreEqual("commit5", buildInfo.CurrentVersionTag.CommitHash); + + // Should have skipped all pre-releases and selected 1.1.1 + Assert.IsNotNull(buildInfo.BaselineVersionTag); + Assert.AreEqual("1.1.1", buildInfo.BaselineVersionTag.VersionInfo.FullVersion); + Assert.AreEqual("commit1", buildInfo.BaselineVersionTag.CommitHash); + + // Should have changelog link between 1.1.1 and 1.1.2 + Assert.IsNotNull(buildInfo.CompleteChangelogLink); + Assert.Contains("v1.1.1...1.1.2", buildInfo.CompleteChangelogLink.TargetUrl); + } + + /// + /// Test that pre-release baseline selection works correctly when target is not in release history. + /// This happens when generating build notes for a version that hasn't been tagged yet. + /// + [TestMethod] + public async Task GitHubRepoConnector_GetBuildInformationAsync_PreReleaseNotInHistory_UsesLatestDifferentHash() + { + // Arrange - Create mock responses where target version doesn't exist yet + using var mockHandler = new MockGitHubGraphQLHttpMessageHandler() + .AddCommitsResponse("newhash123", "commit2", "commit1") + .AddReleasesResponse( + new MockRelease("1.1.2-beta.1", "2024-03-01T00:00:00Z"), + new MockRelease("v1.1.1", "2024-02-01T00:00:00Z")) + .AddPullRequestsResponse() + .AddIssuesResponse() + .AddTagsResponse( + new MockTag("1.1.2-beta.1", "commit2"), + new MockTag("v1.1.1", "commit1")); + + using var mockHttpClient = new HttpClient(mockHandler); + var connector = new MockableGitHubRepoConnector(mockHttpClient); + + // Set up mock command responses + connector.SetCommandResponse("git remote get-url origin", "https://github.com/test/repo.git"); + connector.SetCommandResponse("git rev-parse --abbrev-ref HEAD", "main"); + connector.SetCommandResponse("git rev-parse HEAD", "newhash123"); + connector.SetCommandResponse("gh auth token", "test-token"); + + // Act - Process 1.1.2-beta.2 which doesn't exist in releases yet + var buildInfo = await connector.GetBuildInformationAsync(Version.Create("1.1.2-beta.2")); + + // Assert + Assert.IsNotNull(buildInfo); + Assert.AreEqual("1.1.2-beta.2", buildInfo.CurrentVersionTag.VersionInfo.FullVersion); + Assert.AreEqual("newhash123", buildInfo.CurrentVersionTag.CommitHash); + + // Should use most recent release with different hash + Assert.IsNotNull(buildInfo.BaselineVersionTag); + Assert.AreEqual("1.1.2-beta.1", buildInfo.BaselineVersionTag.VersionInfo.FullVersion); + Assert.AreEqual("commit2", buildInfo.BaselineVersionTag.CommitHash); + } + + /// + /// Test that pre-release baseline selection returns null when all previous versions have the same hash. + /// This is an edge case where all previous tags are re-tags of the current commit. + /// + [TestMethod] + public async Task GitHubRepoConnector_GetBuildInformationAsync_PreReleaseAllPreviousSameHash_ReturnsNullBaseline() + { + // Arrange - Create mock responses where all versions are on the same commit + using var mockHandler = new MockGitHubGraphQLHttpMessageHandler() + .AddCommitsResponse("samehash123") + .AddReleasesResponse( + new MockRelease("1.1.2-rc.1", "2024-03-03T00:00:00Z"), + new MockRelease("1.1.2-beta.2", "2024-03-02T00:00:00Z"), + new MockRelease("1.1.2-beta.1", "2024-03-01T00:00:00Z")) + .AddPullRequestsResponse() + .AddIssuesResponse() + .AddTagsResponse( + new MockTag("1.1.2-rc.1", "samehash123"), + new MockTag("1.1.2-beta.2", "samehash123"), + new MockTag("1.1.2-beta.1", "samehash123")); + + using var mockHttpClient = new HttpClient(mockHandler); + var connector = new MockableGitHubRepoConnector(mockHttpClient); + + // Set up mock command responses + connector.SetCommandResponse("git remote get-url origin", "https://github.com/test/repo.git"); + connector.SetCommandResponse("git rev-parse --abbrev-ref HEAD", "main"); + connector.SetCommandResponse("git rev-parse HEAD", "samehash123"); + connector.SetCommandResponse("gh auth token", "test-token"); + + // Act - Process 1.1.2-rc.1 + var buildInfo = await connector.GetBuildInformationAsync(Version.Create("1.1.2-rc.1")); + + // Assert + Assert.IsNotNull(buildInfo); + Assert.AreEqual("1.1.2-rc.1", buildInfo.CurrentVersionTag.VersionInfo.FullVersion); + Assert.AreEqual("samehash123", buildInfo.CurrentVersionTag.CommitHash); + + // Should have null baseline since all previous versions are on the same hash + Assert.IsNull(buildInfo.BaselineVersionTag); + } } From d8643609e7011af92622667c271f3425a829faf9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Feb 2026 17:24:12 +0000 Subject: [PATCH 3/4] Document from-version selection rules in user guide Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com> --- docs/guide/guide.md | 76 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/docs/guide/guide.md b/docs/guide/guide.md index 5baa777..1c3dc43 100644 --- a/docs/guide/guide.md +++ b/docs/guide/guide.md @@ -399,6 +399,82 @@ buildmark --validate --results validation-results.trx buildmark --validate --results validation-results.xml ``` +# Version Selection Rules + +BuildMark automatically determines which previous version to use as the baseline when generating build notes. This +section explains how BuildMark selects the baseline version for different scenarios. + +## Pre-Release Versions + +For pre-release versions (e.g., `1.2.3-beta.1`, `1.2.3-rc.1`), BuildMark picks the **previous tag (release or +pre-release) that has a different commit hash**. + +This behavior handles cases where multiple pre-release tags point to the same commit (re-tagging scenarios), ensuring +the generated changelog shows actual code changes rather than an empty diff. + +### Example: Pre-Release with Re-Tagged Commits + +Consider the following tags: + +- `1.1.2-rc.1` (commit hash: `a1b2c3d4`) +- `1.1.2-beta.2` (commit hash: `a1b2c3d4`) +- `1.1.2-beta.1` (commit hash: `734713bc`) + +When generating build notes for `1.1.2-rc.1`: + +1. BuildMark identifies that `1.1.2-beta.2` has the same commit hash (`a1b2c3d4`) +2. BuildMark skips `1.1.2-beta.2` since it would result in an empty changelog +3. BuildMark selects `1.1.2-beta.1` as the baseline (different commit hash: `734713bc`) + +The generated build notes will show changes between `1.1.2-beta.1` and `1.1.2-rc.1`. + +## Release Versions + +For release versions (e.g., `1.2.3`), BuildMark picks the **previous release tag**, skipping all pre-release versions. + +This ensures release notes compare against the previous stable release, showing the complete set of changes since the +last production release. + +### Example: Release Skipping Pre-Releases + +Consider the following tags: + +- `1.1.2` (release) +- `1.1.2-rc.1` (pre-release) +- `1.1.2-beta.2` (pre-release) +- `1.1.2-beta.1` (pre-release) +- `1.1.1` (release) + +When generating build notes for `1.1.2`: + +1. BuildMark identifies `1.1.2` as a release version (no pre-release suffix) +2. BuildMark skips all pre-release tags (`1.1.2-rc.1`, `1.1.2-beta.2`, `1.1.2-beta.1`) +3. BuildMark selects `1.1.1` as the baseline (the previous release) + +The generated build notes will show all changes between `1.1.1` and `1.1.2`, including changes from all the +pre-release versions. + +## No Previous Version + +If no previous version is found (e.g., generating build notes for the first release), BuildMark will build the +history from the beginning of the repository, showing all commits up to the specified version. + +## Version Tag Format + +BuildMark recognizes version tags with various formats: + +- Simple format: `1.2.3` +- V-prefix: `v1.2.3` +- Custom prefixes: `ver-1.2.3`, `release_1.2.3` +- Pre-release suffixes: `-alpha.1`, `-beta.2`, `-rc.1`, `.pre.1` +- Build metadata: `+build.123`, `+linux.x64` + +Examples of recognized version tags: + +- `1.0.0`, `v1.0.0`, `ver-1.0.0` +- `2.0.0-beta.1`, `v2.0.0-rc.2` +- `1.2.3+build.456`, `v2.0.0-rc.1+linux` + # Best Practices ## Version Tagging From 6bbfe3c5e97279f6cae3a3f53763900ac606596a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Feb 2026 17:32:17 +0000 Subject: [PATCH 4/4] Fix spell-check violations in test file by renaming hash variables Co-authored-by: Malcolmnixon <1863707+Malcolmnixon@users.noreply.github.com> --- .../GitHubRepoConnectorTests.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test/DemaConsulting.BuildMark.Tests/GitHubRepoConnectorTests.cs b/test/DemaConsulting.BuildMark.Tests/GitHubRepoConnectorTests.cs index 163f158..7daf97a 100644 --- a/test/DemaConsulting.BuildMark.Tests/GitHubRepoConnectorTests.cs +++ b/test/DemaConsulting.BuildMark.Tests/GitHubRepoConnectorTests.cs @@ -378,7 +378,7 @@ public async Task GitHubRepoConnector_GetBuildInformationAsync_PreReleaseNotInHi { // Arrange - Create mock responses where target version doesn't exist yet using var mockHandler = new MockGitHubGraphQLHttpMessageHandler() - .AddCommitsResponse("newhash123", "commit2", "commit1") + .AddCommitsResponse("new-hash-123", "commit2", "commit1") .AddReleasesResponse( new MockRelease("1.1.2-beta.1", "2024-03-01T00:00:00Z"), new MockRelease("v1.1.1", "2024-02-01T00:00:00Z")) @@ -394,7 +394,7 @@ public async Task GitHubRepoConnector_GetBuildInformationAsync_PreReleaseNotInHi // Set up mock command responses connector.SetCommandResponse("git remote get-url origin", "https://github.com/test/repo.git"); connector.SetCommandResponse("git rev-parse --abbrev-ref HEAD", "main"); - connector.SetCommandResponse("git rev-parse HEAD", "newhash123"); + connector.SetCommandResponse("git rev-parse HEAD", "new-hash-123"); connector.SetCommandResponse("gh auth token", "test-token"); // Act - Process 1.1.2-beta.2 which doesn't exist in releases yet @@ -403,7 +403,7 @@ public async Task GitHubRepoConnector_GetBuildInformationAsync_PreReleaseNotInHi // Assert Assert.IsNotNull(buildInfo); Assert.AreEqual("1.1.2-beta.2", buildInfo.CurrentVersionTag.VersionInfo.FullVersion); - Assert.AreEqual("newhash123", buildInfo.CurrentVersionTag.CommitHash); + Assert.AreEqual("new-hash-123", buildInfo.CurrentVersionTag.CommitHash); // Should use most recent release with different hash Assert.IsNotNull(buildInfo.BaselineVersionTag); @@ -420,7 +420,7 @@ public async Task GitHubRepoConnector_GetBuildInformationAsync_PreReleaseAllPrev { // Arrange - Create mock responses where all versions are on the same commit using var mockHandler = new MockGitHubGraphQLHttpMessageHandler() - .AddCommitsResponse("samehash123") + .AddCommitsResponse("same-hash-123") .AddReleasesResponse( new MockRelease("1.1.2-rc.1", "2024-03-03T00:00:00Z"), new MockRelease("1.1.2-beta.2", "2024-03-02T00:00:00Z"), @@ -428,9 +428,9 @@ public async Task GitHubRepoConnector_GetBuildInformationAsync_PreReleaseAllPrev .AddPullRequestsResponse() .AddIssuesResponse() .AddTagsResponse( - new MockTag("1.1.2-rc.1", "samehash123"), - new MockTag("1.1.2-beta.2", "samehash123"), - new MockTag("1.1.2-beta.1", "samehash123")); + new MockTag("1.1.2-rc.1", "same-hash-123"), + new MockTag("1.1.2-beta.2", "same-hash-123"), + new MockTag("1.1.2-beta.1", "same-hash-123")); using var mockHttpClient = new HttpClient(mockHandler); var connector = new MockableGitHubRepoConnector(mockHttpClient); @@ -438,7 +438,7 @@ public async Task GitHubRepoConnector_GetBuildInformationAsync_PreReleaseAllPrev // Set up mock command responses connector.SetCommandResponse("git remote get-url origin", "https://github.com/test/repo.git"); connector.SetCommandResponse("git rev-parse --abbrev-ref HEAD", "main"); - connector.SetCommandResponse("git rev-parse HEAD", "samehash123"); + connector.SetCommandResponse("git rev-parse HEAD", "same-hash-123"); connector.SetCommandResponse("gh auth token", "test-token"); // Act - Process 1.1.2-rc.1 @@ -447,7 +447,7 @@ public async Task GitHubRepoConnector_GetBuildInformationAsync_PreReleaseAllPrev // Assert Assert.IsNotNull(buildInfo); Assert.AreEqual("1.1.2-rc.1", buildInfo.CurrentVersionTag.VersionInfo.FullVersion); - Assert.AreEqual("samehash123", buildInfo.CurrentVersionTag.CommitHash); + Assert.AreEqual("same-hash-123", buildInfo.CurrentVersionTag.CommitHash); // Should have null baseline since all previous versions are on the same hash Assert.IsNull(buildInfo.BaselineVersionTag);