From 90db6b5f03b6f62ef9cc7aada9118a0843e265af Mon Sep 17 00:00:00 2001 From: Mark Ridgwell <273118822+dnyw4l3n13@users.noreply.github.com> Date: Fri, 30 Oct 2026 14:50:12 +0000 Subject: [PATCH 1/2] docs(changelog): placeholder for #434 Add changelog entry for the status notification branch consistency fix (#434). --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a830751..e887cfab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ Please ADD ALL Changes to the UNRELEASED SECTION and not a specific release - Added missing build;buildTransitive IncludeAssets on Serilog package reference required by FunFair.BuildCheck - CloudFormation task settings now live in Mappings so every deploy applies them, reducing ECS task memory from 4 GB to 1 GB - On a new stack, ECS tasks no longer fail to start with a 'log group does not exist' error, and their final logs are kept when the stack is deleted, because the ECS application log group is now created before the tasks and removed after them (#421) +- Status notifications now pick one branch consistently for the embed title and Branch field (prefer release/*, then main, else first) - #434 ### Changed - Dependencies - Updated NSubstitute.Analyzers.CSharp to 1.0.17 - Switched to use minimal APIs From ffaa24cf35c1d25ec282ae1ce740466d921382d8 Mon Sep 17 00:00:00 2001 From: Mark Ridgwell <273118822+dnyw4l3n13@users.noreply.github.com> Date: Fri, 30 Oct 2026 15:13:09 +0000 Subject: [PATCH 2/2] fix(github): use one consistent branch for status title and Branch field Refs #434 --- .../GithubStatusNotificationHandlerTests.cs | 31 ++++++++++++++++++- .../GithubStatusNotificationHandler.cs | 28 ++++++++++++----- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/src/BuildBot.GitHub.Tests/Publishers/GithubStatusNotificationHandlerTests.cs b/src/BuildBot.GitHub.Tests/Publishers/GithubStatusNotificationHandlerTests.cs index a78e00f9..89eda655 100644 --- a/src/BuildBot.GitHub.Tests/Publishers/GithubStatusNotificationHandlerTests.cs +++ b/src/BuildBot.GitHub.Tests/Publishers/GithubStatusNotificationHandlerTests.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Threading; using System.Threading.Tasks; using BuildBot.Discord.Models; @@ -166,4 +166,33 @@ await handler.Handle( Assert.Equal(expected: "Build finished for ci/build from BuildBot ((unknown))", actual: embed.Title); Assert.Equal(expected: new DiscordEmbedField(Name: "Branch", Value: "(unknown)"), actual: embed.Fields[1]); } + + [Theory] + [InlineData("feature/one,main,release/1.2.3", "release/1.2.3")] + [InlineData("main,Release/2.0", "Release/2.0")] + [InlineData("feature/one,main,develop", "main")] + [InlineData("main,feature/one", "main")] + [InlineData("feature/one,feature/two", "feature/one")] + [InlineData("develop", "develop")] + public async Task PublishedEmbedUsesSameSelectedBranchInTitleAndFieldAsync( + string branchNames, + string expectedBranch + ) + { + (IMediator mediator, GithubStatusNotificationHandler handler) = this.CreateHandler(); + + Branch[] branches = Array.ConvertAll( + array: branchNames.Split(','), + converter: static name => new Branch(name: name) + ); + + await handler.Handle( + notification: new(MakeStatusWithBranches(state: "success", branches: branches)), + cancellationToken: this.CancellationToken() + ); + + DiscordEmbed embed = mediator.PublishedEmbed(); + Assert.Equal(expected: $"Build finished for ci/build from BuildBot ({expectedBranch})", actual: embed.Title); + Assert.Equal(expected: new DiscordEmbedField(Name: "Branch", Value: expectedBranch), actual: embed.Fields[1]); + } } diff --git a/src/BuildBot.GitHub/Publishers/GithubStatusNotificationHandler.cs b/src/BuildBot.GitHub/Publishers/GithubStatusNotificationHandler.cs index a3dd2f99..16bbaa75 100644 --- a/src/BuildBot.GitHub/Publishers/GithubStatusNotificationHandler.cs +++ b/src/BuildBot.GitHub/Publishers/GithubStatusNotificationHandler.cs @@ -52,26 +52,40 @@ private static bool IsPendingBuild(in Status message) private static DiscordEmbed BuildStatusMessage(in Status message) { - Branch? lastBranch = message.Branches.Count > 0 ? message.Branches[^1] : null; - string branchName = lastBranch?.Name ?? "(unknown)"; + string branchName = GetBranchName(message.Branches); return new( Title: $"{message.Description} for {message.Context} from {message.Repository.Name} ({branchName})", Url: EmbedUrl.FromString(message.TargetUrl), Description: $"Built at {message.StatusCommit.Sha}", Color: GetEmbedColor(message), - Fields: GetFields(message) + Fields: [AddHeadCommitEmbed(message.StatusCommit), AddBranchEmbed(branchName)] ); } - private static IReadOnlyList GetFields(in Status message) + private static string GetBranchName(IReadOnlyList branches) { - return [AddHeadCommitEmbed(message.StatusCommit), AddBranchEmbed(message)]; + IReadOnlyList names = [.. branches.Select(static b => b.Name)]; + + return names.FirstOrDefault(IsReleaseBranch) + ?? names.FirstOrDefault(IsMainBranch) + ?? names.FirstOrDefault() + ?? "(unknown)"; + } + + private static bool IsReleaseBranch(string name) + { + return name.StartsWith(value: "release/", comparisonType: StringComparison.OrdinalIgnoreCase); + } + + private static bool IsMainBranch(string name) + { + return StringComparer.Ordinal.Equals(x: name, y: "main"); } - private static DiscordEmbedField AddBranchEmbed(in Status message) + private static DiscordEmbedField AddBranchEmbed(string branchName) { - return new(Name: "Branch", Value: message.Branches.Select(static b => b.Name).FirstOrDefault() ?? "(unknown)"); + return new(Name: "Branch", Value: branchName); } private static DiscordEmbedField AddHeadCommitEmbed(in StatusCommit statusCommit)