Modules/businessdev.ALbuild.Apps/Public/Update-BcAppManifest.ps1
|
function Update-BcAppManifest { <# .SYNOPSIS Prepares an AL app manifest (app.json) for a target BC version: version features + preprocessor symbols. .DESCRIPTION Restores the pipeline's V1 "update manifest" behaviour for a compile against a specific BC version (a normal build against Latest, or a runtime package built for an older platform). Two adjustments, both keyed to -BcVersion: * Version features (port of Apply-BcVersionFeatures): set 'application' and 'platform' to '<major>.0.0.0' and 'runtime' to the target's AL runtime version. The runtime is '(major - 11).0' for BC >= 12 (17->6.0, 22->11.0, 28->17.0, ...), with the BC 18.1+ -> 7.1 special case; this keeps working for future majors (V1 stopped at 26/27). Skipped with -SkipVersionFeatures (then only the preprocessor symbols are written). * Preprocessor symbols: 'BC<min>'..'BC<target>', where 'min' is the app's ORIGINAL 'application' major (read BEFORE the version-feature rewrite), plus any -PreprocessorSymbols. This lets version-conditional AL ('#if BC24 ... #endif') compile. Any existing 'preprocessorSymbols' array is replaced. Operates on a single app.json or every app.json under a folder (skipping .alpackages / output). Rewrites the file in place (build workspace); use before Invoke-BcCompiler. .PARAMETER Path An app.json file, or a folder searched recursively for app.json. .PARAMETER BcVersion The target BC version - full ('28.3.52162.52455') or major ('28'); its major drives everything. .PARAMETER PreprocessorSymbols Extra preprocessor symbols to add alongside the BC<n> range. .PARAMETER SkipVersionFeatures Only inject preprocessor symbols; leave application / runtime / platform unchanged. .EXAMPLE Update-BcAppManifest -Path .\app -BcVersion '28.3.52162.52455' .OUTPUTS PSCustomObject per app.json: AppJsonPath, MinMajor, TargetMajor, Runtime, Symbols. #> [CmdletBinding(SupportsShouldProcess)] [OutputType([PSCustomObject])] param( [Parameter(Mandatory)] [string] $Path, [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string] $BcVersion, [string[]] $PreprocessorSymbols = @(), [switch] $SkipVersionFeatures ) if (-not (Test-Path -LiteralPath $Path)) { throw "Path '$Path' does not exist." } $target = ConvertTo-BcVersion $BcVersion $targetMajor = $target.Major # AL runtime for the target major: (major - 11).0 for BC >= 12 (17->6.0 ... 28->17.0); 18.1+ -> 7.1. $runtime = if ($targetMajor -eq 18 -and $target.Minor -ge 1) { '7.1' } else { "$($targetMajor - 11).0" } $item = Get-Item -LiteralPath $Path if ($item.PSIsContainer) { $files = @(Get-ChildItem -LiteralPath $item.FullName -Filter 'app.json' -File -Recurse -ErrorAction SilentlyContinue | Where-Object { $_.FullName -notmatch '[\\/](\.alpackages|\.altemplates|\.snapshots|\.output|output)[\\/]' }) } elseif ($item.Name -eq 'app.json') { $files = @($item) } else { throw "Path '$Path' is neither a folder nor an app.json file." } if ($files.Count -eq 0) { throw "No app.json found under '$Path'." } $utf8NoBom = [System.Text.UTF8Encoding]::new($false) foreach ($file in $files) { $raw = [System.IO.File]::ReadAllText($file.FullName) $json = $raw | ConvertFrom-Json if (-not ($json.PSObject.Properties.Name -contains 'application')) { throw "'$($file.FullName)' has no top-level 'application' property." } $minMajor = (ConvertTo-BcVersion ([string] $json.application)).Major # BC<min>..BC<target> (either direction) + any extra symbols. $symbols = [System.Collections.Generic.List[string]]::new() $lo = [Math]::Min($minMajor, $targetMajor) $hi = [Math]::Max($minMajor, $targetMajor) for ($i = $lo; $i -le $hi; $i++) { $symbols.Add("BC$i") } foreach ($s in $PreprocessorSymbols) { if (-not [string]::IsNullOrWhiteSpace($s)) { $symbols.Add($s.Trim()) } } if (-not $SkipVersionFeatures) { $json | Add-Member -Name 'application' -Value "$targetMajor.0.0.0" -MemberType NoteProperty -Force $json | Add-Member -Name 'platform' -Value "$targetMajor.0.0.0" -MemberType NoteProperty -Force $json | Add-Member -Name 'runtime' -Value $runtime -MemberType NoteProperty -Force } $json | Add-Member -Name 'preprocessorSymbols' -Value ([string[]] $symbols) -MemberType NoteProperty -Force if ($PSCmdlet.ShouldProcess($file.FullName, "Update manifest for BC $targetMajor")) { $out = $json | ConvertTo-Json -Depth 100 # Windows PowerShell 5.1 escapes < > & ' to \uXXXX; restore them (valid JSON either way). $out = $out -replace '\\u0026', '&' -replace '\\u003c', '<' -replace '\\u003e', '>' -replace '\\u0027', "'" [System.IO.File]::WriteAllText($file.FullName, $out, $utf8NoBom) $vf = if ($SkipVersionFeatures) { '(symbols only)' } else { "application $targetMajor.0.0.0, runtime $runtime" } Write-ALbuildLog -Level Success "Manifest '$($file.Directory.Name)': $vf, symbols [$($symbols -join ', ')]." } [PSCustomObject]@{ AppJsonPath = $file.FullName MinMajor = $minMajor TargetMajor = $targetMajor Runtime = $runtime Symbols = @($symbols) } } } |