Modules/businessdev.ALbuild.Core/Classes/ALbuildConfig.ps1
|
# ALbuild's typed configuration objects. All three live in one file on purpose: PowerShell class # inheritance must resolve the base type at parse time, which is only reliable when the base and # its derived classes are defined together (dot-sourcing a derived class from a separate file does # not see a base defined in another runtime-dot-sourced file). # # Derived classes declare their own strongly-typed settings (as real properties); all the name # lookup / merge / serialisation behaviour lives in the base once, so we never reinvent a "config # shape" as a loose PSCustomObject. class ALbuildConfigBase { # Returns the names of all settings (the declared public properties of the concrete type). [string[]] Keys() { return ($this | Get-Member -MemberType Property | Select-Object -ExpandProperty Name) } [bool] Has([string] $name) { return ($this.Keys() -contains $name) } # Returns the value of a setting by name (case-insensitive), throwing for unknown names. [object] Get([string] $name) { $match = $this.Keys() | Where-Object { $_ -ieq $name } | Select-Object -First 1 if (-not $match) { throw "Unknown ALbuild configuration setting '$name'. Known settings: $($this.Keys() -join ', ')." } return $this.$match } # Applies overrides from a hashtable (case-insensitive). Unknown keys are ignored with a # warning when $ignoreUnknown is $true (merging a config file), otherwise they throw. [void] Apply([hashtable] $overrides, [bool] $ignoreUnknown) { foreach ($key in $overrides.Keys) { $match = $this.Keys() | Where-Object { $_ -ieq [string]$key } | Select-Object -First 1 if ($match) { $this.$match = $overrides[$key] } elseif (-not $ignoreUnknown) { throw "Unknown ALbuild configuration setting '$key'. Known settings: $($this.Keys() -join ', ')." } else { Write-Warning "ALbuild: ignoring unknown configuration setting '$key'." } } } # Serialises to an ordered hashtable for persistence. [System.Collections.Specialized.OrderedDictionary] ToOrderedDictionary() { $dict = [ordered]@{} foreach ($key in $this.Keys()) { $dict[$key] = $this.$key } return $dict } } # Machine/runtime settings for the ALbuild tooling itself. This is NOT a per-workspace, committed # file: it lives under the user's application-data folder (see Get-ALbuildConfigPath) and holds # only host concerns - cache locations, retry behaviour, telemetry and licensing. Project/build # choices (country, artifact type, version, test runner, feeds) belong to ALbuildProjectConfig. class ALbuildConfig : ALbuildConfigBase { # Cache locations [string] $BaseFolder [string] $ArtifactCacheFolder [string] $PackageCacheFolder # Process / retry behaviour [int] $ProcessRetryCount [int] $ProcessRetryDelaySeconds # Telemetry (opt-in) [bool] $TelemetryEnabled [string] $TelemetryConnectionString # Licensing (free tier performs no check; licensed features verify against this service) [string] $LicensingBaseUrl [string] $LicenseAppId ALbuildConfig() { $base = Join-Path -Path ([System.Environment]::GetFolderPath('LocalApplicationData')) -ChildPath 'ALbuild' $this.BaseFolder = $base $this.ArtifactCacheFolder = Join-Path -Path $base -ChildPath 'artifacts' $this.PackageCacheFolder = Join-Path -Path $base -ChildPath 'packages' $this.ProcessRetryCount = 3 $this.ProcessRetryDelaySeconds = 5 $this.TelemetryEnabled = $false $this.TelemetryConnectionString = '' $this.LicensingBaseUrl = 'https://license.365businessapi.com/api' $this.LicenseAppId = '59261337-6a43-4884-98ab-fc62b6230547' } } # Developer-facing, committed project configuration. One file per workspace root and, optionally, # one per app folder in a multi-root workspace (app + test). The app-folder file is merged on top # of the workspace-root file, so an app can override the workspace defaults (e.g. a different # country or a specific test runner). Loaded by Get-ALbuildProjectConfig from 'albuild.json' # (canonical) or a deprecated 'pipeline.config' (V1 fallback). class ALbuildProjectConfig : ALbuildConfigBase { # BC target selection (artifact resolution / container) [string] $Country # localisation of the BC target version (e.g. w1, de, fr) [string] $ArtifactType # Sandbox | OnPrem [string] $BcVersion # explicit version or prefix; empty = newest matching [string] $Select # Latest | First | Closest | NextMinor | NextMajor # Test execution [int] $TestRunnerCodeunitId # 0 = use the isolation default (130450/130451) [string] $TestSuite [bool] $DisableTestIsolation # Dependency feeds (in addition to any registered with Register-BcFeed). Each entry is either a # plain feed URL (string) or an object { url, name?, kind?, idScheme?, token?, tokenEnv? } - see # ConvertTo-BcFeedDefinition. Only 'url' is required; everything else is auto-detected. [object[]] $Feeds # Multi-root build: folder leaf names to exclude from the pipeline (e.g. 'migration'). The build # tasks merge this with the pipeline 'excludeProjects' parameter. See Get-BcProjectBuildOrder. [string[]] $ExcludeProjects # Dependency apps that are NOT resolved from a NuGet feed. Both are staged into each project's # .alpackages and pinned as a satisfied baseline for NuGet resolution (so they are not also # fetched from a feed), then installed into the build container with the feed-resolved apps. # UniversalPackages: Azure DevOps Universal feed packages, each an object # { feed, name, version?, organization?, project? } (organization defaults to the collection # URI). For shared symbol bundles / apps published to a Universal feed. # LocalPackages: repository folders holding committed .app files (for ISVs without a public # feed, e.g. CKL). Paths are relative to the repository root. Default: '.dependencies'. [object[]] $UniversalPackages [string[]] $LocalPackages ALbuildProjectConfig() { $this.Country = 'w1' $this.ArtifactType = 'Sandbox' $this.BcVersion = '' $this.Select = 'Latest' $this.TestRunnerCodeunitId = 0 $this.TestSuite = 'DEFAULT' $this.DisableTestIsolation = $false $this.Feeds = @() $this.ExcludeProjects = @() $this.UniversalPackages = @() $this.LocalPackages = @('.dependencies') } # The effective test-runner codeunit: an explicit id, otherwise the isolation default. [int] EffectiveTestRunnerCodeunitId() { if ($this.TestRunnerCodeunitId -gt 0) { return $this.TestRunnerCodeunitId } if ($this.DisableTestIsolation) { return 130451 } return 130450 } } |