diff --git a/Actions/.Modules/ReadSettings.psm1 b/Actions/.Modules/ReadSettings.psm1
new file mode 100644
index 000000000..27aba1e1e
--- /dev/null
+++ b/Actions/.Modules/ReadSettings.psm1
@@ -0,0 +1,475 @@
+$ALGoFolderName = '.AL-Go'
+$ALGoSettingsFile = Join-Path '.AL-Go' 'settings.json'
+$RepoSettingsFile = Join-Path '.github' 'AL-Go-Settings.json'
+$CustomTemplateRepoSettingsFile = Join-Path '.github' 'AL-Go-TemplateRepoSettings.doNotEdit.json'
+$CustomTemplateProjectSettingsFile = Join-Path '.github' 'AL-Go-TemplateProjectSettings.doNotEdit.json'
+
+function MergeCustomObjectIntoOrderedDictionary {
+ Param(
+ [System.Collections.Specialized.OrderedDictionary] $dst,
+ [PSCustomObject] $src
+ )
+
+ # Loop through all properties in the source object
+ # If the property does not exist in the destination object, add it with the right type, but no value
+ # Types supported: PSCustomObject, Object[] and simple types
+ $src.PSObject.Properties.GetEnumerator() | ForEach-Object {
+ $prop = $_.Name
+ $srcProp = $src."$prop"
+ $srcPropType = $srcProp.GetType().Name
+ if (-not $dst.Contains($prop)) {
+ if ($srcPropType -eq "PSCustomObject") {
+ $dst.Add("$prop", [ordered]@{})
+ }
+ elseif ($srcPropType -eq "Object[]") {
+ $dst.Add("$prop", @())
+ }
+ else {
+ $dst.Add("$prop", $srcProp)
+ }
+ }
+ }
+
+ # Loop through all properties in the destination object
+ # If the property does not exist in the source object, do nothing
+ # If the property exists in the source object, but is of a different type, throw an error
+ # If the property exists in the source object:
+ # If the property is an Object, call this function recursively to merge values
+ # If the property is an Object[], merge the arrays
+ # If the property is a simple type, replace the value in the destination object with the value from the source object
+ @($dst.Keys) | ForEach-Object {
+ $prop = $_
+ if ($src.PSObject.Properties.Name -eq $prop) {
+ $dstProp = $dst."$prop"
+ $srcProp = $src."$prop"
+ $dstPropType = $dstProp.GetType().Name
+ $srcPropType = $srcProp.GetType().Name
+ if ($srcPropType -eq "PSCustomObject" -and $dstPropType -eq "OrderedDictionary") {
+ MergeCustomObjectIntoOrderedDictionary -dst $dst."$prop" -src $srcProp
+ }
+ elseif ($dstPropType -ne $srcPropType -and !($srcPropType -eq "Int64" -and $dstPropType -eq "Int32")) {
+ # Under Linux, the Int fields read from the .json file will be Int64, while the settings defaults will be Int32
+ # This is not seen as an error and will not throw an error
+ throw "property $prop should be of type $dstPropType, is $srcPropType."
+ }
+ else {
+ if ($srcProp -is [Object[]]) {
+ $srcProp | ForEach-Object {
+ $srcElm = $_
+ $srcElmType = $srcElm.GetType().Name
+ if ($srcElmType -eq "PSCustomObject") {
+ # Array of objects are not checked for uniqueness
+ $ht = [ordered]@{}
+ $srcElm.PSObject.Properties | Sort-Object -Property Name -Culture ([cultureinfo]::InvariantCulture) | ForEach-Object {
+ $ht[$_.Name] = $_.Value
+ }
+ $dst."$prop" += @($ht)
+ }
+ else {
+ # Add source element to destination array, but only if it does not already exist
+ $dst."$prop" = @($dst."$prop" + $srcElm | Select-Object -Unique)
+ }
+ }
+ }
+ else {
+ $dst."$prop" = $srcProp
+ }
+ }
+ }
+ }
+}
+
+function GetDefaultSettings
+(
+ [string] $repoName
+)
+{
+ return [ordered]@{
+ "type" = "PTE"
+ "unusedALGoSystemFiles" = @()
+ "projects" = @()
+ "powerPlatformSolutionFolder" = ""
+ "country" = "us"
+ "artifact" = ""
+ "companyName" = ""
+ "repoVersion" = "1.0"
+ "repoName" = "$repoName"
+ "versioningStrategy" = 0
+ "runNumberOffset" = 0
+ "appBuild" = 0
+ "appRevision" = 0
+ "keyVaultName" = ""
+ "licenseFileUrlSecretName" = "licenseFileUrl"
+ "ghTokenWorkflowSecretName" = "ghTokenWorkflow"
+ "adminCenterApiCredentialsSecretName" = "adminCenterApiCredentials"
+ "applicationInsightsConnectionStringSecretName" = "applicationInsightsConnectionString"
+ "keyVaultCertificateUrlSecretName" = ""
+ "keyVaultCertificatePasswordSecretName" = ""
+ "keyVaultClientIdSecretName" = ""
+ "keyVaultCodesignCertificateName" = ""
+ "codeSignCertificateUrlSecretName" = "codeSignCertificateUrl"
+ "codeSignCertificatePasswordSecretName" = "codeSignCertificatePassword"
+ "additionalCountries" = @()
+ "appDependencies" = @()
+ "projectName" = ""
+ "appFolders" = @()
+ "testDependencies" = @()
+ "testFolders" = @()
+ "bcptTestFolders" = @()
+ "pageScriptingTests" = @()
+ "restoreDatabases" = @()
+ "installApps" = @()
+ "installTestApps" = @()
+ "installOnlyReferencedApps" = $true
+ "generateDependencyArtifact" = $false
+ "skipUpgrade" = $false
+ "applicationDependency" = "18.0.0.0"
+ "updateDependencies" = $false
+ "installTestRunner" = $false
+ "installTestFramework" = $false
+ "installTestLibraries" = $false
+ "installPerformanceToolkit" = $false
+ "enableCodeCop" = $false
+ "enableUICop" = $false
+ "enableCodeAnalyzersOnTestApps" = $false
+ "customCodeCops" = @()
+ "failOn" = "error"
+ "treatTestFailuresAsWarnings" = $false
+ "rulesetFile" = ""
+ "enableExternalRulesets" = $false
+ "vsixFile" = ""
+ "assignPremiumPlan" = $false
+ "enableTaskScheduler" = $false
+ "doNotBuildTests" = $false
+ "doNotRunTests" = $false
+ "doNotRunBcptTests" = $false
+ "doNotRunPageScriptingTests" = $false
+ "doNotPublishApps" = $false
+ "doNotSignApps" = $false
+ "configPackages" = @()
+ "appSourceCopMandatoryAffixes" = @()
+ "deliverToAppSource" = [ordered]@{
+ "mainAppFolder" = ""
+ "productId" = ""
+ "includeDependencies" = @()
+ "continuousDelivery" = $false
+ }
+ "obsoleteTagMinAllowedMajorMinor" = ""
+ "memoryLimit" = ""
+ "templateUrl" = ""
+ "templateSha" = ""
+ "templateBranch" = ""
+ "appDependencyProbingPaths" = @()
+ "useProjectDependencies" = $false
+ "runs-on" = "windows-latest"
+ "shell" = ""
+ "githubRunner" = ""
+ "githubRunnerShell" = ""
+ "cacheImageName" = "my"
+ "cacheKeepDays" = 3
+ "alwaysBuildAllProjects" = $false
+ "incrementalBuilds" = [ordered]@{
+ "onPush" = $false
+ "onPull_Request" = $true
+ "onSchedule" = $false
+ "retentionDays" = 30
+ "mode" = "modifiedApps" # modifiedProjects, modifiedApps
+ }
+ "microsoftTelemetryConnectionString" = "InstrumentationKey=cd2cc63e-0f37-4968-b99a-532411a314b8;IngestionEndpoint=https://northeurope-2.in.applicationinsights.azure.com/"
+ "partnerTelemetryConnectionString" = ""
+ "sendExtendedTelemetryToMicrosoft" = $false
+ "environments" = @()
+ "buildModes" = @()
+ "useCompilerFolder" = $false
+ "pullRequestTrigger" = "pull_request_target"
+ "bcptThresholds" = [ordered]@{
+ "DurationWarning" = 10
+ "DurationError" = 25
+ "NumberOfSqlStmtsWarning" = 5
+ "NumberOfSqlStmtsError" = 10
+ }
+ "fullBuildPatterns" = @()
+ "excludeEnvironments" = @()
+ "alDoc" = [ordered]@{
+ "continuousDeployment" = $false
+ "deployToGitHubPages" = $true
+ "maxReleases" = 3
+ "groupByProject" = $true
+ "includeProjects" = @()
+ "excludeProjects" = @()
+ "header" = "Documentation for {REPOSITORY} {VERSION}"
+ "footer" = "Documentation for {REPOSITORY} made with AL-Go for GitHub, ALDoc and DocFx"
+ "defaultIndexMD" = "## Reference documentation\n\nThis is the generated reference documentation for [{REPOSITORY}](https://github.com/{REPOSITORY}).\n\nYou can use the navigation bar at the top and the table of contents to the left to navigate your documentation.\n\nYou can change this content by creating/editing the **{INDEXTEMPLATERELATIVEPATH}** file in your repository or use the alDoc:defaultIndexMD setting in your repository settings file (.github/AL-Go-Settings.json)\n\n{RELEASENOTES}"
+ "defaultReleaseMD" = "## Release reference documentation\n\nThis is the generated reference documentation for [{REPOSITORY}](https://github.com/{REPOSITORY}).\n\nYou can use the navigation bar at the top and the table of contents to the left to navigate your documentation.\n\nYou can change this content by creating/editing the **{INDEXTEMPLATERELATIVEPATH}** file in your repository or use the alDoc:defaultReleaseMD setting in your repository settings file (.github/AL-Go-Settings.json)\n\n{RELEASENOTES}"
+ }
+ "trustMicrosoftNuGetFeeds" = $true
+ "nuGetFeedSelectMode" = "LatestMatching"
+ "commitOptions" = [ordered]@{
+ "messageSuffix" = ""
+ "pullRequestAutoMerge" = $false
+ "pullRequestLabels" = @()
+ "createPullRequest" = $true
+ }
+ "trustedSigning" = [ordered]@{
+ "Endpoint" = ""
+ "Account" = ""
+ "CertificateProfile" = ""
+ }
+ "useGitSubmodules" = "false"
+ "gitSubmodulesTokenSecretName" = "gitSubmodulesToken"
+ "shortLivedArtifactsRetentionDays" = 1 # 0 means use GitHub default
+ }
+}
+
+
+<#
+ .SYNOPSIS
+ Read settings from the settings files and merge them into an ordered dictionary.
+ .DESCRIPTION
+ This function reads settings from various files and merges them into an ordered dictionary.
+ The settings are read from the following files:
+ - ALGoOrgSettings (github Variable) = Organization settings variable
+ - .github/AL-Go-TemplateRepoSettings.doNotEdit.json = Repository settings from custom template
+ - .github/AL-Go-Settings.json = Repository Settings file
+ - ALGoRepoSettings (github Variable) = Repository settings variable
+ - .github/AL-Go-TemplateProjectSettings.doNotEdit.json = Project settings from custom template
+ - /.AL-Go/settings.json = Project settings file
+ - .github/.settings.json = Workflow settings file
+ - /.AL-Go/.settings.json = Project workflow settings file
+ - /.AL-Go/.settings.json = User settings file
+ .PARAMETER baseFolder
+ The base folder where the settings files are located. Default is $ENV:GITHUB_WORKSPACE when running in GitHub Actions.
+ .PARAMETER repoName
+ The name of the repository. Default is $ENV:GITHUB_REPOSITORY when running in GitHub Actions.
+ .PARAMETER project
+ The project path relative to the base folder. Default is '.'
+ .PARAMETER buildMode
+ The build mode to use when there are conditional settings. Default is "Default".
+ .PARAMETER workflowName
+ The name of the workflow. Default is $ENV:GITHUB_WORKFLOW when running in GitHub Actions.
+ .PARAMETER userName
+ The name of the user. Default is $ENV:GITHUB_ACTOR when running in GitHub Actions.
+ .PARAMETER branchName
+ The name of the branch to use for conditional settings. Default is $ENV:GITHUB_REF_NAME when running in GitHub Actions.
+ .PARAMETER orgSettingsVariableValue
+ The value of the organization settings variable. Default is $ENV:ALGoOrgSettings.
+ .PARAMETER repoSettingsVariableValue
+ The value of the repository settings variable. Default is $ENV:ALGoRepoSettings.
+ .PARAMETER silent
+ If specified, the function will not output any messages to the console.
+#>
+function ReadSettings {
+ Param(
+ [string] $baseFolder = "$ENV:GITHUB_WORKSPACE",
+ [string] $repoName = "$ENV:GITHUB_REPOSITORY",
+ [string] $project = '.',
+ [string] $buildMode = "Default",
+ [string] $workflowName = "$ENV:GITHUB_WORKFLOW",
+ [string] $userName = "$ENV:GITHUB_ACTOR",
+ [string] $branchName = "$ENV:GITHUB_REF_NAME",
+ [string] $orgSettingsVariableValue = "$ENV:ALGoOrgSettings",
+ [string] $repoSettingsVariableValue = "$ENV:ALGoRepoSettings",
+ [switch] $silent
+ )
+
+ # If the build is triggered by a pull request the refname will be the merge branch. To apply conditional settings we need to use the base branch
+ if (($env:GITHUB_EVENT_NAME -eq "pull_request") -and ($branchName -eq $ENV:GITHUB_REF_NAME)) {
+ $branchName = $env:GITHUB_BASE_REF
+ }
+
+ function GetSettingsObject {
+ Param(
+ [string] $path
+ )
+
+ if (Test-Path $path) {
+ try {
+ if (!$silent.IsPresent) { Write-Host "Applying settings from $path" }
+ $settings = Get-Content $path -Encoding UTF8 | ConvertFrom-Json
+ if ($settings) {
+ return $settings
+ }
+ }
+ catch {
+ throw "Error reading $path. Error was $($_.Exception.Message).`n$($_.ScriptStackTrace)"
+ }
+ }
+ else {
+ if (!$silent.IsPresent) { Write-Host "No settings found in $path" }
+ }
+ return $null
+ }
+
+ $repoName = $repoName.SubString("$repoName".LastIndexOf('/') + 1)
+ $githubFolder = Join-Path $baseFolder ".github"
+ $workflowName = $workflowName.Trim().Split([System.IO.Path]::getInvalidFileNameChars()) -join ""
+
+ # Start with default settings
+ $settings = GetDefaultSettings -repoName $repoName
+
+ # Read settings from files and merge them into the settings object
+
+ $settingsObjects = @()
+ # Read settings from organization settings variable (parameter)
+ if ($orgSettingsVariableValue) {
+ $orgSettingsVariableObject = $orgSettingsVariableValue | ConvertFrom-Json
+ $settingsObjects += @($orgSettingsVariableObject)
+ }
+
+ # Read settings from repository settings file
+ $customTemplateRepoSettingsObject = GetSettingsObject -Path (Join-Path $baseFolder $CustomTemplateRepoSettingsFile)
+ $settingsObjects += @($customTemplateRepoSettingsObject)
+
+ # Read settings from repository settings file
+ $repoSettingsObject = GetSettingsObject -Path (Join-Path $baseFolder $RepoSettingsFile)
+ $settingsObjects += @($repoSettingsObject)
+
+ # Read settings from repository settings variable (parameter)
+ if ($repoSettingsVariableValue) {
+ $repoSettingsVariableObject = $repoSettingsVariableValue | ConvertFrom-Json
+ $settingsObjects += @($repoSettingsVariableObject)
+ }
+
+ if ($project) {
+ # Read settings from repository settings file
+ $customTemplateProjectSettingsObject = GetSettingsObject -Path (Join-Path $baseFolder $CustomTemplateProjectSettingsFile)
+ $settingsObjects += @($customTemplateProjectSettingsObject)
+ # Read settings from project settings file
+ $projectFolder = Join-Path $baseFolder $project -Resolve
+ $projectSettingsObject = GetSettingsObject -Path (Join-Path $projectFolder $ALGoSettingsFile)
+ $settingsObjects += @($projectSettingsObject)
+ }
+
+ if ($workflowName) {
+ # Read settings from workflow settings file
+ $workflowSettingsObject = GetSettingsObject -Path (Join-Path $gitHubFolder "$workflowName.settings.json")
+ $settingsObjects += @($workflowSettingsObject)
+ if ($project) {
+ # Read settings from project workflow settings file
+ $projectWorkflowSettingsObject = GetSettingsObject -Path (Join-Path $projectFolder "$ALGoFolderName/$workflowName.settings.json")
+ # Read settings from user settings file
+ $userSettingsObject = GetSettingsObject -Path (Join-Path $projectFolder "$ALGoFolderName/$userName.settings.json")
+ $settingsObjects += @($projectWorkflowSettingsObject, $userSettingsObject)
+ }
+ }
+
+ foreach($settingsJson in $settingsObjects) {
+ if ($settingsJson) {
+ MergeCustomObjectIntoOrderedDictionary -dst $settings -src $settingsJson
+ if ($settingsJson.PSObject.Properties.Name -eq "ConditionalSettings") {
+ foreach($conditionalSetting in $settingsJson.ConditionalSettings) {
+ if ("$conditionalSetting" -ne "") {
+ $conditionMet = $true
+ $conditions = @()
+ @{"buildModes" = $buildMode; "branches" = $branchName; "repositories" = $repoName; "projects" = $project; "workflows" = $workflowName; "users" = $userName}.GetEnumerator() | ForEach-Object {
+ $propName = $_.Key
+ $propValue = $_.Value
+ if ($conditionMet -and $conditionalSetting.PSObject.Properties.Name -eq $propName) {
+ $conditionMet = $propValue -and $conditionMet -and ($conditionalSetting."$propName" | Where-Object { $propValue -like $_ })
+ $conditions += @("$($propName): $propValue")
+ }
+ }
+ if ($conditionMet) {
+ if (!$silent.IsPresent) { Write-Host "Applying conditional settings for $($conditions -join ", ")" }
+ MergeCustomObjectIntoOrderedDictionary -dst $settings -src $conditionalSetting.settings
+ }
+ }
+ }
+ }
+ }
+ }
+
+ # runs-on is used for all jobs except for the build job (basically all jobs which doesn't need a container)
+ # gitHubRunner is used for the build job (or basically all jobs that needs a container)
+ #
+ # shell defaults to "powershell" unless runs-on is Ubuntu (Linux), then it defaults to pwsh
+ #
+ # gitHubRunner defaults to "runs-on", unless runs-on is Ubuntu (Linux) as this won't work.
+ # gitHubRunnerShell defaults to "shell"
+ #
+ # The exception for keeping gitHubRunner to Windows-Latest (when set to Ubuntu-*) will be removed when all jobs supports Ubuntu (Linux)
+ # At some point in the future (likely version 3.0), we will switch to Ubuntu (Linux) as default for "runs-on"
+ #
+ if ($settings.shell -eq "") {
+ if ($settings."runs-on" -like "*ubuntu-*") {
+ $settings.shell = "pwsh"
+ }
+ else {
+ $settings.shell = "powershell"
+ }
+ }
+ if ($settings.githubRunner -eq "") {
+ if ($settings."runs-on" -like "*ubuntu-*") {
+ $settings.githubRunner = "windows-latest"
+ }
+ else {
+ $settings.githubRunner = $settings."runs-on"
+ }
+ }
+ if ($settings.githubRunnerShell -eq "") {
+ $settings.githubRunnerShell = $settings.shell
+ }
+
+ # Check that gitHubRunnerShell and Shell is valid
+ if ($settings.githubRunnerShell -ne "powershell" -and $settings.githubRunnerShell -ne "pwsh") {
+ throw "Invalid value for setting: gitHubRunnerShell: $($settings.githubRunnerShell)"
+ }
+ if ($settings.shell -ne "powershell" -and $settings.shell -ne "pwsh") {
+ throw "Invalid value for setting: shell: $($settings.githubRunnerShell)"
+ }
+
+ if (($settings.githubRunner -like "*ubuntu-*") -and ($settings.githubRunnerShell -eq "powershell")) {
+ if (!$silent.IsPresent) { Write-Host "Switching shell to pwsh for ubuntu" }
+ $settings.githubRunnerShell = "pwsh"
+ }
+
+ if($settings.projectName -eq '') {
+ $settings.projectName = $project # Default to project path as project name
+ }
+
+ $settings | ValidateSettings
+
+ $settings
+}
+
+<#
+ .SYNOPSIS
+ Validate the settings against the settings schema file.
+ .PARAMETER settings
+ The settings to validate.
+#>
+function ValidateSettings {
+ Param(
+ [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
+ $settings
+ )
+ Process {
+ $settingsJson = ConvertTo-Json -InputObject $settings -Depth 99 -Compress
+ $settingsSchemaFile = Join-Path $PSScriptRoot "settings.schema.json" -Resolve
+
+ $result = ""
+ try{
+ $command = [scriptblock] {
+ $result = ''
+ Test-Json -Json $args[0] -SchemaFile $args[1] -ErrorVariable result -ErrorAction SilentlyContinue | Out-Null
+ return $result
+ }
+
+ if($PSVersionTable.PSVersion.Major -lt 6) { # Test-Json is not available in PS5.1
+ $result = pwsh -noprofile -Command $command -args $settingsJson, $settingsSchemaFile
+ }
+ else {
+ $result = Invoke-Command -ScriptBlock $command -ArgumentList $settingsJson, $settingsSchemaFile
+ }
+ }
+ catch {
+ OutputWarning "Error validating settings. Error: $($_.Exception.Message)"
+ }
+ if ($result) {
+ OutputWarning "Settings are not valid. Error: $result"
+ }
+ }
+}
+
+Export-ModuleMember -Function ReadSettings
+Export-ModuleMember -Variable ALGoFolderName, ALGoSettingsFile, RepoSettingsFile, CustomTemplateRepoSettingsFile, CustomTemplateProjectSettingsFile
diff --git a/Actions/settings.schema.json b/Actions/.Modules/settings.schema.json
similarity index 100%
rename from Actions/settings.schema.json
rename to Actions/.Modules/settings.schema.json
diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1
index a9982e024..cddbd9ddc 100644
--- a/Actions/AL-Go-Helper.ps1
+++ b/Actions/AL-Go-Helper.ps1
@@ -3,18 +3,21 @@ Param(
)
$gitHubHelperPath = Join-Path $PSScriptRoot 'Github-Helper.psm1'
+$readSettingsModule = Join-Path $PSScriptRoot '.Modules/ReadSettings.psm1'
if (Test-Path $gitHubHelperPath) {
Import-Module $gitHubHelperPath
# If we are adding more dependencies here, then localDevEnv and cloudDevEnv needs to be updated
}
+if (Test-Path $readSettingsModule) {
+ Import-Module $readSettingsModule
+}
+
$errorActionPreference = "Stop"; $ProgressPreference = "SilentlyContinue"; Set-StrictMode -Version 2.0
$ALGoFolderName = '.AL-Go'
$ALGoSettingsFile = Join-Path '.AL-Go' 'settings.json'
$RepoSettingsFile = Join-Path '.github' 'AL-Go-Settings.json'
-$CustomTemplateRepoSettingsFile = Join-Path '.github' 'AL-Go-TemplateRepoSettings.doNotEdit.json'
-$CustomTemplateProjectSettingsFile = Join-Path '.github' 'AL-Go-TemplateProjectSettings.doNotEdit.json'
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'defaultCICDPushBranches', Justification = 'False positive.')]
$defaultCICDPushBranches = @( 'main', 'release/*', 'feature/*' )
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'defaultCICDPullRequestBranches', Justification = 'False positive.')]
@@ -461,447 +464,6 @@ function DownloadAndImportBcContainerHelper([string] $baseFolder = $ENV:GITHUB_W
. $bcContainerHelperPath @params
}
-function MergeCustomObjectIntoOrderedDictionary {
- Param(
- [System.Collections.Specialized.OrderedDictionary] $dst,
- [PSCustomObject] $src
- )
-
- # Loop through all properties in the source object
- # If the property does not exist in the destination object, add it with the right type, but no value
- # Types supported: PSCustomObject, Object[] and simple types
- $src.PSObject.Properties.GetEnumerator() | ForEach-Object {
- $prop = $_.Name
- $srcProp = $src."$prop"
- $srcPropType = $srcProp.GetType().Name
- if (-not $dst.Contains($prop)) {
- if ($srcPropType -eq "PSCustomObject") {
- $dst.Add("$prop", [ordered]@{})
- }
- elseif ($srcPropType -eq "Object[]") {
- $dst.Add("$prop", @())
- }
- else {
- $dst.Add("$prop", $srcProp)
- }
- }
- }
-
- # Loop through all properties in the destination object
- # If the property does not exist in the source object, do nothing
- # If the property exists in the source object, but is of a different type, throw an error
- # If the property exists in the source object:
- # If the property is an Object, call this function recursively to merge values
- # If the property is an Object[], merge the arrays
- # If the property is a simple type, replace the value in the destination object with the value from the source object
- @($dst.Keys) | ForEach-Object {
- $prop = $_
- if ($src.PSObject.Properties.Name -eq $prop) {
- $dstProp = $dst."$prop"
- $srcProp = $src."$prop"
- $dstPropType = $dstProp.GetType().Name
- $srcPropType = $srcProp.GetType().Name
- if ($srcPropType -eq "PSCustomObject" -and $dstPropType -eq "OrderedDictionary") {
- MergeCustomObjectIntoOrderedDictionary -dst $dst."$prop" -src $srcProp
- }
- elseif ($dstPropType -ne $srcPropType -and !($srcPropType -eq "Int64" -and $dstPropType -eq "Int32")) {
- # Under Linux, the Int fields read from the .json file will be Int64, while the settings defaults will be Int32
- # This is not seen as an error and will not throw an error
- throw "property $prop should be of type $dstPropType, is $srcPropType."
- }
- else {
- if ($srcProp -is [Object[]]) {
- $srcProp | ForEach-Object {
- $srcElm = $_
- $srcElmType = $srcElm.GetType().Name
- if ($srcElmType -eq "PSCustomObject") {
- # Array of objects are not checked for uniqueness
- $ht = [ordered]@{}
- $srcElm.PSObject.Properties | Sort-Object -Property Name -Culture ([cultureinfo]::InvariantCulture) | ForEach-Object {
- $ht[$_.Name] = $_.Value
- }
- $dst."$prop" += @($ht)
- }
- else {
- # Add source element to destination array, but only if it does not already exist
- $dst."$prop" = @($dst."$prop" + $srcElm | Select-Object -Unique)
- }
- }
- }
- else {
- $dst."$prop" = $srcProp
- }
- }
- }
- }
-}
-
-function GetDefaultSettings
-(
- [string] $repoName
-)
-{
- return [ordered]@{
- "type" = "PTE"
- "unusedALGoSystemFiles" = @()
- "projects" = @()
- "powerPlatformSolutionFolder" = ""
- "country" = "us"
- "artifact" = ""
- "companyName" = ""
- "repoVersion" = "1.0"
- "repoName" = "$repoName"
- "versioningStrategy" = 0
- "runNumberOffset" = 0
- "appBuild" = 0
- "appRevision" = 0
- "keyVaultName" = ""
- "licenseFileUrlSecretName" = "licenseFileUrl"
- "ghTokenWorkflowSecretName" = "ghTokenWorkflow"
- "adminCenterApiCredentialsSecretName" = "adminCenterApiCredentials"
- "applicationInsightsConnectionStringSecretName" = "applicationInsightsConnectionString"
- "keyVaultCertificateUrlSecretName" = ""
- "keyVaultCertificatePasswordSecretName" = ""
- "keyVaultClientIdSecretName" = ""
- "keyVaultCodesignCertificateName" = ""
- "codeSignCertificateUrlSecretName" = "codeSignCertificateUrl"
- "codeSignCertificatePasswordSecretName" = "codeSignCertificatePassword"
- "additionalCountries" = @()
- "appDependencies" = @()
- "projectName" = ""
- "appFolders" = @()
- "testDependencies" = @()
- "testFolders" = @()
- "bcptTestFolders" = @()
- "pageScriptingTests" = @()
- "restoreDatabases" = @()
- "installApps" = @()
- "installTestApps" = @()
- "installOnlyReferencedApps" = $true
- "generateDependencyArtifact" = $false
- "skipUpgrade" = $false
- "applicationDependency" = "18.0.0.0"
- "updateDependencies" = $false
- "installTestRunner" = $false
- "installTestFramework" = $false
- "installTestLibraries" = $false
- "installPerformanceToolkit" = $false
- "enableCodeCop" = $false
- "enableUICop" = $false
- "enableCodeAnalyzersOnTestApps" = $false
- "customCodeCops" = @()
- "failOn" = "error"
- "treatTestFailuresAsWarnings" = $false
- "rulesetFile" = ""
- "enableExternalRulesets" = $false
- "vsixFile" = ""
- "assignPremiumPlan" = $false
- "enableTaskScheduler" = $false
- "doNotBuildTests" = $false
- "doNotRunTests" = $false
- "doNotRunBcptTests" = $false
- "doNotRunPageScriptingTests" = $false
- "doNotPublishApps" = $false
- "doNotSignApps" = $false
- "configPackages" = @()
- "appSourceCopMandatoryAffixes" = @()
- "deliverToAppSource" = [ordered]@{
- "mainAppFolder" = ""
- "productId" = ""
- "includeDependencies" = @()
- "continuousDelivery" = $false
- }
- "obsoleteTagMinAllowedMajorMinor" = ""
- "memoryLimit" = ""
- "templateUrl" = ""
- "templateSha" = ""
- "templateBranch" = ""
- "appDependencyProbingPaths" = @()
- "useProjectDependencies" = $false
- "runs-on" = "windows-latest"
- "shell" = ""
- "githubRunner" = ""
- "githubRunnerShell" = ""
- "cacheImageName" = "my"
- "cacheKeepDays" = 3
- "alwaysBuildAllProjects" = $false
- "incrementalBuilds" = [ordered]@{
- "onPush" = $false
- "onPull_Request" = $true
- "onSchedule" = $false
- "retentionDays" = 30
- "mode" = "modifiedApps" # modifiedProjects, modifiedApps
- }
- "microsoftTelemetryConnectionString" = "InstrumentationKey=cd2cc63e-0f37-4968-b99a-532411a314b8;IngestionEndpoint=https://northeurope-2.in.applicationinsights.azure.com/"
- "partnerTelemetryConnectionString" = ""
- "sendExtendedTelemetryToMicrosoft" = $false
- "environments" = @()
- "buildModes" = @()
- "useCompilerFolder" = $false
- "pullRequestTrigger" = "pull_request_target"
- "bcptThresholds" = [ordered]@{
- "DurationWarning" = 10
- "DurationError" = 25
- "NumberOfSqlStmtsWarning" = 5
- "NumberOfSqlStmtsError" = 10
- }
- "fullBuildPatterns" = @()
- "excludeEnvironments" = @()
- "alDoc" = [ordered]@{
- "continuousDeployment" = $false
- "deployToGitHubPages" = $true
- "maxReleases" = 3
- "groupByProject" = $true
- "includeProjects" = @()
- "excludeProjects" = @()
- "header" = "Documentation for {REPOSITORY} {VERSION}"
- "footer" = "Documentation for {REPOSITORY} made with AL-Go for GitHub, ALDoc and DocFx"
- "defaultIndexMD" = "## Reference documentation\n\nThis is the generated reference documentation for [{REPOSITORY}](https://github.com/{REPOSITORY}).\n\nYou can use the navigation bar at the top and the table of contents to the left to navigate your documentation.\n\nYou can change this content by creating/editing the **{INDEXTEMPLATERELATIVEPATH}** file in your repository or use the alDoc:defaultIndexMD setting in your repository settings file (.github/AL-Go-Settings.json)\n\n{RELEASENOTES}"
- "defaultReleaseMD" = "## Release reference documentation\n\nThis is the generated reference documentation for [{REPOSITORY}](https://github.com/{REPOSITORY}).\n\nYou can use the navigation bar at the top and the table of contents to the left to navigate your documentation.\n\nYou can change this content by creating/editing the **{INDEXTEMPLATERELATIVEPATH}** file in your repository or use the alDoc:defaultReleaseMD setting in your repository settings file (.github/AL-Go-Settings.json)\n\n{RELEASENOTES}"
- }
- "trustMicrosoftNuGetFeeds" = $true
- "nuGetFeedSelectMode" = "LatestMatching"
- "commitOptions" = [ordered]@{
- "messageSuffix" = ""
- "pullRequestAutoMerge" = $false
- "pullRequestLabels" = @()
- "createPullRequest" = $true
- }
- "trustedSigning" = [ordered]@{
- "Endpoint" = ""
- "Account" = ""
- "CertificateProfile" = ""
- }
- "useGitSubmodules" = "false"
- "gitSubmodulesTokenSecretName" = "gitSubmodulesToken"
- "shortLivedArtifactsRetentionDays" = 1 # 0 means use GitHub default
- }
-}
-
-# Read settings from the settings files
-# Settings are read from the following files:
-# - ALGoOrgSettings (github Variable) = Organization settings variable
-# - .github/AL-Go-TemplateRepoSettings.doNotEdit.json = Repository settings from custom template
-# - .github/AL-Go-Settings.json = Repository Settings file
-# - ALGoRepoSettings (github Variable) = Repository settings variable
-# - .github/AL-Go-TemplateProjectSettings.doNotEdit.json = Project settings from custom template
-# - /.AL-Go/settings.json = Project settings file
-# - .github/.settings.json = Workflow settings file
-# - /.AL-Go/.settings.json = Project workflow settings file
-# - /.AL-Go/.settings.json = User settings file
-function ReadSettings {
- Param(
- [string] $baseFolder = "$ENV:GITHUB_WORKSPACE",
- [string] $repoName = "$ENV:GITHUB_REPOSITORY",
- [string] $project = '.',
- [string] $buildMode = "Default",
- [string] $workflowName = "$ENV:GITHUB_WORKFLOW",
- [string] $userName = "$ENV:GITHUB_ACTOR",
- [string] $branchName = "$ENV:GITHUB_REF_NAME",
- [string] $orgSettingsVariableValue = "$ENV:ALGoOrgSettings",
- [string] $repoSettingsVariableValue = "$ENV:ALGoRepoSettings",
- [switch] $silent
- )
-
- # If the build is triggered by a pull request the refname will be the merge branch. To apply conditional settings we need to use the base branch
- if (($env:GITHUB_EVENT_NAME -eq "pull_request") -and ($branchName -eq $ENV:GITHUB_REF_NAME)) {
- $branchName = $env:GITHUB_BASE_REF
- }
-
- function GetSettingsObject {
- Param(
- [string] $path
- )
-
- if (Test-Path $path) {
- try {
- if (!$silent.IsPresent) { Write-Host "Applying settings from $path" }
- $settings = Get-Content $path -Encoding UTF8 | ConvertFrom-Json
- if ($settings) {
- return $settings
- }
- }
- catch {
- throw "Error reading $path. Error was $($_.Exception.Message).`n$($_.ScriptStackTrace)"
- }
- }
- else {
- if (!$silent.IsPresent) { Write-Host "No settings found in $path" }
- }
- return $null
- }
-
- $repoName = $repoName.SubString("$repoName".LastIndexOf('/') + 1)
- $githubFolder = Join-Path $baseFolder ".github"
- $workflowName = $workflowName.Trim().Split([System.IO.Path]::getInvalidFileNameChars()) -join ""
-
- # Start with default settings
- $settings = GetDefaultSettings -repoName $repoName
-
- # Read settings from files and merge them into the settings object
-
- $settingsObjects = @()
- # Read settings from organization settings variable (parameter)
- if ($orgSettingsVariableValue) {
- $orgSettingsVariableObject = $orgSettingsVariableValue | ConvertFrom-Json
- $settingsObjects += @($orgSettingsVariableObject)
- }
-
- # Read settings from repository settings file
- $customTemplateRepoSettingsObject = GetSettingsObject -Path (Join-Path $baseFolder $CustomTemplateRepoSettingsFile)
- $settingsObjects += @($customTemplateRepoSettingsObject)
-
- # Read settings from repository settings file
- $repoSettingsObject = GetSettingsObject -Path (Join-Path $baseFolder $RepoSettingsFile)
- $settingsObjects += @($repoSettingsObject)
-
- # Read settings from repository settings variable (parameter)
- if ($repoSettingsVariableValue) {
- $repoSettingsVariableObject = $repoSettingsVariableValue | ConvertFrom-Json
- $settingsObjects += @($repoSettingsVariableObject)
- }
-
- if ($project) {
- # Read settings from repository settings file
- $customTemplateProjectSettingsObject = GetSettingsObject -Path (Join-Path $baseFolder $CustomTemplateProjectSettingsFile)
- $settingsObjects += @($customTemplateProjectSettingsObject)
- # Read settings from project settings file
- $projectFolder = Join-Path $baseFolder $project -Resolve
- $projectSettingsObject = GetSettingsObject -Path (Join-Path $projectFolder $ALGoSettingsFile)
- $settingsObjects += @($projectSettingsObject)
- }
-
- if ($workflowName) {
- # Read settings from workflow settings file
- $workflowSettingsObject = GetSettingsObject -Path (Join-Path $gitHubFolder "$workflowName.settings.json")
- $settingsObjects += @($workflowSettingsObject)
- if ($project) {
- # Read settings from project workflow settings file
- $projectWorkflowSettingsObject = GetSettingsObject -Path (Join-Path $projectFolder "$ALGoFolderName/$workflowName.settings.json")
- # Read settings from user settings file
- $userSettingsObject = GetSettingsObject -Path (Join-Path $projectFolder "$ALGoFolderName/$userName.settings.json")
- $settingsObjects += @($projectWorkflowSettingsObject, $userSettingsObject)
- }
- }
-
- foreach($settingsJson in $settingsObjects) {
- if ($settingsJson) {
- MergeCustomObjectIntoOrderedDictionary -dst $settings -src $settingsJson
- if ($settingsJson.PSObject.Properties.Name -eq "ConditionalSettings") {
- foreach($conditionalSetting in $settingsJson.ConditionalSettings) {
- if ("$conditionalSetting" -ne "") {
- $conditionMet = $true
- $conditions = @()
- @{"buildModes" = $buildMode; "branches" = $branchName; "repositories" = $repoName; "projects" = $project; "workflows" = $workflowName; "users" = $userName}.GetEnumerator() | ForEach-Object {
- $propName = $_.Key
- $propValue = $_.Value
- if ($conditionMet -and $conditionalSetting.PSObject.Properties.Name -eq $propName) {
- $conditionMet = $propValue -and $conditionMet -and ($conditionalSetting."$propName" | Where-Object { $propValue -like $_ })
- $conditions += @("$($propName): $propValue")
- }
- }
- if ($conditionMet) {
- if (!$silent.IsPresent) { Write-Host "Applying conditional settings for $($conditions -join ", ")" }
- MergeCustomObjectIntoOrderedDictionary -dst $settings -src $conditionalSetting.settings
- }
- }
- }
- }
- }
- }
-
- # runs-on is used for all jobs except for the build job (basically all jobs which doesn't need a container)
- # gitHubRunner is used for the build job (or basically all jobs that needs a container)
- #
- # shell defaults to "powershell" unless runs-on is Ubuntu (Linux), then it defaults to pwsh
- #
- # gitHubRunner defaults to "runs-on", unless runs-on is Ubuntu (Linux) as this won't work.
- # gitHubRunnerShell defaults to "shell"
- #
- # The exception for keeping gitHubRunner to Windows-Latest (when set to Ubuntu-*) will be removed when all jobs supports Ubuntu (Linux)
- # At some point in the future (likely version 3.0), we will switch to Ubuntu (Linux) as default for "runs-on"
- #
- if ($settings.shell -eq "") {
- if ($settings."runs-on" -like "*ubuntu-*") {
- $settings.shell = "pwsh"
- }
- else {
- $settings.shell = "powershell"
- }
- }
- if ($settings.githubRunner -eq "") {
- if ($settings."runs-on" -like "*ubuntu-*") {
- $settings.githubRunner = "windows-latest"
- }
- else {
- $settings.githubRunner = $settings."runs-on"
- }
- }
- if ($settings.githubRunnerShell -eq "") {
- $settings.githubRunnerShell = $settings.shell
- }
-
- # Check that gitHubRunnerShell and Shell is valid
- if ($settings.githubRunnerShell -ne "powershell" -and $settings.githubRunnerShell -ne "pwsh") {
- throw "Invalid value for setting: gitHubRunnerShell: $($settings.githubRunnerShell)"
- }
- if ($settings.shell -ne "powershell" -and $settings.shell -ne "pwsh") {
- throw "Invalid value for setting: shell: $($settings.githubRunnerShell)"
- }
-
- if (($settings.githubRunner -like "*ubuntu-*") -and ($settings.githubRunnerShell -eq "powershell")) {
- if (!$silent.IsPresent) { Write-Host "Switching shell to pwsh for ubuntu" }
- $settings.githubRunnerShell = "pwsh"
- }
-
- if($settings.projectName -eq '') {
- $settings.projectName = $project # Default to project path as project name
- }
-
- $settings | ValidateSettings
-
- $settings
-}
-
-<#
- .SYNOPSIS
- Validate the settings against the settings schema file.
- .PARAMETER settings
- The settings to validate.
-#>
-function ValidateSettings {
- Param(
- [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
- $settings
- )
- Process {
- $settingsJson = ConvertTo-Json -InputObject $settings -Depth 99 -Compress
- $settingsSchemaFile = Join-Path $PSScriptRoot "settings.schema.json" -Resolve
-
- $result = ""
- try{
- $command = [scriptblock] {
- $result = ''
- Test-Json -Json $args[0] -SchemaFile $args[1] -ErrorVariable result -ErrorAction SilentlyContinue | Out-Null
- return $result
- }
-
- if($PSVersionTable.PSVersion.Major -lt 6) { # Test-Json is not available in PS5.1
- $result = pwsh -noprofile -Command $command -args $settingsJson, $settingsSchemaFile
- }
- else {
- $result = Invoke-Command -ScriptBlock $command -ArgumentList $settingsJson, $settingsSchemaFile
- }
- }
- catch {
- OutputWarning "Error validating settings. Error: $($_.Exception.Message)"
- }
- if ($result) {
- OutputWarning "Settings are not valid. Error: $result"
- }
- }
-}
-
function ExcludeUnneededApps {
Param(
[string[]] $folders,
diff --git a/Templates/AppSource App/.AL-Go/cloudDevEnv.ps1 b/Templates/AppSource App/.AL-Go/cloudDevEnv.ps1
index 39e13e4ea..a07cdb19a 100644
--- a/Templates/AppSource App/.AL-Go/cloudDevEnv.ps1
+++ b/Templates/AppSource App/.AL-Go/cloudDevEnv.ps1
@@ -52,11 +52,13 @@ Write-Host -ForegroundColor Yellow @'
$tmpFolder = Join-Path ([System.IO.Path]::GetTempPath()) "$([Guid]::NewGuid().ToString())"
New-Item -Path $tmpFolder -ItemType Directory -Force | Out-Null
$GitHubHelperPath = DownloadHelperFile -url 'https://raw.githubusercontent.com/microsoft/AL-Go-Actions/main/Github-Helper.psm1' -folder $tmpFolder -notifyAuthenticatedAttempt
+$ReadSettingsModule = DownloadHelperFile -url 'https://raw.githubusercontent.com/microsoft/AL-Go-Actions/main/.Modules/ReadSettings.psm1' -folder $tmpFolder
$ALGoHelperPath = DownloadHelperFile -url 'https://raw.githubusercontent.com/microsoft/AL-Go-Actions/main/AL-Go-Helper.ps1' -folder $tmpFolder
DownloadHelperFile -url 'https://raw.githubusercontent.com/microsoft/AL-Go-Actions/main/settings.schema.json' -folder $tmpFolder | Out-Null
DownloadHelperFile -url 'https://raw.githubusercontent.com/microsoft/AL-Go-Actions/main/Packages.json' -folder $tmpFolder | Out-Null
Import-Module $GitHubHelperPath
+Import-Module $ReadSettingsModule
. $ALGoHelperPath -local
$baseFolder = GetBaseFolder -folder $PSScriptRoot
diff --git a/Templates/AppSource App/.AL-Go/localDevEnv.ps1 b/Templates/AppSource App/.AL-Go/localDevEnv.ps1
index aeaaedb73..80622d5d0 100644
--- a/Templates/AppSource App/.AL-Go/localDevEnv.ps1
+++ b/Templates/AppSource App/.AL-Go/localDevEnv.ps1
@@ -56,11 +56,13 @@ Write-Host -ForegroundColor Yellow @'
$tmpFolder = Join-Path ([System.IO.Path]::GetTempPath()) "$([Guid]::NewGuid().ToString())"
New-Item -Path $tmpFolder -ItemType Directory -Force | Out-Null
$GitHubHelperPath = DownloadHelperFile -url 'https://raw.githubusercontent.com/microsoft/AL-Go-Actions/main/Github-Helper.psm1' -folder $tmpFolder -notifyAuthenticatedAttempt
+$ReadSettingsModule = DownloadHelperFile -url 'https://raw.githubusercontent.com/microsoft/AL-Go-Actions/main/.Modules/ReadSettings.psm1' -folder $tmpFolder
$ALGoHelperPath = DownloadHelperFile -url 'https://raw.githubusercontent.com/microsoft/AL-Go-Actions/main/AL-Go-Helper.ps1' -folder $tmpFolder
DownloadHelperFile -url 'https://raw.githubusercontent.com/microsoft/AL-Go-Actions/main/settings.schema.json' -folder $tmpFolder | Out-Null
DownloadHelperFile -url 'https://raw.githubusercontent.com/microsoft/AL-Go-Actions/main/Packages.json' -folder $tmpFolder | Out-Null
Import-Module $GitHubHelperPath
+Import-Module $ReadSettingsModule
. $ALGoHelperPath -local
$baseFolder = GetBaseFolder -folder $PSScriptRoot
diff --git a/Templates/Per Tenant Extension/.AL-Go/cloudDevEnv.ps1 b/Templates/Per Tenant Extension/.AL-Go/cloudDevEnv.ps1
index 39e13e4ea..a07cdb19a 100644
--- a/Templates/Per Tenant Extension/.AL-Go/cloudDevEnv.ps1
+++ b/Templates/Per Tenant Extension/.AL-Go/cloudDevEnv.ps1
@@ -52,11 +52,13 @@ Write-Host -ForegroundColor Yellow @'
$tmpFolder = Join-Path ([System.IO.Path]::GetTempPath()) "$([Guid]::NewGuid().ToString())"
New-Item -Path $tmpFolder -ItemType Directory -Force | Out-Null
$GitHubHelperPath = DownloadHelperFile -url 'https://raw.githubusercontent.com/microsoft/AL-Go-Actions/main/Github-Helper.psm1' -folder $tmpFolder -notifyAuthenticatedAttempt
+$ReadSettingsModule = DownloadHelperFile -url 'https://raw.githubusercontent.com/microsoft/AL-Go-Actions/main/.Modules/ReadSettings.psm1' -folder $tmpFolder
$ALGoHelperPath = DownloadHelperFile -url 'https://raw.githubusercontent.com/microsoft/AL-Go-Actions/main/AL-Go-Helper.ps1' -folder $tmpFolder
DownloadHelperFile -url 'https://raw.githubusercontent.com/microsoft/AL-Go-Actions/main/settings.schema.json' -folder $tmpFolder | Out-Null
DownloadHelperFile -url 'https://raw.githubusercontent.com/microsoft/AL-Go-Actions/main/Packages.json' -folder $tmpFolder | Out-Null
Import-Module $GitHubHelperPath
+Import-Module $ReadSettingsModule
. $ALGoHelperPath -local
$baseFolder = GetBaseFolder -folder $PSScriptRoot
diff --git a/Templates/Per Tenant Extension/.AL-Go/localDevEnv.ps1 b/Templates/Per Tenant Extension/.AL-Go/localDevEnv.ps1
index aeaaedb73..80622d5d0 100644
--- a/Templates/Per Tenant Extension/.AL-Go/localDevEnv.ps1
+++ b/Templates/Per Tenant Extension/.AL-Go/localDevEnv.ps1
@@ -56,11 +56,13 @@ Write-Host -ForegroundColor Yellow @'
$tmpFolder = Join-Path ([System.IO.Path]::GetTempPath()) "$([Guid]::NewGuid().ToString())"
New-Item -Path $tmpFolder -ItemType Directory -Force | Out-Null
$GitHubHelperPath = DownloadHelperFile -url 'https://raw.githubusercontent.com/microsoft/AL-Go-Actions/main/Github-Helper.psm1' -folder $tmpFolder -notifyAuthenticatedAttempt
+$ReadSettingsModule = DownloadHelperFile -url 'https://raw.githubusercontent.com/microsoft/AL-Go-Actions/main/.Modules/ReadSettings.psm1' -folder $tmpFolder
$ALGoHelperPath = DownloadHelperFile -url 'https://raw.githubusercontent.com/microsoft/AL-Go-Actions/main/AL-Go-Helper.ps1' -folder $tmpFolder
DownloadHelperFile -url 'https://raw.githubusercontent.com/microsoft/AL-Go-Actions/main/settings.schema.json' -folder $tmpFolder | Out-Null
DownloadHelperFile -url 'https://raw.githubusercontent.com/microsoft/AL-Go-Actions/main/Packages.json' -folder $tmpFolder | Out-Null
Import-Module $GitHubHelperPath
+Import-Module $ReadSettingsModule
. $ALGoHelperPath -local
$baseFolder = GetBaseFolder -folder $PSScriptRoot
diff --git a/Tests/AL-Go-Helper.Test.ps1 b/Tests/AL-Go-Helper.Test.ps1
index 57c5e114d..18719d85d 100644
--- a/Tests/AL-Go-Helper.Test.ps1
+++ b/Tests/AL-Go-Helper.Test.ps1
@@ -3,82 +3,6 @@
. (Join-Path $PSScriptRoot '../Actions/AL-Go-Helper.ps1')
}
- It 'MergeCustomObjectIntoOrderedDictionary' {
- # This function is used to merge settings files into the settings object
- # dest is the default settings object
- $dest = [ordered]@{
- 'int0' = 0
- 'int1' = 1
- 'int2' = 2
- 'str1' = 'str1'
- 'str2' = 'str2'
- 'arr1' = @('a', 'b', 'c')
- 'arr2' = @('a', 'b', 'c')
- 'obj1' = [ordered]@{
- 'a' = 'a'
- 'b' = 'b'
- 'c' = 'c'
- }
- 'obj2' = [ordered]@{
- 'a' = 'a'
- 'b' = 'b'
- 'c' = 'c'
- }
- 'objarr1' = @([ordered]@{'a' = 'a'; 'b' = 'b'; 'c' = 'c'}, [ordered]@{'d' = 'd'; 'e' = 'e'; 'f' = 'f'})
- 'objarr2' = @([ordered]@{'a' = 'a'; 'b' = 'b'; 'c' = 'c'}, [ordered]@{'d' = 'd'; 'e' = 'e'; 'f' = 'f'})
- }
-
- $dest.Count | Should -Be 11
-
- # source is the settings read from a file
- $src = @{
- 'int1' = [Int64]::MaxValue
- 'int2' = 3
- 'int3' = 4
- 'objarr2' = @([ordered]@{'g' = 'g'; 'h' = 'h'; 'i' = 'i'}, [ordered]@{'d' = 'd'; 'e' = 'e'; 'f' = 'f'})
- 'objarr3' = @([ordered]@{'g' = 'g'; 'h' = 'h'; 'i' = 'i'}, [ordered]@{'j' = 'j'; 'k' = 'k'; 'l' = 'l'})
- } | ConvertTo-Json | ConvertFrom-Json
- $src.int2 = [Int32]3
- $src.int3 = [Int32]4
-
- # Merge the settings
- MergeCustomObjectIntoOrderedDictionary -dst $dest -src $src
- $dest.Count | Should -Be 13
- $dest['int0'] | Should -Be 0
- $dest['int1'] | Should -Be ([Int64]::MaxValue)
- $dest['int2'] | Should -Be 3
- $dest['int3'] | Should -Be 4
- $dest['objarr2'] | ConvertTo-Json | Should -Be (@([ordered]@{'a' = 'a'; 'b' = 'b'; 'c' = 'c'}, [ordered]@{'d' = 'd'; 'e' = 'e'; 'f' = 'f'}, [ordered]@{'g' = 'g'; 'h' = 'h'; 'i' = 'i'}, [ordered]@{'d' = 'd'; 'e' = 'e'; 'f' = 'f'}) | ConvertTo-Json)
- $dest['objarr3'] | ConvertTo-Json | Should -Be (@([ordered]@{'g' = 'g'; 'h' = 'h'; 'i' = 'i'}, [ordered]@{'j' = 'j'; 'k' = 'k'; 'l' = 'l'}) | ConvertTo-Json)
-
- # source is the settings read from a file
- # Check that multiple settings files are merged correctly one after the other
- $src = @{
- 'str2' = 'str3'
- 'str3' = 'str4'
- 'arr2' = @('c', 'd', 'e')
- 'arr3' = @('c', 'd', 'e')
- 'obj2' = [ordered]@{'c' = 'c'; 'd' = 'd'; 'e' = 'e'}
- 'obj3' = [ordered]@{'d' = 'd'; 'e' = 'e'; 'f' = 'f'}
- } | ConvertTo-Json | ConvertFrom-Json
-
- # Check that applying the same settings twice doesn't change the result
- 1..2 | ForEach-Object {
- MergeCustomObjectIntoOrderedDictionary -dst $dest -src $src
- $dest.Count | Should -Be 16
- $dest['int0'] | Should -Be 0
- $dest['int1'] | Should -Be ([Int64]::MaxValue)
- $dest['int2'] | Should -Be 3
- $dest['int3'] | Should -Be 4
- $dest['str2'] | Should -Be 'str3'
- $dest['str3'] | Should -Be 'str4'
- $dest['arr2'] | Should -Be @('a', 'b', 'c', 'd', 'e')
- $dest['arr3'] | Should -Be @('c', 'd', 'e')
- $dest['obj2'] | ConvertTo-Json | Should -Be ([ordered]@{'a' = 'a'; 'b' = 'b'; 'c' = 'c'; 'd' = 'd'; 'e' = 'e'} | ConvertTo-Json)
- $dest['obj3'] | ConvertTo-Json | Should -Be ([ordered]@{'d' = 'd'; 'e' = 'e'; 'f' = 'f'} | ConvertTo-Json)
- }
- }
-
It 'CheckAndCreateProjectFolder' {
Mock Write-Host { }
@@ -190,270 +114,3 @@
)
}
}
-
-
-Describe "ReadSettings" {
- BeforeAll {
- . (Join-Path $PSScriptRoot '../Actions/AL-Go-Helper.ps1')
- [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'scriptPath', Justification = 'False positive.')]
- $schema = Get-Content -Path (Join-Path $PSScriptRoot '../Actions/settings.schema.json') -Raw
- }
-
- It 'Reads settings from all settings locations' {
- Mock Write-Host { }
- Mock Out-Host { }
-
- Push-Location
- $tempName = Join-Path ([System.IO.Path]::GetTempPath()) ([Guid]::NewGuid().ToString())
- $githubFolder = Join-Path $tempName ".github"
- $ALGoFolder = Join-Path $tempName $ALGoFolderName
- $projectALGoFolder = Join-Path $tempName "Project/$ALGoFolderName"
-
- New-Item $githubFolder -ItemType Directory | Out-Null
- New-Item $ALGoFolder -ItemType Directory | Out-Null
- New-Item $projectALGoFolder -ItemType Directory | Out-Null
-
- New-Item -Path (Join-Path $tempName "projectx/$ALGoFolderName") -ItemType Directory | Out-Null
- New-Item -Path (Join-Path $tempName "projecty/$ALGoFolderName") -ItemType Directory | Out-Null
-
- # Create settings files
- # Property: Repo: Project (single): Project (multi): Workflow: Workflow: User:
- # if(branch=dev):
- # Property1 repo1 single1 multi1 branch1 user1
- # Property2 repo2 workflow2
- # Property3 repo3
- # Arr1 @("repo1","repo2")
- # Property4 single4 branch4
- # property5 multi5
- # property6 user6
- @{ "property1" = "repo1"; "property2" = "repo2"; "property3" = "repo3"; "arr1" = @("repo1","repo2") } | ConvertTo-Json -Depth 99 |
- Set-Content -Path (Join-Path $githubFolder "AL-Go-Settings.json") -encoding utf8 -Force
- @{ "property1" = "single1"; "property4" = "single4" } | ConvertTo-Json -Depth 99 |
- Set-Content -Path (Join-Path $ALGoFolder "settings.json") -encoding utf8 -Force
- @{ "property1" = "multi1"; "property5" = "multi5" } | ConvertTo-Json -Depth 99 |
- Set-Content -Path (Join-Path $projectALGoFolder "settings.json") -encoding utf8 -Force
- @{ "property2" = "workflow2"; "conditionalSettings" = @( @{ "branches" = @( 'dev' ); "settings" = @{ "property1" = "branch1"; "property4" = "branch4" } } ) } | ConvertTo-Json -Depth 99 |
- Set-Content -Path (Join-Path $githubFolder "Workflow.settings.json") -encoding utf8 -Force
- @{ "property1" = "user1"; "property6" = "user6" } | ConvertTo-Json -Depth 99 |
- Set-Content -Path (Join-Path $projectALGoFolder "user.settings.json") -encoding utf8 -Force
-
- # No settings variables
- $ENV:ALGoOrgSettings = ''
- $ENV:ALGoRepoSettings = ''
-
- # Repo only
- $repoSettings = ReadSettings -baseFolder $tempName -project '' -repoName 'repo' -workflowName '' -branchName '' -userName ''
- $repoSettings.property1 | Should -Be 'repo1'
- $repoSettings.property2 | Should -Be 'repo2'
- $repoSettings.property3 | Should -Be 'repo3'
-
- # Repo + single project
- $singleProjectSettings = ReadSettings -baseFolder $tempName -project '.' -repoName 'repo' -workflowName '' -branchName '' -userName ''
- $singleProjectSettings.property1 | Should -Be 'single1'
- $singleProjectSettings.property2 | Should -Be 'repo2'
- $singleProjectSettings.property4 | Should -Be 'single4'
-
- # Repo + multi project
- $multiProjectSettings = ReadSettings -baseFolder $tempName -project 'Project' -repoName 'repo' -workflowName '' -branchName '' -userName ''
- $multiProjectSettings.property1 | Should -Be 'multi1'
- $multiProjectSettings.property2 | Should -Be 'repo2'
- $multiProjectSettings.property5 | Should -Be 'multi5'
-
- # Repo + workflow
- $workflowRepoSettings = ReadSettings -baseFolder $tempName -project '' -repoName 'repo' -workflowName 'Workflow' -branchName '' -userName ''
- $workflowRepoSettings.property1 | Should -Be 'repo1'
- $workflowRepoSettings.property2 | Should -Be 'workflow2'
-
- # Repo + single project + workflow
- $workflowSingleSettings = ReadSettings -baseFolder $tempName -project '.' -repoName 'repo' -workflowName 'Workflow' -branchName '' -userName ''
- $workflowSingleSettings.property1 | Should -Be 'single1'
- $workflowSingleSettings.property2 | Should -Be 'workflow2'
- $workflowSingleSettings.property4 | Should -Be 'single4'
- $workflowSingleSettings.property3 | Should -Be 'repo3'
-
- # Repo + multi project + workflow + dev branch
- $workflowMultiSettings = ReadSettings -baseFolder $tempName -project 'Project' -repoName 'repo' -workflowName 'Workflow' -branchName 'dev' -userName ''
- $workflowMultiSettings.property1 | Should -Be 'branch1'
- $workflowMultiSettings.property2 | Should -Be 'workflow2'
- $workflowMultiSettings.property3 | Should -Be 'repo3'
- $workflowMultiSettings.property4 | Should -Be 'branch4'
- $workflowMultiSettings.property5 | Should -Be 'multi5'
- { $workflowMultiSettings.property6 } | Should -Throw
-
- # Repo + multi project + workflow + dev branch + user
- $userWorkflowMultiSettings = ReadSettings -baseFolder $tempName -project 'Project' -repoName 'repo' -workflowName 'Workflow' -branchName 'dev' -userName 'user'
- $userWorkflowMultiSettings.property1 | Should -Be 'user1'
- $userWorkflowMultiSettings.property2 | Should -Be 'workflow2'
- $userWorkflowMultiSettings.property3 | Should -Be 'repo3'
- $userWorkflowMultiSettings.property4 | Should -Be 'branch4'
- $userWorkflowMultiSettings.property5 | Should -Be 'multi5'
- $userWorkflowMultiSettings.property6 | Should -Be 'user6'
-
- # Org settings variable
- # property 2 = orgsetting2
- # property 7 = orgsetting7
- # arr1 = @(org3) - gets merged
- $ENV:ALGoOrgSettings = @{ "property2" = "orgsetting2"; "property7" = "orgsetting7"; "arr1" = @("org3") } | ConvertTo-Json -Depth 99
-
- # Org(var) + Repo + multi project + workflow + dev branch + user
- $withOrgSettings = ReadSettings -baseFolder $tempName -project 'Project' -repoName 'repo' -workflowName 'Workflow' -branchName 'dev' -userName 'user'
- $withOrgSettings.property1 | Should -Be 'user1'
- $withOrgSettings.property2 | Should -Be 'workflow2'
- $withOrgSettings.property3 | Should -Be 'repo3'
- $withOrgSettings.property4 | Should -Be 'branch4'
- $withOrgSettings.property5 | Should -Be 'multi5'
- $withOrgSettings.property6 | Should -Be 'user6'
- $withOrgSettings.property7 | Should -Be 'orgsetting7'
- $withOrgSettings.arr1 | Should -Be @("org3","repo1","repo2")
-
- # Repo settings variable
- # property3 = reposetting3
- # property8 = reposetting8
- $ENV:ALGoRepoSettings = @{ "property3" = "reposetting3"; "property8" = "reposetting8" } | ConvertTo-Json -Depth 99
-
- # Org(var) + Repo + Repo(var) + multi project + workflow + dev branch + user
- $withRepoSettings = ReadSettings -baseFolder $tempName -project 'Project' -repoName 'repo' -workflowName 'Workflow' -branchName 'dev' -userName 'user'
- $withRepoSettings.property1 | Should -Be 'user1'
- $withRepoSettings.property2 | Should -Be 'workflow2'
- $withRepoSettings.property3 | Should -Be 'reposetting3'
- $withRepoSettings.property4 | Should -Be 'branch4'
- $withRepoSettings.property5 | Should -Be 'multi5'
- $withRepoSettings.property6 | Should -Be 'user6'
- $withRepoSettings.property7 | Should -Be 'orgsetting7'
- $withRepoSettings.property8 | Should -Be 'reposetting8'
-
- # Add conditional settings as repo(var) settings
- $conditionalSettings = [ordered]@{
- "conditionalSettings" = @(
- @{
- "branches" = @( 'branchx', 'branchy' )
- "settings" = @{ "property3" = "branchxy"; "property4" = "branchxy" }
- }
- @{
- "repositories" = @( 'repox', 'repoy' )
- "settings" = @{ "property3" = "repoxy"; "property4" = "repoxy" }
- }
- @{
- "projects" = @( 'projectx', 'projecty' )
- "settings" = @{ "property3" = "projectxy"; "property4" = "projectxy" }
- }
- @{
- "workflows" = @( 'workflowx', 'workflowy' )
- "settings" = @{ "property3" = "workflowxy"; "property4" = "workflowxy" }
- }
- @{
- "users" = @( 'userx', 'usery' )
- "settings" = @{ "property3" = "userxy"; "property4" = "userxy" }
- }
- @{
- "branches" = @( 'branchx', 'branchy' )
- "projects" = @( 'projectx','projecty' )
- "settings" = @{ "property3" = "bpxy"; "property4" = "bpxy" }
- }
- )
- }
- $ENV:ALGoRepoSettings = $conditionalSettings | ConvertTo-Json -Depth 99
-
- # Test that conditional settings are applied correctly
- $conditionalSettings = ReadSettings -baseFolder $tempName -project 'Project' -repoName 'repo' -workflowName 'Workflow' -branchName 'branchy' -userName 'user'
- $conditionalSettings.property3 | Should -Be 'branchxy'
- $conditionalSettings.property4 | Should -Be 'branchxy'
-
- $conditionalSettings = ReadSettings -baseFolder $tempName -project 'Project' -repoName 'repox' -workflowName 'Workflow' -branchName 'dev' -userName 'user'
- $conditionalSettings.property3 | Should -Be 'repoxy'
- $conditionalSettings.property4 | Should -Be 'branch4'
-
- $conditionalSettings = ReadSettings -baseFolder $tempName -project 'projectx' -repoName 'repo' -workflowName 'Workflow' -branchName 'branch' -userName 'user'
- $conditionalSettings.property3 | Should -Be 'projectxy'
- $conditionalSettings.property4 | Should -Be 'projectxy'
-
- $conditionalSettings = ReadSettings -baseFolder $tempName -project 'projectx' -repoName 'repo' -workflowName 'Workflowx' -branchName 'branch' -userName 'user'
- $conditionalSettings.property3 | Should -Be 'workflowxy'
- $conditionalSettings.property4 | Should -Be 'workflowxy'
-
- $conditionalSettings = ReadSettings -baseFolder $tempName -project 'Project' -repoName 'repo' -workflowName 'Workflow' -branchName 'branch' -userName 'usery'
- $conditionalSettings.property3 | Should -Be 'userxy'
- $conditionalSettings.property4 | Should -Be 'userxy'
-
- $conditionalSettings = ReadSettings -baseFolder $tempName -project 'projecty' -repoName 'repo' -workflowName 'Workflow' -branchName 'branchx' -userName 'user'
- $conditionalSettings.property3 | Should -Be 'bpxy'
- $conditionalSettings.property4 | Should -Be 'bpxy'
-
- # Invalid Org(var) setting should throw
- $ENV:ALGoOrgSettings = 'this is not json'
- { ReadSettings -baseFolder $tempName -project 'Project' } | Should -Throw
-
- $ENV:ALGoOrgSettings = ''
- $ENV:ALGoRepoSettings = ''
-
- # Clean up
- Pop-Location
- Remove-Item -Path $tempName -Recurse -Force
- }
-
- It 'Settings schema is valid' {
- Test-Json -json $schema | Should -Be $true
- }
-
- It 'All default settings are in the schema' {
- $defaultSettings = GetDefaultSettings
-
- $schemaObj = $schema | ConvertFrom-Json
-
- $defaultSettings.Keys | ForEach-Object {
- $property = $_
- $schemaObj.properties.PSObject.Properties.Name | Should -Contain $property
- }
- }
-
- It 'Default settings match schema' {
- $defaultSettings = GetDefaultSettings
- Test-Json -json (ConvertTo-Json $defaultSettings) -schema $schema | Should -Be $true
- }
-
- It 'Shell setting can only be pwsh or powershell' {
- $defaultSettings = GetDefaultSettings
- $defaultSettings.shell = 42
- try {
- Test-Json -json (ConvertTo-Json $defaultSettings) -schema $schema
- }
- catch {
- $_.Exception.Message | Should -Be "The JSON is not valid with the schema: Value is `"integer`" but should be `"string`" at '/shell'"
- }
-
- $defaultSettings.shell = "random"
- try {
- Test-Json -json (ConvertTo-Json $defaultSettings) -schema $schema
- }
- catch {
- $_.Exception.Message | Should -Be "The JSON is not valid with the schema: The string value is not a match for the indicated regular expression at '/shell'"
- }
- }
-
- It 'Projects setting is an array of strings' {
- # If the projects setting is not an array, it should throw an error
- $defaultSettings = GetDefaultSettings
- $defaultSettings.projects = "not an array"
- try {
- Test-Json -json (ConvertTo-Json $defaultSettings) -schema $schema
- }
- catch {
- $_.Exception.Message | Should -Be "The JSON is not valid with the schema: Value is `"string`" but should be `"array`" at '/projects'"
- }
-
- # If the projects setting is an array, but contains non-string values, it should throw an error
- $defaultSettings.projects = @("project1", 42)
- try {
- Test-Json -json (ConvertTo-Json $defaultSettings) -schema $schema
- }
- catch {
- $_.Exception.Message | Should -Be "The JSON is not valid with the schema: Value is `"integer`" but should be `"string`" at '/projects/1'"
- }
-
- # If the projects setting is an array of strings, it should pass the schema validation
- $defaultSettings.projects = @("project1")
- Test-Json -json (ConvertTo-Json $defaultSettings) -schema $schema | Should -Be $true
- $defaultSettings.projects = @("project1", "project2")
- Test-Json -json (ConvertTo-Json $defaultSettings) -schema $schema | Should -Be $true
- }
-}
diff --git a/Tests/ReadSettings.Test.ps1 b/Tests/ReadSettings.Test.ps1
new file mode 100644
index 000000000..1bcfe058f
--- /dev/null
+++ b/Tests/ReadSettings.Test.ps1
@@ -0,0 +1,268 @@
+Import-Module (Join-Path $PSScriptRoot '../Actions/.Modules/ReadSettings.psm1')
+
+InModuleScope ReadSettings { # Allows testing of private functions
+ Describe "ReadSettings" {
+ BeforeAll {
+ [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'scriptPath', Justification = 'False positive.')]
+ $schema = Get-Content -Path (Join-Path $PSScriptRoot '../Actions/.Modules/settings.schema.json') -Raw
+ }
+
+ It 'Reads settings from all settings locations' {
+ Mock Write-Host { }
+ Mock Out-Host { }
+
+ Push-Location
+ $tempName = Join-Path ([System.IO.Path]::GetTempPath()) ([Guid]::NewGuid().ToString())
+ $githubFolder = Join-Path $tempName ".github"
+ $ALGoFolder = Join-Path $tempName $ALGoFolderName
+ $projectALGoFolder = Join-Path $tempName "Project/$ALGoFolderName"
+
+ New-Item $githubFolder -ItemType Directory | Out-Null
+ New-Item $ALGoFolder -ItemType Directory | Out-Null
+ New-Item $projectALGoFolder -ItemType Directory | Out-Null
+
+ New-Item -Path (Join-Path $tempName "projectx/$ALGoFolderName") -ItemType Directory | Out-Null
+ New-Item -Path (Join-Path $tempName "projecty/$ALGoFolderName") -ItemType Directory | Out-Null
+
+ # Create settings files
+ # Property: Repo: Project (single): Project (multi): Workflow: Workflow: User:
+ # if(branch=dev):
+ # Property1 repo1 single1 multi1 branch1 user1
+ # Property2 repo2 workflow2
+ # Property3 repo3
+ # Arr1 @("repo1","repo2")
+ # Property4 single4 branch4
+ # property5 multi5
+ # property6 user6
+ @{ "property1" = "repo1"; "property2" = "repo2"; "property3" = "repo3"; "arr1" = @("repo1", "repo2") } | ConvertTo-Json -Depth 99 |
+ Set-Content -Path (Join-Path $githubFolder "AL-Go-Settings.json") -encoding utf8 -Force
+ @{ "property1" = "single1"; "property4" = "single4" } | ConvertTo-Json -Depth 99 |
+ Set-Content -Path (Join-Path $ALGoFolder "settings.json") -encoding utf8 -Force
+ @{ "property1" = "multi1"; "property5" = "multi5" } | ConvertTo-Json -Depth 99 |
+ Set-Content -Path (Join-Path $projectALGoFolder "settings.json") -encoding utf8 -Force
+ @{ "property2" = "workflow2"; "conditionalSettings" = @( @{ "branches" = @( 'dev' ); "settings" = @{ "property1" = "branch1"; "property4" = "branch4" } } ) } | ConvertTo-Json -Depth 99 |
+ Set-Content -Path (Join-Path $githubFolder "Workflow.settings.json") -encoding utf8 -Force
+ @{ "property1" = "user1"; "property6" = "user6" } | ConvertTo-Json -Depth 99 |
+ Set-Content -Path (Join-Path $projectALGoFolder "user.settings.json") -encoding utf8 -Force
+
+ # No settings variables
+ $ENV:ALGoOrgSettings = ''
+ $ENV:ALGoRepoSettings = ''
+
+ # Repo only
+ $repoSettings = ReadSettings -baseFolder $tempName -project '' -repoName 'repo' -workflowName '' -branchName '' -userName ''
+ $repoSettings.property1 | Should -Be 'repo1'
+ $repoSettings.property2 | Should -Be 'repo2'
+ $repoSettings.property3 | Should -Be 'repo3'
+
+ # Repo + single project
+ $singleProjectSettings = ReadSettings -baseFolder $tempName -project '.' -repoName 'repo' -workflowName '' -branchName '' -userName ''
+ $singleProjectSettings.property1 | Should -Be 'single1'
+ $singleProjectSettings.property2 | Should -Be 'repo2'
+ $singleProjectSettings.property4 | Should -Be 'single4'
+
+ # Repo + multi project
+ $multiProjectSettings = ReadSettings -baseFolder $tempName -project 'Project' -repoName 'repo' -workflowName '' -branchName '' -userName ''
+ $multiProjectSettings.property1 | Should -Be 'multi1'
+ $multiProjectSettings.property2 | Should -Be 'repo2'
+ $multiProjectSettings.property5 | Should -Be 'multi5'
+
+ # Repo + workflow
+ $workflowRepoSettings = ReadSettings -baseFolder $tempName -project '' -repoName 'repo' -workflowName 'Workflow' -branchName '' -userName ''
+ $workflowRepoSettings.property1 | Should -Be 'repo1'
+ $workflowRepoSettings.property2 | Should -Be 'workflow2'
+
+ # Repo + single project + workflow
+ $workflowSingleSettings = ReadSettings -baseFolder $tempName -project '.' -repoName 'repo' -workflowName 'Workflow' -branchName '' -userName ''
+ $workflowSingleSettings.property1 | Should -Be 'single1'
+ $workflowSingleSettings.property2 | Should -Be 'workflow2'
+ $workflowSingleSettings.property4 | Should -Be 'single4'
+ $workflowSingleSettings.property3 | Should -Be 'repo3'
+
+ # Repo + multi project + workflow + dev branch
+ $workflowMultiSettings = ReadSettings -baseFolder $tempName -project 'Project' -repoName 'repo' -workflowName 'Workflow' -branchName 'dev' -userName ''
+ $workflowMultiSettings.property1 | Should -Be 'branch1'
+ $workflowMultiSettings.property2 | Should -Be 'workflow2'
+ $workflowMultiSettings.property3 | Should -Be 'repo3'
+ $workflowMultiSettings.property4 | Should -Be 'branch4'
+ $workflowMultiSettings.property5 | Should -Be 'multi5'
+ $workflowMultiSettings.property6 | Should -BeNullOrEmpty
+
+ # Repo + multi project + workflow + dev branch + user
+ $userWorkflowMultiSettings = ReadSettings -baseFolder $tempName -project 'Project' -repoName 'repo' -workflowName 'Workflow' -branchName 'dev' -userName 'user'
+ $userWorkflowMultiSettings.property1 | Should -Be 'user1'
+ $userWorkflowMultiSettings.property2 | Should -Be 'workflow2'
+ $userWorkflowMultiSettings.property3 | Should -Be 'repo3'
+ $userWorkflowMultiSettings.property4 | Should -Be 'branch4'
+ $userWorkflowMultiSettings.property5 | Should -Be 'multi5'
+ $userWorkflowMultiSettings.property6 | Should -Be 'user6'
+
+ # Org settings variable
+ # property 2 = orgsetting2
+ # property 7 = orgsetting7
+ # arr1 = @(org3) - gets merged
+ $ENV:ALGoOrgSettings = @{ "property2" = "orgsetting2"; "property7" = "orgsetting7"; "arr1" = @("org3") } | ConvertTo-Json -Depth 99
+
+ # Org(var) + Repo + multi project + workflow + dev branch + user
+ $withOrgSettings = ReadSettings -baseFolder $tempName -project 'Project' -repoName 'repo' -workflowName 'Workflow' -branchName 'dev' -userName 'user'
+ $withOrgSettings.property1 | Should -Be 'user1'
+ $withOrgSettings.property2 | Should -Be 'workflow2'
+ $withOrgSettings.property3 | Should -Be 'repo3'
+ $withOrgSettings.property4 | Should -Be 'branch4'
+ $withOrgSettings.property5 | Should -Be 'multi5'
+ $withOrgSettings.property6 | Should -Be 'user6'
+ $withOrgSettings.property7 | Should -Be 'orgsetting7'
+ $withOrgSettings.arr1 | Should -Be @("org3", "repo1", "repo2")
+
+ # Repo settings variable
+ # property3 = reposetting3
+ # property8 = reposetting8
+ $ENV:ALGoRepoSettings = @{ "property3" = "reposetting3"; "property8" = "reposetting8" } | ConvertTo-Json -Depth 99
+
+ # Org(var) + Repo + Repo(var) + multi project + workflow + dev branch + user
+ $withRepoSettings = ReadSettings -baseFolder $tempName -project 'Project' -repoName 'repo' -workflowName 'Workflow' -branchName 'dev' -userName 'user'
+ $withRepoSettings.property1 | Should -Be 'user1'
+ $withRepoSettings.property2 | Should -Be 'workflow2'
+ $withRepoSettings.property3 | Should -Be 'reposetting3'
+ $withRepoSettings.property4 | Should -Be 'branch4'
+ $withRepoSettings.property5 | Should -Be 'multi5'
+ $withRepoSettings.property6 | Should -Be 'user6'
+ $withRepoSettings.property7 | Should -Be 'orgsetting7'
+ $withRepoSettings.property8 | Should -Be 'reposetting8'
+
+ # Add conditional settings as repo(var) settings
+ $conditionalSettings = [ordered]@{
+ "conditionalSettings" = @(
+ @{
+ "branches" = @( 'branchx', 'branchy' )
+ "settings" = @{ "property3" = "branchxy"; "property4" = "branchxy" }
+ }
+ @{
+ "repositories" = @( 'repox', 'repoy' )
+ "settings" = @{ "property3" = "repoxy"; "property4" = "repoxy" }
+ }
+ @{
+ "projects" = @( 'projectx', 'projecty' )
+ "settings" = @{ "property3" = "projectxy"; "property4" = "projectxy" }
+ }
+ @{
+ "workflows" = @( 'workflowx', 'workflowy' )
+ "settings" = @{ "property3" = "workflowxy"; "property4" = "workflowxy" }
+ }
+ @{
+ "users" = @( 'userx', 'usery' )
+ "settings" = @{ "property3" = "userxy"; "property4" = "userxy" }
+ }
+ @{
+ "branches" = @( 'branchx', 'branchy' )
+ "projects" = @( 'projectx', 'projecty' )
+ "settings" = @{ "property3" = "bpxy"; "property4" = "bpxy" }
+ }
+ )
+ }
+ $ENV:ALGoRepoSettings = $conditionalSettings | ConvertTo-Json -Depth 99
+
+ # Test that conditional settings are applied correctly
+ $conditionalSettings = ReadSettings -baseFolder $tempName -project 'Project' -repoName 'repo' -workflowName 'Workflow' -branchName 'branchy' -userName 'user'
+ $conditionalSettings.property3 | Should -Be 'branchxy'
+ $conditionalSettings.property4 | Should -Be 'branchxy'
+
+ $conditionalSettings = ReadSettings -baseFolder $tempName -project 'Project' -repoName 'repox' -workflowName 'Workflow' -branchName 'dev' -userName 'user'
+ $conditionalSettings.property3 | Should -Be 'repoxy'
+ $conditionalSettings.property4 | Should -Be 'branch4'
+
+ $conditionalSettings = ReadSettings -baseFolder $tempName -project 'projectx' -repoName 'repo' -workflowName 'Workflow' -branchName 'branch' -userName 'user'
+ $conditionalSettings.property3 | Should -Be 'projectxy'
+ $conditionalSettings.property4 | Should -Be 'projectxy'
+
+ $conditionalSettings = ReadSettings -baseFolder $tempName -project 'projectx' -repoName 'repo' -workflowName 'Workflowx' -branchName 'branch' -userName 'user'
+ $conditionalSettings.property3 | Should -Be 'workflowxy'
+ $conditionalSettings.property4 | Should -Be 'workflowxy'
+
+ $conditionalSettings = ReadSettings -baseFolder $tempName -project 'Project' -repoName 'repo' -workflowName 'Workflow' -branchName 'branch' -userName 'usery'
+ $conditionalSettings.property3 | Should -Be 'userxy'
+ $conditionalSettings.property4 | Should -Be 'userxy'
+
+ $conditionalSettings = ReadSettings -baseFolder $tempName -project 'projecty' -repoName 'repo' -workflowName 'Workflow' -branchName 'branchx' -userName 'user'
+ $conditionalSettings.property3 | Should -Be 'bpxy'
+ $conditionalSettings.property4 | Should -Be 'bpxy'
+
+ # Invalid Org(var) setting should throw
+ $ENV:ALGoOrgSettings = 'this is not json'
+ { ReadSettings -baseFolder $tempName -project 'Project' } | Should -Throw
+
+ $ENV:ALGoOrgSettings = ''
+ $ENV:ALGoRepoSettings = ''
+
+ # Clean up
+ Pop-Location
+ Remove-Item -Path $tempName -Recurse -Force
+ }
+
+ It 'Settings schema is valid' {
+ Test-Json -json $schema | Should -Be $true
+ }
+
+ It 'All default settings are in the schema' {
+ $defaultSettings = GetDefaultSettings
+
+ $schemaObj = $schema | ConvertFrom-Json
+
+ $defaultSettings.Keys | ForEach-Object {
+ $property = $_
+ $schemaObj.properties.PSObject.Properties.Name | Should -Contain $property
+ }
+ }
+
+ It 'Default settings match schema' {
+ $defaultSettings = GetDefaultSettings
+ Test-Json -json (ConvertTo-Json $defaultSettings) -schema $schema | Should -Be $true
+ }
+
+ It 'Shell setting can only be pwsh or powershell' {
+ $defaultSettings = GetDefaultSettings
+ $defaultSettings.shell = 42
+ try {
+ Test-Json -json (ConvertTo-Json $defaultSettings) -schema $schema
+ }
+ catch {
+ $_.Exception.Message | Should -Be "The JSON is not valid with the schema: Value is `"integer`" but should be `"string`" at '/shell'"
+ }
+
+ $defaultSettings.shell = "random"
+ try {
+ Test-Json -json (ConvertTo-Json $defaultSettings) -schema $schema
+ }
+ catch {
+ $_.Exception.Message | Should -Be "The JSON is not valid with the schema: The string value is not a match for the indicated regular expression at '/shell'"
+ }
+ }
+
+ It 'Projects setting is an array of strings' {
+ # If the projects setting is not an array, it should throw an error
+ $defaultSettings = GetDefaultSettings
+ $defaultSettings.projects = "not an array"
+ try {
+ Test-Json -json (ConvertTo-Json $defaultSettings) -schema $schema
+ }
+ catch {
+ $_.Exception.Message | Should -Be "The JSON is not valid with the schema: Value is `"string`" but should be `"array`" at '/projects'"
+ }
+
+ # If the projects setting is an array, but contains non-string values, it should throw an error
+ $defaultSettings.projects = @("project1", 42)
+ try {
+ Test-Json -json (ConvertTo-Json $defaultSettings) -schema $schema
+ }
+ catch {
+ $_.Exception.Message | Should -Be "The JSON is not valid with the schema: Value is `"integer`" but should be `"string`" at '/projects/1'"
+ }
+
+ # If the projects setting is an array of strings, it should pass the schema validation
+ $defaultSettings.projects = @("project1")
+ Test-Json -json (ConvertTo-Json $defaultSettings) -schema $schema | Should -Be $true
+ $defaultSettings.projects = @("project1", "project2")
+ Test-Json -json (ConvertTo-Json $defaultSettings) -schema $schema | Should -Be $true
+ }
+ }
+}