From 7645a34619dd11f890e808d7476caca64e215f7d Mon Sep 17 00:00:00 2001 From: Zaine Date: Fri, 8 May 2026 16:04:36 +0100 Subject: [PATCH] testing the pipeline 2 --- gitea-build-monitor.ps1 | 191 +++++++++++++++++++++++++++++++++++++--- posts/posts-list.org | 2 +- recently-updated.org | 2 +- sitemap.org | 31 ++++--- 4 files changed, 194 insertions(+), 32 deletions(-) diff --git a/gitea-build-monitor.ps1 b/gitea-build-monitor.ps1 index 13d530a..38101a6 100755 --- a/gitea-build-monitor.ps1 +++ b/gitea-build-monitor.ps1 @@ -57,7 +57,7 @@ $Config = @{ MaxDiscordEmbeds = 10 RetryCount = 3 RetryDelaySeconds = 2 - AuthoringTestsEnabled = $false + AuthoringTestsEnabled = $true AuthoringTestsPattern = 'test_authoring_server.py' AuthoringTestsDirectory = Join-Path $PSScriptRoot 'tests' AuthoringTestTimeoutSec = 120 @@ -75,6 +75,7 @@ $Config = @{ # When true, completed successful runs are reported too. NotifySuccessfulBuilds = $true + MaxPreviousFailures = 5 # When true, successful but slow/warned jobs are reported too. # Keep this false if Discord should only receive notifications for failed/cancelled/timed-out jobs. @@ -547,15 +548,35 @@ function Get-Severity { return 'Info' } +function Get-BuildStatus { + param([Parameter(Mandatory)][object]$Build) + + $conclusion = Get-ObjectValue -Object $Build -Name 'conclusion' + if ([string]::IsNullOrWhiteSpace([string]$conclusion)) { + $conclusion = Get-ObjectValue -Object $Build -Name 'result' + } + if ([string]::IsNullOrWhiteSpace([string]$conclusion)) { + $conclusion = Get-ObjectValue -Object $Build -Name 'outcome' + } + if (-not [string]::IsNullOrWhiteSpace([string]$conclusion)) { + return [string]$conclusion + } + + $status = Get-ObjectValue -Object $Build -Name 'status' + if (-not [string]::IsNullOrWhiteSpace([string]$status)) { + return [string]$status + } + + return 'unknown' +} + function Analyze-Build { param( [Parameter(Mandatory)][hashtable]$Repository, [Parameter(Mandatory)][object]$Job ) - $conclusion = Get-ObjectValue -Object $Job -Name 'conclusion' - $jobStatus = Get-ObjectValue -Object $Job -Name 'status' - $status = if ($conclusion) { [string]$conclusion } elseif ($jobStatus) { [string]$jobStatus } else { 'unknown' } + $status = Get-BuildStatus -Build $Job $isSuccessfulStatus = Test-IsSuccessfulStatus -Status $status $duration = Get-Duration -Job $Job $isSlow = $duration.TotalMinutes -ge [double]$Config.SlowBuildThresholdMins @@ -728,6 +749,128 @@ function Send-DiscordNotification { } } +function Get-BuildStatusEmoji { + param([Parameter(Mandatory)][string]$Status) + + if (Test-IsSuccessfulStatus -Status $Status) { + return '✅' + } + + $normalized = $Status.ToLowerInvariant() + if ($normalized -in @('failure', 'failed', 'cancelled', 'canceled', 'timed_out')) { + return '❌' + } + + return 'ℹ️' +} + +function Send-BuildStatusNotification { + param([Parameter(Mandatory)][object[]]$Analyses) + + $latestByRepository = @($Analyses | + Group-Object Repository | + ForEach-Object { + $_.Group | Sort-Object StartedAt -Descending | Select-Object -First 1 + } | + Sort-Object Repository) + + if ($latestByRepository.Count -eq 0) { + Write-Log -Message "No completed builds found in the last $($Config.LookbackMinutes) minute(s)." + return + } + + $embeds = New-Object System.Collections.Generic.List[object] + $failedLatestCount = 0 + $successfulLatestCount = 0 + $previousFailureCount = 0 + + foreach ($latest in $latestByRepository) { + $latestStatus = [string]$latest.Status + $emoji = Get-BuildStatusEmoji -Status $latestStatus + $isLatestSuccessful = Test-IsSuccessfulStatus -Status $latestStatus + if ($isLatestSuccessful) { + $successfulLatestCount++ + } + elseif ($latest.Severity -eq 'Critical') { + $failedLatestCount++ + } + + $previousFailures = @($Analyses | + Where-Object { + $_.Repository -eq $latest.Repository -and + $_.RunId -ne $latest.RunId -and + $_.Severity -eq 'Critical' + } | + Sort-Object StartedAt -Descending | + Select-Object -First ([int]$Config.MaxPreviousFailures)) + + $previousFailureCount += $previousFailures.Count + $previousFailureText = if ($previousFailures.Count -gt 0) { + ($previousFailures | ForEach-Object { + $shortSha = if ($_.CommitSha -and $_.CommitSha.Length -ge 8) { $_.CommitSha.Substring(0, 8) } else { $_.CommitSha } + $commitPart = if ($shortSha) { " ``$shortSha``" } else { '' } + "#{0} {1}{2}" -f $_.RunId, $_.Status, $commitPart + }) -join "`n" + } + else { + 'None in this lookback window.' + } + + if ($previousFailureText.Length -gt 950) { + $previousFailureText = $previousFailureText.Substring(0, 947) + '...' + } + + $shortLatestSha = if ($latest.CommitSha -and $latest.CommitSha.Length -ge 8) { $latest.CommitSha.Substring(0, 8) } else { $latest.CommitSha } + $latestCommit = if ($shortLatestSha) { + if ($latest.CommitMessage) { "``$shortLatestSha`` $($latest.CommitMessage)" } else { "``$shortLatestSha``" } + } + else { + 'unknown' + } + + $color = if ($isLatestSuccessful) { 3066993 } elseif ($latest.Severity -eq 'Critical') { 15158332 } else { 3447003 } + $embeds.Add(@{ + title = "$emoji Latest build: $($latest.Repository) #$($latest.RunId)" + url = $latest.BuildUrl + color = $color + description = if ($isLatestSuccessful) { 'Latest completed build is successful.' } elseif ($latest.Severity -eq 'Critical') { 'Latest completed build failed.' } else { 'Latest completed build has a non-success status.' } + fields = @( + @{ name = 'Latest status'; value = "$emoji $latestStatus"; inline = $true }, + @{ name = 'Branch'; value = $latest.Branch; inline = $true }, + @{ name = 'Duration'; value = $latest.DurationText; inline = $true }, + @{ name = 'Commit'; value = $latestCommit; inline = $false }, + @{ name = 'Previous failed builds'; value = $previousFailureText; inline = $false } + ) + footer = @{ + text = "Run ID $($latest.RunId)" + } + timestamp = (Get-Date).ToUniversalTime().ToString('o') + }) + } + + $payload = @{ + username = 'Gitea Build Monitor' + content = if ($failedLatestCount -gt 0) { + "❌ Latest Gitea build status: $failedLatestCount failed, $successfulLatestCount successful. Previous failures in window: $previousFailureCount." + } + elseif ($successfulLatestCount -gt 0) { + "✅ Latest Gitea build status: $successfulLatestCount successful. Previous failures in window: $previousFailureCount." + } + else { + "ℹ️ Latest Gitea build status reported. Previous failures in window: $previousFailureCount." + } + embeds = @($embeds) + } + + Invoke-DiscordWebhook -Payload $payload + if ($DryRun) { + Write-Log -Message "Prepared build status notification with $($embeds.Count) embed(s) in dry-run mode." + } + else { + Write-Log -Message "Sent build status notification with $($embeds.Count) embed(s)." + } +} + function Get-PythonCommand { $linuxVenvPython = Join-Path $PSScriptRoot '.venv/bin/python' $windowsVenvPython = Join-Path $PSScriptRoot '.venv/Scripts/python.exe' @@ -921,6 +1064,25 @@ function Get-CacheKey { return "$(Get-RepositorySlug -Repository $Repository):$kind`:$jobId`:state:$state" } +function Get-BuildSummaryCacheKey { + param([Parameter(Mandatory)][object[]]$Analyses) + + $parts = @($Analyses | + Group-Object Repository | + ForEach-Object { + $latest = $_.Group | Sort-Object StartedAt -Descending | Select-Object -First 1 + $previousFailureIds = @($_.Group | + Where-Object { $_.RunId -ne $latest.RunId -and $_.Severity -eq 'Critical' } | + Sort-Object StartedAt -Descending | + Select-Object -First ([int]$Config.MaxPreviousFailures) | + ForEach-Object { $_.RunId }) + '{0}:latest:{1}:{2}:prevfail:{3}' -f $latest.Repository, $latest.RunId, $latest.Status, ($previousFailureIds -join ',') + } | + Sort-Object) + + return 'build-summary:' + ($parts -join '|') +} + function Start-BuildMonitor { Assert-Config @@ -961,17 +1123,9 @@ function Start-BuildMonitor { continue } - $cacheKey = Get-CacheKey -Repository $repository -Job $job - if ($cache.ContainsKey($cacheKey)) { - continue - } - try { $analysis = Analyze-Build -Repository $repository -Job $job $analyses.Add($analysis) - if (-not $DryRun) { - $cache[$cacheKey] = Get-Date - } Write-Log -Message ("Analyzed job {0} for {1}: severity={2}, status={3}, duration={4}" -f (Get-ObjectValue -Object $job -Name 'id'), $analysis.Repository, $analysis.Severity, $analysis.Status, $analysis.DurationText) } catch { @@ -981,10 +1135,19 @@ function Start-BuildMonitor { } if ($analyses.Count -gt 0) { - Send-DiscordNotification -Analyses $analyses.ToArray() + $summaryCacheKey = Get-BuildSummaryCacheKey -Analyses $analyses.ToArray() + if ($cache.ContainsKey($summaryCacheKey)) { + Write-Log -Message 'Build status summary has already been sent.' + } + else { + Send-BuildStatusNotification -Analyses $analyses.ToArray() + if (-not $DryRun) { + $cache[$summaryCacheKey] = Get-Date + } + } } else { - Write-Log -Message "No new jobs found in the last $($Config.LookbackMinutes) minute(s)." + Write-Log -Message "No completed builds found in the last $($Config.LookbackMinutes) minute(s)." } if (-not $DryRun) { diff --git a/posts/posts-list.org b/posts/posts-list.org index c02ae25..e10fe37 100755 --- a/posts/posts-list.org +++ b/posts/posts-list.org @@ -4,7 +4,7 @@ See the categories: @@html:Categories@@ * Posts: -- [[file:career/career-list.org][Career List]] @@html:08-05-2026 15:52@@ +- [[file:career/career-list.org][Career List]] @@html:08-05-2026 16:04@@ - [[file:posts-list.sync-conflict-20260417-233432-VT6366A.org][Posts List]] @@html:14-04-2026 16:36@@ - [[file:career/ha-dr.org][High Availability, Disaster Recovery and Business Continuity]] @@html:11-03-2026 17:18@@ @@html:@@ @@html:@@ - [[file:career/javascript.org][Understands the Javascript language]] @@html:11-03-2026 16:52@@ @@html:@@ @@html:@@ diff --git a/recently-updated.org b/recently-updated.org index 6fb684c..48f6d79 100755 --- a/recently-updated.org +++ b/recently-updated.org @@ -16,7 +16,6 @@ - [[file:blogs/2026/04-april/ending-the-week-17-04-26.org][End of week thoughts]] @@html:2026-04-17 16:17@@ - [[file:blogs/2026/04-april/16-04-26.org][Rambles]] @@html:2026-04-16 16:02@@ - [[file:posts/posts-list.sync-conflict-20260417-233432-VT6366A.org][Posts List]] @@html:2026-04-14 16:36@@ -- [[file:home/categories.sync-conflict-20260417-233429-VT6366A.org][Categories]] @@html:2026-04-14 16:36@@ - [[file:blogs/2026/04-april/comparison-14-04.org][Comparison is the thief of joy]] @@html:2026-04-14 09:55@@ - [[file:blogs/2026/04-april/12-04-week-review.org][[12-04-2026] - Weekly Review]] @@html:2026-04-12 12:00@@ - [[file:blogs/2026/04-april/starting-new-rotation-08-04-26.org][Starting new rotation]] @@html:2026-04-08 16:15@@ @@ -28,3 +27,4 @@ - [[file:blogs/2026/03-march/intellectually-challenging-myself-30-03-26.org][Intellectually challenging oneself]] @@html:2026-03-31 11:14@@ - [[file:blogs/2026/03-march/cooking-dinner-29-03-26.org][Cooking Dinner (num)]] @@html:2026-03-30 11:49@@ - [[file:blogs/2026/03-march/29-03-week-review.org][[29-03-2026] - Weekly Review]] @@html:2026-03-29 12:00@@ +- [[file:blogs/2026/03-march/training-on-friday-afternoon-27-03-26.org][Training time on Friday afternoon]] @@html:2026-03-27 15:09@@ diff --git a/sitemap.org b/sitemap.org index 69e2620..130ecb8 100755 --- a/sitemap.org +++ b/sitemap.org @@ -13,24 +13,11 @@ - [[file:tags/website.org][Tag: website]] - [[file:tags/life.org][Tag: life]] - [[file:tags/update.org][Tag: update]] - - [[file:tags/insights.org][Tag: insights]] - - [[file:tags/emacs.org][Tag: emacs]] - [[file:tags/education.org][Tag: education]] + - [[file:tags/insights.org][Tag: insights]] - [[file:tags/reading.org][Tag: reading]] + - [[file:tags/emacs.org][Tag: emacs]] - [[file:tags/maths.org][Tag: maths]] -- home - - [[file:home/countdown.org][Countdown]] - - [[file:home/contact.org][Contact]] - - [[file:home/backlog.org][Backlog]] - - [[file:home/notes.org][Notes]] - - [[file:home/services.org][Service]] - - [[file:home/status.org][Competency Status Board]] - - [[file:home/categories.sync-conflict-20260417-233429-VT6366A.org][Categories]] - - [[file:home/wird-tracker.org][Wird Tracker]] - - [[file:home/categories.org][Categories]] - - guide - - [[file:home/guide/setup.org][Setup]] - - [[file:home/guide/wird-tracker-guide.org][Wird Tracker — Technical Guide]] - posts - [[file:posts/posts-intro.org][Posts Introduction]] - [[file:posts/posts-list.sync-conflict-20260417-233432-VT6366A.org][Posts List]] @@ -64,4 +51,16 @@ - clean-code - [[file:books/clean-code/clean-code-notes.org][Clean Code Notes]] - lima - - [[file:lima/lima-list.org][Lima]] \ No newline at end of file + - [[file:lima/lima-list.org][Lima]] +- home + - [[file:home/countdown.org][Countdown]] + - [[file:home/contact.org][Contact]] + - [[file:home/backlog.org][Backlog]] + - [[file:home/notes.org][Notes]] + - [[file:home/services.org][Service]] + - [[file:home/status.org][Competency Status Board]] + - [[file:home/wird-tracker.org][Wird Tracker]] + - [[file:home/categories.org][Categories]] + - guide + - [[file:home/guide/setup.org][Setup]] + - [[file:home/guide/wird-tracker-guide.org][Wird Tracker — Technical Guide]] \ No newline at end of file