Modules/businessdev.ALbuild.Apps/Public/Resolve-BcBuildProfile.ps1

function Resolve-BcBuildProfile {
    <#
    .SYNOPSIS
        Returns how a workspace is compiled in the quality gate: manifest stamp, symbols, warnings, analyzers.
 
    .DESCRIPTION
        One answer for every surface, so a local build can compile exactly as the gate does. Read from the
        albuild.json 'build' block:
 
            { "build": { "updateManifest": true, "preprocessorSymbols": [ "CLEAN" ],
                         "treatWarningsAsErrors": true, "requireAnalyzers": true, "majorGracePeriod": false } }
 
        With -Gate a key the block leaves out takes the gate default: updateManifest, treatWarningsAsErrors
        and requireAnalyzers on, majorGracePeriod off - the settings of the ALbuild quality-gate templates.
        Without -Gate a missing key is off, which is what a plain build has always done.
 
        The difference this closes: Banking's gate stamped the manifest for BC 29 and replaced the committed
        symbols (BC25, ONPREM, DEBUG) with BC25..BC29, so '#if not ONPREM' code compiled only there, and
        treated the resulting AL0679 warning as an error. A local build from the committed app.json never saw
        it (quality gate 28801).
 
    .PARAMETER WorkspaceRoot
        The repository root holding albuild.json.
 
    .PARAMETER Gate
        Fill missing keys with the quality-gate defaults instead of off.
 
    .OUTPUTS
        PSCustomObject: UpdateManifest, PreprocessorSymbols[], TreatWarningsAsErrors, RequireAnalyzers,
        MajorGracePeriod, Source.
    #>

    [CmdletBinding()]
    [OutputType([PSCustomObject])]
    param(
        [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $WorkspaceRoot,
        [switch] $Gate
    )

    $block = $null
    try {
        $config = Get-ALbuildProjectConfig -AppFolder $WorkspaceRoot -WorkspaceRoot $WorkspaceRoot
        if ($config.Has('Build')) { $block = $config.Build }
    }
    catch { Write-ALbuildLog -Level Verbose "No albuild.json at '$WorkspaceRoot': $($_.Exception.Message)" }

    $read = {
        param([string] $name, $default)
        if ($block -and ($block.PSObject.Properties.Name -contains $name) -and $null -ne $block.$name) { return $block.$name }
        return $default
    }
    $gateDefault = [bool]$Gate
    $symbols = @(foreach ($s in @(& $read 'preprocessorSymbols' @())) { if ("$s".Trim()) { "$s".Trim() } })

    [PSCustomObject]@{
        UpdateManifest        = [bool](& $read 'updateManifest' $gateDefault)
        PreprocessorSymbols   = $symbols
        TreatWarningsAsErrors = [bool](& $read 'treatWarningsAsErrors' $gateDefault)
        RequireAnalyzers      = [bool](& $read 'requireAnalyzers' $gateDefault)
        MajorGracePeriod      = [bool](& $read 'majorGracePeriod' $false)
        Source                = if ($block) { 'albuild.json build' } elseif ($Gate) { 'quality-gate defaults' } else { 'defaults' }
    }
}