Modules/businessdev.ALbuild.Apps/Public/Resolve-BcAnalyzerConfig.ps1
|
function Resolve-BcAnalyzerConfig { <# .SYNOPSIS Determines the code analyzers and ruleset for a compile, layering the sources by precedence. .DESCRIPTION Precedence (highest first): an explicit value (the task input) > the project's albuild.json (Analyzers / RuleSet) > the project's .vscode/settings.json ('al.codeAnalyzers' / 'al.ruleSetPath'). Only the highest source that supplies a value is used (the sources do not merge), matching how an explicit pipeline input overrides committed config. Analyzer entries are returned as given (tokens / short names / DLL paths - Resolve-BcAnalyzer maps them at compile time); a relative ruleset path is resolved against the project folder. .PARAMETER ProjectFolder The AL project folder (holds app.json, optionally .vscode/settings.json and albuild.json). .PARAMETER WorkspaceRoot Workspace root for albuild.json resolution (merged root + app). Default: the project folder. .PARAMETER InputAnalyzers Explicit analyzers from the task input (comma/semicolon separated). Wins over config. .PARAMETER InputRuleSet Explicit ruleset path from the task input. Wins over config. .OUTPUTS PSCustomObject: Analyzers (string[]), RuleSet (string), AnalyzersSource, RuleSetSource. #> [CmdletBinding()] [OutputType([PSCustomObject])] param( [Parameter(Mandatory)] [string] $ProjectFolder, [string] $WorkspaceRoot, [string] $InputAnalyzers, [string] $InputRuleSet ) if (-not $WorkspaceRoot) { $WorkspaceRoot = $ProjectFolder } # albuild.json (Analyzers / RuleSet) $cfgAnalyzers = @(); $cfgRuleSet = '' try { $cfg = Get-ALbuildProjectConfig -AppFolder $ProjectFolder -WorkspaceRoot $WorkspaceRoot if ($cfg) { if ($cfg.Analyzers) { $cfgAnalyzers = @($cfg.Analyzers) } if ($cfg.RuleSet) { $cfgRuleSet = [string] $cfg.RuleSet } } } catch { Write-Verbose "No albuild.json analyzer config at '$ProjectFolder': $($_.Exception.Message)" } # .vscode/settings.json (al.codeAnalyzers / al.ruleSetPath) $setAnalyzers = @(); $setRuleSet = '' $settingsPath = Join-Path $ProjectFolder '.vscode/settings.json' if (Test-Path -LiteralPath $settingsPath) { try { $raw = Get-Content -LiteralPath $settingsPath -Raw # VS Code settings allow // line comments (JSONC); strip whole-line comments conservatively. $clean = (($raw -split "`n") | ForEach-Object { $_ -replace '^\s*//.*$', '' }) -join "`n" $settings = $clean | ConvertFrom-Json if ($settings.'al.codeAnalyzers') { $setAnalyzers = @($settings.'al.codeAnalyzers') } if ($settings.'al.ruleSetPath') { $setRuleSet = [string] $settings.'al.ruleSetPath' } } catch { Write-Verbose "Could not read analyzers from '$settingsPath': $($_.Exception.Message)" } } # Precedence: task input > albuild.json > settings.json. $analyzers = @(); $aSource = 'none' if (-not [string]::IsNullOrWhiteSpace($InputAnalyzers)) { $analyzers = @($InputAnalyzers -split '[;,]' | ForEach-Object { $_.Trim() } | Where-Object { $_ }) $aSource = 'task input' } elseif ($cfgAnalyzers.Count -gt 0) { $analyzers = $cfgAnalyzers; $aSource = 'albuild.json' } elseif ($setAnalyzers.Count -gt 0) { $analyzers = $setAnalyzers; $aSource = '.vscode/settings.json' } $rawRule = ''; $rSource = 'none' if (-not [string]::IsNullOrWhiteSpace($InputRuleSet)) { $rawRule = $InputRuleSet; $rSource = 'task input' } elseif ($cfgRuleSet) { $rawRule = $cfgRuleSet; $rSource = 'albuild.json' } elseif ($setRuleSet) { $rawRule = $setRuleSet; $rSource = '.vscode/settings.json' } $ruleset = '' if ($rawRule) { $ruleset = if ([System.IO.Path]::IsPathRooted($rawRule)) { $rawRule } else { Join-Path $ProjectFolder $rawRule } } # Test apps are never AppSource-published, so their analyzer findings (AppSourceCop/CodeCop/UICop) are # noise - and the V1 pipeline never ran analyzers at all, so migrated products would newly fail on them # (e.g. AS0015 'TranslationFile'). Disable ALL analyzers for a test app, detected by the AL test # framework (a Microsoft *assert*/*test* dependency, a manifest 'test' reference, or a 'Subtype = Test' # object). This wins over every config source. The ruleset is left as-is (it has no effect without # analyzers, but still governs the compiler's own diagnostics). if ($analyzers.Count -gt 0) { $manifest = $null $appJsonPath = Join-Path $ProjectFolder 'app.json' if (Test-Path -LiteralPath $appJsonPath) { try { $manifest = Get-Content -LiteralPath $appJsonPath -Raw -Encoding UTF8 | ConvertFrom-Json } catch { $manifest = $null } } if ($manifest -and (Test-BcIsTestApp -Manifest $manifest -AppFolder $ProjectFolder)) { Write-ALbuildLog "Test app at '$ProjectFolder': disabling all code analyzers (was $($analyzers -join ', ') from $aSource)." $analyzers = @() $aSource = 'test app (analyzers disabled)' } } return [PSCustomObject]@{ Analyzers = @($analyzers) RuleSet = $ruleset AnalyzersSource = $aSource RuleSetSource = $rSource } } |