Modules/businessdev.ALbuild.RuntimePackages/Private/Get-BcRuntimeLogSection.ps1

function Get-BcRuntimeLogSection {
    <#
    .SYNOPSIS
        Turns the factory's results into collapsible Azure DevOps log sections - one per app, one per BC
        major - with platform versions sorted as versions.
 
    .DESCRIPTION
        The run log used to be the worker's raw output, replayed in full inside one group per platform
        version: 44 000 lines per slice, in completion order, with every compiler warning of every
        successful build in it. Everything was there and nothing could be found.
 
        What a reader asks is "how did THIS app do?", so the app is the section. Azure DevOps cannot nest
        '##[group]', so a section per app AND per platform version is not available - and of the two the
        app is the useful one: a run spans hundreds of platform versions and twelve apps.
 
        Inside a section the platform versions are grouped by BC major and listed newest first, sorted as
        VERSIONS: sorted as text, 25.10 comes before 25.2, which is the one ordering no reader expects.
        Failures carry their compiler diagnostics, so the section answers the question on its own.
 
        Returns lines instead of writing them, so the shape can be asserted in a test rather than eyeballed
        in a build.
 
    .PARAMETER Result
        The per-platform-version results, as Invoke-BcRuntimeFactory collects them.
 
    .PARAMETER MaxDiagnostic
        How many diagnostics to show per failed app before pointing at the artifact.
 
    .OUTPUTS
        System.String[] - the log lines, including the '##[group]' / '##[endgroup]' markers.
    #>

    [CmdletBinding()]
    [OutputType([string[]])]
    param(
        [Parameter(Mandatory)] [AllowEmptyCollection()] [object[]] $Result,
        [ValidateRange(1, 50)] [int] $MaxDiagnostic = 5
    )

    $out = [System.Collections.Generic.List[string]]::new()
    $rows = [System.Collections.Generic.List[object]]::new()

    foreach ($v in @($Result)) {
        $pv = "$($v.PlatformVersion)"
        $sortable = try { [version](ConvertTo-BcVersion $pv) } catch { [version]'0.0.0.0' }
        foreach ($p in @(Get-BcRuntimeProperty -InputObject $v -Name 'Products' -Default @())) {
            $rows.Add([PSCustomObject]@{
                    App      = "$($p.Name)"
                    Version  = $pv
                    Sort     = $sortable
                    Major    = $sortable.Major
                    Country  = "$(Get-BcRuntimeProperty -InputObject $v -Name 'Country' -Default '')"
                    Status   = "$($p.Status)"
                    Seconds  = [double](Get-BcRuntimeProperty -InputObject $p -Name 'Seconds' -Default 0)
                    Error    = "$(Get-BcRuntimeProperty -InputObject $p -Name 'Error' -Default '')"
                    Diagnostics = @(Get-BcRuntimeProperty -InputObject $p -Name 'Diagnostics' -Default @())
                })
        }
    }

    if ($rows.Count -eq 0) {
        $out.Add('Nothing was built in this slice - every planned runtime package already existed.')
        return $out.ToArray()
    }

    $mark = { param($s) switch ($s) { 'Succeeded' { '+' } 'Skipped' { '-' } default { 'x' } } }
    $label = { param($r) "BC $($r.Version)$(if ($r.Country) { " ($($r.Country))" })" }

    # ---------------------------------------------------------------- one section per app
    $out.Add('')
    $out.Add('##[section]Results per app')
    foreach ($app in (@($rows | Select-Object -ExpandProperty App -Unique) | Sort-Object)) {
        $mine = @($rows | Where-Object { $_.App -eq $app })
        $ok = @($mine | Where-Object { $_.Status -eq 'Succeeded' }).Count
        $bad = @($mine | Where-Object { $_.Status -eq 'Failed' }).Count
        $skip = @($mine | Where-Object { $_.Status -eq 'Skipped' }).Count
        $state = if ($bad -eq 0) { 'all built' } elseif ($ok -eq 0) { 'nothing built' } else { "$ok of $($mine.Count) built" }
        $out.Add("##[group]$app - $state ($bad failed$(if ($skip) { ", $skip skipped" }))")

        # By major inside the section, because 'did anything work on BC24' is how a reader narrows a
        # list of 197 platform versions down - and majors newest first, like everything else here.
        foreach ($major in (@($mine | Select-Object -ExpandProperty Major -Unique) | Sort-Object -Descending)) {
            $ofMajor = @($mine | Where-Object { $_.Major -eq $major } | Sort-Object Sort -Descending)
            $mOk = @($ofMajor | Where-Object { $_.Status -eq 'Succeeded' }).Count
            $out.Add(" BC $major - $mOk of $($ofMajor.Count) built")
            foreach ($r in $ofMajor) {
                $line = " $(& $mark $r.Status) $((& $label $r).PadRight(30)) $([Math]::Round($r.Seconds, 1))s"
                if ($r.Error) { $line += " $($r.Error)" }
                $out.Add($line)
                foreach ($d in @($r.Diagnostics)) { $out.Add(" $d") }
            }
        }
        $out.Add('##[endgroup]')
    }

    return $out.ToArray()
}