Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions BuildMonitor.Test/HistoryRunsTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright (c) 2023-2026 ktsu-dev contributors

namespace ktsu.BuildMonitor.Test;

using Microsoft.VisualStudio.TestTools.UnitTesting;

/// <summary>
/// Tests for <see cref="BuildMonitor.SelectHistoryRuns"/>.
/// </summary>
/// <remarks>
/// The History column draws its indicators left to right, and a column narrower than all of them
/// clips on the right. The newest runs therefore have to come first, so clipping drops the oldest.
/// </remarks>
[TestClass]
public sealed class HistoryRunsTests
{
private static readonly DateTimeOffset Start = new(2026, 1, 1, 0, 0, 0, TimeSpan.Zero);

/// <summary>
/// Builds runs with the given statuses, most recent first, an hour apart.
/// </summary>
private static List<Run> RunsNewestFirst(params RunStatus[] statuses) =>
[.. statuses.Select((status, i) => new Run { Status = status, Started = Start.AddHours(-i) })];

[TestMethod]
public void TheNewestRunIsDrawnFirst()
{
// Arrange
List<Run> branchRuns = RunsNewestFirst(RunStatus.Running, RunStatus.Success, RunStatus.Success, RunStatus.Success, RunStatus.Success);

// Act
List<Run> history = BuildMonitor.SelectHistoryRuns(branchRuns);

// Assert
CollectionAssert.AreEqual(branchRuns, history);

Check warning on line 35 in BuildMonitor.Test/HistoryRunsTests.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use 'Assert.AreSequenceEqual' instead of 'CollectionAssert.AreEqual'

See more on https://sonarcloud.io/project/issues?id=ktsu-dev_BuildMonitor&issues=AaEysSFXh5G4AE1-oJaE&open=AaEysSFXh5G4AE1-oJaE&pullRequest=367
}

[TestMethod]
public void OnlyTheFiveNewestRunsAreShown()
{
// Arrange
List<Run> branchRuns = RunsNewestFirst(RunStatus.Running, RunStatus.Failure, RunStatus.Success, RunStatus.Success, RunStatus.Success, RunStatus.Failure);

// Act
List<Run> history = BuildMonitor.SelectHistoryRuns(branchRuns);

// Assert
CollectionAssert.AreEqual(branchRuns.Take(5).ToList(), history);

Check warning on line 48 in BuildMonitor.Test/HistoryRunsTests.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use 'Assert.AreSequenceEqual' instead of 'CollectionAssert.AreEqual'

See more on https://sonarcloud.io/project/issues?id=ktsu-dev_BuildMonitor&issues=AaEysSFXh5G4AE1-oJaF&open=AaEysSFXh5G4AE1-oJaF&pullRequest=367
}

[TestMethod]
public void CanceledRunsAreSkipped()
{
// Arrange
List<Run> branchRuns = RunsNewestFirst(RunStatus.Canceled, RunStatus.Success, RunStatus.Failure);

// Act
List<Run> history = BuildMonitor.SelectHistoryRuns(branchRuns);

// Assert
CollectionAssert.AreEqual(branchRuns.Skip(1).ToList(), history);

Check warning on line 61 in BuildMonitor.Test/HistoryRunsTests.cs

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use 'Assert.AreSequenceEqual' instead of 'CollectionAssert.AreEqual'

See more on https://sonarcloud.io/project/issues?id=ktsu-dev_BuildMonitor&issues=AaEysSFXh5G4AE1-oJaG&open=AaEysSFXh5G4AE1-oJaG&pullRequest=367
}
}
20 changes: 15 additions & 5 deletions BuildMonitor/BuildMonitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@
/// fields actually occupy tests the bug itself, so a fixed binding is recognised as fixed and
/// anything else is refused rather than guessed at.
/// </remarks>
private static unsafe int? ProbeNativeImGuiTableColumnSize()

Check warning on line 236 in BuildMonitor/BuildMonitor.cs

View workflow job for this annotation

GitHub Actions / ci / .NET / Analyze & Release

Avoid using this unsafe code block.

Check warning on line 236 in BuildMonitor/BuildMonitor.cs

View workflow job for this annotation

GitHub Actions / ci / .NET / Analyze & Release

Avoid using this unsafe code block.
{
int csharpSize = sizeof(ImGuiTableColumn);
int widthGivenOffset;
Expand Down Expand Up @@ -332,7 +332,7 @@
return narrowFieldBytes == NarrowlyBoundColumnFields.Length * 2 ? csharpSize : null;
}

