Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Actions/.Modules/ReadSettings.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ function GetDefaultSettings
}
"fullBuildPatterns" = @()
"excludeEnvironments" = @()
"noMatchingEnvironmentsAction" = "ignore"
"alDoc" = [ordered]@{
"continuousDeployment" = $false
"deployToGitHubPages" = $true
Expand Down
6 changes: 6 additions & 0 deletions Actions/.Modules/settings.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,12 @@
},
"description": "An array of environments to be excluded from the build. See https://aka.ms/ALGoSettings#excludeenvironments"
},
"noMatchingEnvironmentsAction": {
"type": "string",
"enum": ["ignore", "warning", "error"],
"default": "ignore",
"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": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,21 @@ else {
}
}
if (!$includeEnvironment) {
Write-Host "Environment $environmentName is not setup for deployments from branch $ENV:GITHUB_REF_NAME"
$hasPolicyBranches = $deploymentSettings.BranchesFromPolicy -and $deploymentSettings.BranchesFromPolicy.Count -gt 0
$hasSettingsBranches = $deploymentSettings.Branches -and $deploymentSettings.Branches.Count -gt 0
if ($hasPolicyBranches -and $hasSettingsBranches) {
# Both restrictions are enforced - a branch must satisfy both, so report both allowed lists
Write-Host "Environment $environmentName is not setup for deployments from branch '$($ENV:GITHUB_REF_NAME)' (GitHub policy allows branches: $($deploymentSettings.BranchesFromPolicy -join ', '); allowed branches in settings: $($deploymentSettings.Branches -join ', '))"
}
elseif ($hasPolicyBranches) {
Write-Host "Environment $environmentName is not setup for deployments from branch '$($ENV:GITHUB_REF_NAME)' (GitHub policy allows branches: $($deploymentSettings.BranchesFromPolicy -join ', '))"
}
elseif ($hasSettingsBranches) {
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) {
Expand Down Expand Up @@ -304,3 +318,20 @@ 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.
# Only applies to manual 'Publish' deployments - for continuous deployment (CD), matching zero
# environments (e.g. when pushing to a branch that no environment allows) is expected and must not fail.
if ($type -eq 'Publish' -and $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
}
}
1 change: 1 addition & 0 deletions Actions/DumpWorkflowInfo/DumpWorkflowInfo.ps1
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
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
Expand Down
4 changes: 4 additions & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
### New setting noMatchingEnvironmentsAction to control behavior when nothing is deployed

The manual `Publish To Environment` workflow could report success even when no environment matched the deployment criteria (for example when the selected branch is not allowed by the environment branch policy), making it look like a deployment happened when it did not. A new setting `noMatchingEnvironmentsAction` controls this behavior for `Publish` deployments. Allowed values are `ignore` (default, workflow succeeds silently as before), `warning` (workflow succeeds but shows a visible warning annotation) and `error` (workflow fails with a clear error message). Continuous deployment is unaffected, since matching zero environments is expected there. The `DumpWorkflowInfo` action now also logs the branch, and the skip message explains which branches are allowed for the environment.

### Expanded AL-Go telemetry dashboard

The starter Azure Data Explorer dashboard now includes dedicated views for workflow reliability, run exploration, test quality, workflow duration, runner efficiency, and AL-Go maintenance. It also provides repository, workflow, branch, and repository-type filtering, clearer empty states, and repository-level runtime supportability information.
Expand Down
1 change: 1 addition & 0 deletions Scenarios/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ The repository settings are only read from the repository settings file (.github
| <a id="enableTaskScheduler"></a>enableTaskScheduler | Setting enableTaskScheduler to true in your project setting file, causes the build container to be created with the Task Scheduler running. | false |
| <a id="useCompilerFolder"></a>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 |
| <a id="doNotPerformUpgrade"></a>doNotPerformUpgrade | When true, Run-AlPipeline skips the upgrade phase, but AL-Go still downloads and passes previous release apps so AppSourceCop breaking-change checks can run. Unlike **skipUpgrade**, which ignores previous releases entirely, use this setting when you want to publish and test without executing upgrade logic. | false |
| <a id="noMatchingEnvironmentsAction"></a>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 |
| <a id="workspaceCompilation"></a>workspaceCompilation | **PREVIEW:** Configuration for workspace compilation. This uses the AL tool to compile all apps in the workspace in a single operation, which can improve build performance for repositories with multiple apps. Like **useCompilerFolder**, this is containerless compiling.<br />**enabled** - Set to true to enable workspace compilation. Default: false.<br />**parallelism** - The number of parallel compilation processes. Set to 0 or -1 to use all available processors. Default: 1.<br /><br />**Note:** Workspace compilation requires the artifact setting to use BC v28 or higher.<br />Workspace compilation supports incremental builds when `incrementalBuilds.mode` is set to `modifiedApps`. In incremental mode, only modified apps and their dependents are recompiled; unmodified apps are downloaded from the baseline workflow run. | { "enabled": false, "parallelism": 1 } |
| <a id="excludeEnvironments"></a>excludeEnvironments| excludeEnvironments can be an array of GitHub Environments, which should be excluded from the list of environments considered for deployment. github-pages and copilot are automatically added to this array and cannot be used as an environment for deployment of AL-Go for GitHub projects. | [ ] |
| <a id="trustMicrosoftNuGetFeeds"></a>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 |
Expand Down
116 changes: 116 additions & 0 deletions Tests/DetermineDeploymentEnvironments.Test.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -331,4 +331,120 @@ 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
# OutputWarning uses Write-Warning when running locally, but Write-Host (::Warning::) on GitHub Actions.
# Capture all output streams so we can check for the message in either case.
$allOutput = . (Join-Path $scriptRoot $scriptName) -getEnvironments '*' -type 'Publish' *>&1
PassGeneratedOutput
$EnvironmentCount | Should -Be 0
# Verify the warning was emitted in any output stream
# Use Out-String so Should -Match checks the combined text rather than requiring every element to match
($allOutput | Out-String) | 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*"
}

# noMatchingEnvironmentsAction should NOT affect continuous deployment (CD) - matching zero environments is expected there
It 'Test calling action directly - noMatchingEnvironmentsAction error should not throw for CD' {
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 not throw for CD, even with error setting - and should end up with 0 environments
. (Join-Path $scriptRoot $scriptName) -getEnvironments '*' -type 'CD'
PassGeneratedOutput
$EnvironmentCount | Should -Be 0
}

# Skip message should list both allowed branch lists when a GitHub policy and settings Branches are both configured
It 'Test calling action directly - skip message lists both GitHub policy and settings branches' {
Mock InvokeWebRequest -ParameterFilter { $uri -like '*/environments' } -MockWith {
return @{"Content" = (ConvertTo-Json -Compress -Depth 99 -InputObject @{ "environments" = @( @{ "name" = "test"; "protection_rules" = @( @{ "type" = "branch_policy"}); "deployment_branch_policy" = @{ "protected_branches" = $false; "custom_branch_policies" = $true } } ) })}
}
Mock InvokeWebRequest -ParameterFilter { $uri -like '*/deployment-branch-policies' } -MockWith {
return @{"Content" = (@{ "branch_policies" = @( @{ "name" = "feature/*" } ) } | ConvertTo-Json -Depth 99 -Compress)}
}

$settings = @{
"type" = "PTE"; "runs-on" = "ubuntu-latest"; "shell" = "pwsh"; "environments" = @(); "excludeEnvironments" = @( 'github-pages' )
"alDoc" = @{ "continuousDeployment" = $false; "deployToGitHubPages" = $false }
"DeployToTest" = @{ "Branches" = @("release/*") }
}
$env:Settings = $settings | ConvertTo-Json -Compress
# Branch passes the GitHub policy (feature/*) but is rejected by the settings Branches (release/*)
$env:GITHUB_REF_NAME = "feature/my-feature"

$allOutput = . (Join-Path $scriptRoot $scriptName) -getEnvironments '*' -type 'Publish' *>&1
PassGeneratedOutput
$EnvironmentCount | Should -Be 0
# Both allowed lists must be reported so the actual reason is not hidden.
# Match against the raw output lines rather than Out-String, which word-wraps long
# lines at the console width and can split the searched text across a newline.
$skipMessage = @($allOutput | ForEach-Object { "$_" }) -join "`n"
$skipMessage | Should -Match "GitHub policy allows branches: feature/\*"
$skipMessage | Should -Match "allowed branches in settings: release/\*"
}
}
Loading