diff --git a/CHANGELOG.md b/CHANGELOG.md index 85482a806..204ca3a7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ Please ADD ALL Changes to the UNRELEASED SECTION and not a specific release - Added null guards for botMessageChannel and botReleaseMessageChannel parameters in BotService constructor - Pass ILogger to HealthCheckClient.ExecuteAsync to match new API in Credfeto.Docker.HealthCheck.Http.Client 0.0.72.928 - Made DiscordChannelAdapter testable by accepting ITextChannel instead of the sealed SocketTextChannel, and added unit tests +- Guard against IndexOutOfRangeException when Branches list is empty in GithubStatusNotificationHandler ### Changed - Dependencies - Updated NSubstitute.Analyzers.CSharp to 1.0.17 - Switched to use minimal APIs diff --git a/src/BuildBot.GitHub.Tests/Publishers/GithubStatusNotificationHandlerTests.cs b/src/BuildBot.GitHub.Tests/Publishers/GithubStatusNotificationHandlerTests.cs index 4e6d3ea4a..c77067951 100644 --- a/src/BuildBot.GitHub.Tests/Publishers/GithubStatusNotificationHandlerTests.cs +++ b/src/BuildBot.GitHub.Tests/Publishers/GithubStatusNotificationHandlerTests.cs @@ -19,6 +19,16 @@ public sealed class GithubStatusNotificationHandlerTests : TestBase .UtcDateTime; private static Status MakeStatus(string state) + { + return MakeStatusWithBranches(state: state, branches: [new Branch(name: "main")]); + } + + private static Status MakeStatusWithNoBranches(string state) + { + return MakeStatusWithBranches(state: state, branches: []); + } + + private static Status MakeStatusWithBranches(string state, Branch[] branches) { Repository repository = new( id: 1, @@ -49,7 +59,7 @@ private static Status MakeStatus(string state) repository: repository, context: "ci/build", state: state, - branches: [new Branch(name: "main")], + branches: branches, description: "Build finished", statusCommit: statusCommit ); @@ -92,4 +102,20 @@ public async Task NonPendingStateShouldPublishAsync(string state) await mediator.Received(1).Publish(Arg.Any(), Arg.Any()); } + + [Theory] + [InlineData("success")] + [InlineData("failure")] + [InlineData("error")] + public async Task NonPendingStateWithNoBranchesShouldPublishAsync(string state) + { + (IMediator mediator, GithubStatusNotificationHandler handler) = this.CreateHandler(); + + Status status = MakeStatusWithNoBranches(state: state); + GithubStatus notification = new(status); + + await handler.Handle(notification: notification, cancellationToken: this.CancellationToken()); + + await mediator.Received(1).Publish(Arg.Any(), Arg.Any()); + } } diff --git a/src/BuildBot.GitHub/Publishers/GithubStatusNotificationHandler.cs b/src/BuildBot.GitHub/Publishers/GithubStatusNotificationHandler.cs index b93b962cf..ccf038b8f 100644 --- a/src/BuildBot.GitHub/Publishers/GithubStatusNotificationHandler.cs +++ b/src/BuildBot.GitHub/Publishers/GithubStatusNotificationHandler.cs @@ -53,11 +53,11 @@ private static bool IsPendingBuild(in Status message) private static EmbedBuilder BuildStatusMessage(in Status message) { - Branch lastBranch = message.Branches[^1]; + Branch? lastBranch = message.Branches.Count > 0 ? message.Branches[^1] : null; return new EmbedBuilder() .WithTitle( - $"{message.Description} for {message.Context} from {message.Repository.Name} ({lastBranch.Name})" + $"{message.Description} for {message.Context} from {message.Repository.Name} ({lastBranch?.Name ?? "(unknown)"})" ) .WithUrl(message.TargetUrl) .WithDescription($"Built at {message.StatusCommit.Sha}") @@ -74,7 +74,7 @@ private static EmbedFieldBuilder AddBranchEmbed(in Status message) { return new EmbedFieldBuilder() .WithName("Branch") - .WithValue(message.Branches.Select(static b => b.Name).FirstOrDefault()); + .WithValue(message.Branches.Select(static b => b.Name).FirstOrDefault() ?? "(unknown)"); } private static EmbedFieldBuilder AddHeadCommitEmbed(in StatusCommit statusCommit)