diff --git a/Actions/.Modules/ReadSettings.psm1 b/Actions/.Modules/ReadSettings.psm1 index 46a07e4958..b37ea6d26d 100644 --- a/Actions/.Modules/ReadSettings.psm1 +++ b/Actions/.Modules/ReadSettings.psm1 @@ -219,6 +219,7 @@ function GetDefaultSettings } "fullBuildPatterns" = @() "excludeEnvironments" = @() + "noMatchingEnvironmentsAction" = "ignore" "alDoc" = [ordered]@{ "continuousDeployment" = $false "deployToGitHubPages" = $true diff --git a/Actions/.Modules/settings.schema.json b/Actions/.Modules/settings.schema.json index af08720d34..bd5ac2c8fe 100644 --- a/Actions/.Modules/settings.schema.json +++ b/Actions/.Modules/settings.schema.json @@ -554,6 +554,11 @@ }, "description": "An array of environments to be excluded from the build. See https://aka.ms/ALGoSettings#excludeenvironments" }, + "noMatchingEnvironmentsAction": { + "type": "string", + "pattern": "^(ignore|warning|error)$", + "description": "Specifies what happens when deployment environments are found but all are excluded by branch policies or deployment type filters. Allowed values are ignore, warning and error. See https://aka.ms/ALGoSettings#nomatchingenvironmentsaction" + }, "alDoc": { "type": "object", "properties": { diff --git a/Actions/DetermineDeploymentEnvironments/DetermineDeploymentEnvironments.ps1 b/Actions/DetermineDeploymentEnvironments/DetermineDeploymentEnvironments.ps1 index 6fc16f99ed..eebd33d7ba 100644 --- a/Actions/DetermineDeploymentEnvironments/DetermineDeploymentEnvironments.ps1 +++ b/Actions/DetermineDeploymentEnvironments/DetermineDeploymentEnvironments.ps1 @@ -270,7 +270,15 @@ else { } } if (!$includeEnvironment) { - Write-Host "Environment $environmentName is not setup for deployments from branch $ENV:GITHUB_REF_NAME" + if ($deploymentSettings.BranchesFromPolicy -and $deploymentSettings.BranchesFromPolicy.Count -gt 0) { + Write-Host "Environment $environmentName is not setup for deployments from branch '$($ENV:GITHUB_REF_NAME)' (GitHub policy allows branches: $($deploymentSettings.BranchesFromPolicy -join ', '))" + } + elseif ($deploymentSettings.Branches -and $deploymentSettings.Branches.Count -gt 0) { + Write-Host "Environment $environmentName is not setup for deployments from branch '$($ENV:GITHUB_REF_NAME)' (allowed branches in settings: $($deploymentSettings.Branches -join ', '))" + } + else { + Write-Host "Environment $environmentName is not setup for deployments from branch '$($ENV:GITHUB_REF_NAME)' (no branch policy defined - only 'main' is allowed by default)" + } } } if ($includeEnvironment) { @@ -304,3 +312,18 @@ Write-Host "EnvironmentCount=$($deploymentEnvironments.Keys.Count)" Add-Content -Encoding UTF8 -Path $env:GITHUB_OUTPUT -Value "UnknownEnvironment=$unknownEnvironment" Write-Host "UnknownEnvironment=$unknownEnvironment" + +# Handle noMatchingEnvironmentsAction when environments were found but all filtered out +if ($deploymentEnvironments.Keys.Count -eq 0 -and $environments -and @($environments).Count -gt 0) { + $noMatchAction = if ($settings.ContainsKey('noMatchingEnvironmentsAction')) { $settings.noMatchingEnvironmentsAction } else { 'ignore' } + $message = "No environments matched deployment criteria. $(@($environments).Count) environment(s) were found ($($environments -join ', ')) but all were excluded by branch policies or deployment type filters. Current branch: $ENV:GITHUB_REF_NAME" + switch ($noMatchAction) { + 'warning' { + OutputWarning $message + } + 'error' { + throw $message + } + # 'ignore' - current behavior, do nothing + } +} diff --git a/Actions/DumpWorkflowInfo/DumpWorkflowInfo.ps1 b/Actions/DumpWorkflowInfo/DumpWorkflowInfo.ps1 index 555b0e4067..7052236d96 100644 --- a/Actions/DumpWorkflowInfo/DumpWorkflowInfo.ps1 +++ b/Actions/DumpWorkflowInfo/DumpWorkflowInfo.ps1 @@ -1,12 +1,13 @@ -Write-Host "Event name: $env:GITHUB_EVENT_NAME" -if ($env:GITHUB_EVENT_NAME -eq 'workflow_dispatch') { - Write-Host "Inputs:" - $eventPath = Get-Content -Encoding UTF8 -Path $env:GITHUB_EVENT_PATH -Raw | ConvertFrom-Json - if ($null -ne $eventPath.inputs) { - $eventPath.inputs.psObject.Properties | Sort-Object { $_.Name } | ForEach-Object { - $property = $_.Name - $value = $eventPath.inputs."$property" - Write-Host "- $property = '$value'" - } - } -} +Write-Host "Event name: $env:GITHUB_EVENT_NAME" +Write-Host "Branch: $env:GITHUB_REF_NAME" +if ($env:GITHUB_EVENT_NAME -eq 'workflow_dispatch') { + Write-Host "Inputs:" + $eventPath = Get-Content -Encoding UTF8 -Path $env:GITHUB_EVENT_PATH -Raw | ConvertFrom-Json + if ($null -ne $eventPath.inputs) { + $eventPath.inputs.psObject.Properties | Sort-Object { $_.Name } | ForEach-Object { + $property = $_.Name + $value = $eventPath.inputs."$property" + Write-Host "- $property = '$value'" + } + } +} diff --git a/Scenarios/settings.md b/Scenarios/settings.md index 53573420a8..ef9eab1688 100644 --- a/Scenarios/settings.md +++ b/Scenarios/settings.md @@ -130,6 +130,7 @@ The repository settings are only read from the repository settings file (.github | enableTaskScheduler | Setting enableTaskScheduler to true in your project setting file, causes the build container to be created with the Task Scheduler running. | false | | useCompilerFolder | Setting useCompilerFolder to true causes your pipelines to use containerless compiling. Unless you also set **doNotPublishApps** to true, setting useCompilerFolder to true won't give you any performance advantage, since AL-Go for GitHub will still need to create a container in order to publish and test the apps. In the future, publishing and testing will be split from building and there will be other options for getting an instance of Business Central for publishing and testing. **Note** when using UseCompilerFolder you need to sign apps using the new signing mechanism described [here](../Scenarios/Codesigning.md). | false | | excludeEnvironments | excludeEnvironments can be an array of GitHub Environments, which should be excluded from the list of environments considered for deployment. github-pages is automatically added to this array and cannot be used as environment for deployment of AL-Go for GitHub projects. | [ ] | +| noMatchingEnvironmentsAction | Specifies what happens when deployment environments are found but all are excluded by branch policies or deployment type filters, resulting in nothing being deployed. Allowed values are **ignore** (workflow succeeds silently, current default behavior), **warning** (workflow succeeds but shows a visible warning annotation), and **error** (workflow fails with a clear error message). | ignore | | trustMicrosoftNuGetFeeds | Unless this setting is set to false, AL-Go for GitHub will trust the NuGet feeds provided by Microsoft. The feeds provided by Microsoft contains all Microsoft apps, all Microsoft symbols and symbols for all AppSource apps. | true | | trustedNuGetFeeds | trustedNuGetFeeds can be an array of NuGet feed specifications, which AL-Go for GitHub will use for dependency resolution. Every feed specification must include a URL property and can optionally include a few other properties:
**url** = The URL of the feed (examples: https://pkgs.dev.azure.com/myorg/apps/\_packaging/myrepo/nuget/v3/index.json or https://nuget.pkg.github.com/mygithuborg/index.json").
**authTokenSecret** = If the NuGet feed specified by URL is private, the authTokenSecret must be the name of a secret containing the authentication token with permissions to search and read packages from the NuGet feed.
**patterns** = AL-Go for GitHub will only trust packages, where the ID matches this pattern. Default is all packages (\*).
**fingerprints** = If specified, AL-Go for GitHub will only trust packages signed with a certificate with a fingerprint matching one of the fingerprints in this array. | [ ] | | nuGetFeedSelectMode | Determines the select mode when finding Business Central app packages from NuGet feeds, based on the dependency version specified in app.json. Options are:
- `Earliest` for earliest version of the package
- `EarliestMatching` for earliest version of the package also compatible with the Business Central version used
- `Exact` for the exact version of the package
- `Latest` for the latest version of the package
- `LatestMatching` for the latest version of the package also compatible with the Business Central version used. | LatestMatching | diff --git a/Tests/DetermineDeploymentEnvironments.Test.ps1 b/Tests/DetermineDeploymentEnvironments.Test.ps1 index 6b90ef76ad..7db01dbcea 100644 --- a/Tests/DetermineDeploymentEnvironments.Test.ps1 +++ b/Tests/DetermineDeploymentEnvironments.Test.ps1 @@ -331,4 +331,67 @@ Describe "DetermineDeploymentEnvironments Action Test" { $EnvironmentCount | Should -Be 0 $UnknownEnvironment | Should -Be 0 } + + # noMatchingEnvironmentsAction = ignore (default) - should succeed silently when all environments are filtered out by branch policy + It 'Test calling action directly - noMatchingEnvironmentsAction ignore should succeed silently' { + Mock InvokeWebRequest -ParameterFilter { $uri -like '*/environments' } -MockWith { + return @{"Content" = (ConvertTo-Json -Compress -Depth 99 -InputObject @{ "environments" = @( @{ "name" = "test"; "protection_rules" = @() } ) })} + } + + $settings = @{ + "type" = "PTE"; "runs-on" = "ubuntu-latest"; "shell" = "pwsh"; "environments" = @(); "excludeEnvironments" = @( 'github-pages' ) + "alDoc" = @{ "continuousDeployment" = $false; "deployToGitHubPages" = $false } + "noMatchingEnvironmentsAction" = "ignore" + "DeployToTest" = @{ "Branches" = @("release/*") } + } + $env:Settings = $settings | ConvertTo-Json -Compress + $env:GITHUB_REF_NAME = "feature/my-feature" + + # Should succeed silently with 0 environments + . (Join-Path $scriptRoot $scriptName) -getEnvironments '*' -type 'Publish' + PassGeneratedOutput + $EnvironmentCount | Should -Be 0 + } + + # noMatchingEnvironmentsAction = warning - should succeed with a warning when all environments are filtered out by branch policy + It 'Test calling action directly - noMatchingEnvironmentsAction warning should output warning' { + Mock InvokeWebRequest -ParameterFilter { $uri -like '*/environments' } -MockWith { + return @{"Content" = (ConvertTo-Json -Compress -Depth 99 -InputObject @{ "environments" = @( @{ "name" = "test"; "protection_rules" = @() } ) })} + } + + $settings = @{ + "type" = "PTE"; "runs-on" = "ubuntu-latest"; "shell" = "pwsh"; "environments" = @(); "excludeEnvironments" = @( 'github-pages' ) + "alDoc" = @{ "continuousDeployment" = $false; "deployToGitHubPages" = $false } + "noMatchingEnvironmentsAction" = "warning" + "DeployToTest" = @{ "Branches" = @("release/*") } + } + $env:Settings = $settings | ConvertTo-Json -Compress + $env:GITHUB_REF_NAME = "feature/my-feature" + + # Should succeed but output a warning + . (Join-Path $scriptRoot $scriptName) -getEnvironments '*' -type 'Publish' 3>&1 -WarningVariable warningOutput | Out-Null + PassGeneratedOutput + $EnvironmentCount | Should -Be 0 + # Verify the warning was emitted (OutputWarning writes to warning stream when running locally) + $warningOutput | Should -Match "No environments matched deployment criteria" + } + + # noMatchingEnvironmentsAction = error - should throw when all environments are filtered out by branch policy + It 'Test calling action directly - noMatchingEnvironmentsAction error should throw' { + Mock InvokeWebRequest -ParameterFilter { $uri -like '*/environments' } -MockWith { + return @{"Content" = (ConvertTo-Json -Compress -Depth 99 -InputObject @{ "environments" = @( @{ "name" = "test"; "protection_rules" = @() } ) })} + } + + $settings = @{ + "type" = "PTE"; "runs-on" = "ubuntu-latest"; "shell" = "pwsh"; "environments" = @(); "excludeEnvironments" = @( 'github-pages' ) + "alDoc" = @{ "continuousDeployment" = $false; "deployToGitHubPages" = $false } + "noMatchingEnvironmentsAction" = "error" + "DeployToTest" = @{ "Branches" = @("release/*") } + } + $env:Settings = $settings | ConvertTo-Json -Compress + $env:GITHUB_REF_NAME = "feature/my-feature" + + # Should throw with a clear error message + { . (Join-Path $scriptRoot $scriptName) -getEnvironments '*' -type 'Publish' } | Should -Throw "*No environments matched deployment criteria*" + } }