private static unsafe void SaveColumnWidth(string columnName, int columnIndex)

Check warning on line 335 in BuildMonitor/BuildMonitor.cs

View workflow job for this annotation

GitHub Actions / ci / .NET / Analyze & Release

Avoid using this unsafe code block.

Check warning on line 335 in BuildMonitor/BuildMonitor.cs

View workflow job for this annotation

GitHub Actions / ci / .NET / Analyze & Release

Avoid using this unsafe code block.
{
// Null means the layout probe rejected the binding, so there is no address we can trust.
if (NativeImGuiTableColumnSize is not int nativeStructSize)
Expand Down Expand Up @@ -459,7 +459,7 @@
SaveSettingsIfRequired();
}

private static void UpdateOwnerTabs()

Check warning on line 462 in BuildMonitor/BuildMonitor.cs

View workflow job for this annotation

GitHub Actions / ci / .NET / Analyze & Release

Refactor this method to reduce its Cognitive Complexity from 17 to the 15 allowed.

Check warning on line 462 in BuildMonitor/BuildMonitor.cs

View workflow job for this annotation

GitHub Actions / ci / .NET / Analyze & Release

Refactor this method to reduce its Cognitive Complexity from 17 to the 15 allowed.
{
// Build expected tabs based on provider type:
// - GitHub: one tab per owner (org/user)
Expand All @@ -468,7 +468,7 @@
HashSet<string> expectedTabIds = [AllOwnersTabId, LogsTabId];
Dictionary<string, (string Label, Action Content)> tabsToCreate = [];

foreach ((BuildProviderName providerName, BuildProvider provider) in AppData.BuildProviders)

Check warning on line 471 in BuildMonitor/BuildMonitor.cs

View workflow job for this annotation

GitHub Actions / ci / .NET / Analyze & Release

Remove the unused local variable 'providerName'.

Check warning on line 471 in BuildMonitor/BuildMonitor.cs

View workflow job for this annotation

GitHub Actions / ci / .NET / Analyze & Release

Remove the unused local variable 'providerName'.
{
if (provider is GitHub)
{
Expand Down Expand Up @@ -675,7 +675,7 @@
return displayName;
}

private static string MakeRepositoryDisplayName(Build build)

Check warning on line 678 in BuildMonitor/BuildMonitor.cs

View workflow job for this annotation

GitHub Actions / ci / .NET / Analyze & Release

All 'MakeRepositoryDisplayName' method overloads should be adjacent.

Check warning on line 678 in BuildMonitor/BuildMonitor.cs

View workflow job for this annotation

GitHub Actions / ci / .NET / Analyze & Release

All 'MakeRepositoryDisplayName' method overloads should be adjacent.
{
string repoName = build.Repository.Name;
string ownerName = build.Owner.Name;
Expand Down Expand Up @@ -749,17 +749,27 @@
return shouldShow;
}

private static void ShowBranchHistory(List<Run> branchRuns)
/// <summary>
/// Picks the runs the History column shows from a branch's runs, most recent first.
/// </summary>
/// <remarks>
/// The indicators are drawn left to right, and a column too narrow for all of them clips on the
/// right, so the newest come first: clipping then drops the oldest runs rather than the newest.
/// </remarks>
/// <param name="branchRuns">The branch's runs, most recent first.</param>
/// <returns>Up to five runs that were not canceled, in the order they are drawn.</returns>
internal static List<Run> SelectHistoryRuns(IEnumerable<Run> branchRuns)
{
const int recentRuns = 5;

List<Run> runs = [.. branchRuns
return [.. branchRuns
.Where(r => r.Status != RunStatus.Canceled)
.Take(recentRuns)];
}

runs.Reverse();

foreach (Run? run in runs)
private static void ShowBranchHistory(List<Run> branchRuns)
{
foreach (Run? run in SelectHistoryRuns(branchRuns))
{
ImGui.SameLine();
ImGuiWidgets.ColorIndicator(GetStatusColor(run.Status), true);
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ The main interface displays a table of all your builds grouped by workflow and b
- **Status**: Current status (Pending, Running, Success, Failure, Canceled)
- **Last Run**: Timestamp of when the build started
- **Duration**: How long the build has been running or took to complete
- **History**: Visual history of the last 5 builds on this branch
- **History**: Visual history of the last 5 builds on this branch, newest first
- **Progress**: Progress bar for ongoing builds
- **ETA**: Estimated time to completion for ongoing builds
- **Errors**: Error messages from failed builds (click to view full details)
Expand Down
Loading