diff --git a/Actions/DetermineDeploymentEnvironments/DetermineDeploymentEnvironments.ps1 b/Actions/DetermineDeploymentEnvironments/DetermineDeploymentEnvironments.ps1 index 43fe98a732..6fc16f99ed 100644 --- a/Actions/DetermineDeploymentEnvironments/DetermineDeploymentEnvironments.ps1 +++ b/Actions/DetermineDeploymentEnvironments/DetermineDeploymentEnvironments.ps1 @@ -285,7 +285,11 @@ else { $json = @{"matrix" = @{ "include" = @() }; "fail-fast" = $false } $deploymentEnvironments.Keys | Sort-Object | ForEach-Object { $deploymentEnvironment = $deploymentEnvironments."$_" - $json.matrix.include += @{ "environment" = $_; "os" = "$(ConvertTo-Json -InputObject @($deploymentEnvironment."runs-on".Split(',').Trim()) -compress)"; "shell" = $deploymentEnvironment."shell" } + $buildMode = "Default" + if ($deploymentEnvironment.ContainsKey("buildMode") -and $deploymentEnvironment."buildMode") { + $buildMode = $deploymentEnvironment."buildMode" + } + $json.matrix.include += @{ "environment" = $_; "os" = "$(ConvertTo-Json -InputObject @($deploymentEnvironment."runs-on".Split(',').Trim()) -compress)"; "shell" = $deploymentEnvironment."shell"; "buildMode" = $buildMode } } $environmentsMatrixJson = $json | ConvertTo-Json -Depth 99 -compress Add-Content -Encoding UTF8 -Path $env:GITHUB_OUTPUT -Value "EnvironmentsMatrixJson=$environmentsMatrixJson" diff --git a/Actions/GetArtifactsForDeployment/GetArtifactsForDeployment.ps1 b/Actions/GetArtifactsForDeployment/GetArtifactsForDeployment.ps1 index 30c2f5e7c4..1491b453e6 100644 --- a/Actions/GetArtifactsForDeployment/GetArtifactsForDeployment.ps1 +++ b/Actions/GetArtifactsForDeployment/GetArtifactsForDeployment.ps1 @@ -4,18 +4,31 @@ Param( [Parameter(HelpMessage = "Artifacts version to download (current, prerelease, draft, latest or version number)", Mandatory = $true)] [string] $artifactsVersion, [Parameter(HelpMessage = "Folder in which the artifacts will be downloaded", Mandatory = $true)] - [string] $artifactsFolder + [string] $artifactsFolder, + [Parameter(HelpMessage = "Build mode used when building the artifacts", Mandatory = $false)] + [string] $buildMode = 'Default' ) Import-Module (Join-Path -Path $PSScriptRoot "GetArtifactsForDeployment.psm1") . (Join-Path -Path $PSScriptRoot -ChildPath "..\AL-Go-Helper.ps1" -Resolve) DownloadAndImportBcContainerHelper +# If buildMode is 'Default', set it to empty string (no prefix in artifact names) +if ($buildMode -eq 'Default') { + $buildMode = '' +} + # Get artifacts for all projects $projects = "*" -$artifactsToDownload = @("Apps","TestApps","Dependencies","PowerPlatformSolution") -Write-Host "Get artifacts for version: '$artifactsVersion' for these projects: '$projects' to folder: '$artifactsFolder'" +# Default artifact types (used for releases which only support default buildMode) +$defaultArtifactTypes = @("Apps","TestApps","Dependencies","PowerPlatformSolution") + +# Artifact types with buildMode prefix (used for workflow artifacts) +# PowerPlatformSolution is always built with 'default' buildMode, so it never has a prefix +$buildModeArtifactTypes = @("$($buildMode)Apps","$($buildMode)TestApps","$($buildMode)Dependencies","PowerPlatformSolution") + +Write-Host "Get artifacts for version: '$artifactsVersion' (build mode: $buildMode) for these projects: '$projects' to folder: '$artifactsFolder'" $artifactsFolder = Join-Path $ENV:GITHUB_WORKSPACE $artifactsFolder if (!(Test-Path $artifactsFolder)) { @@ -38,7 +51,8 @@ if ($artifactsVersion -eq "current" -or $artifactsVersion -eq "prerelease" -or $ if (!($release)) { throw "Unable to locate $artifactsVersion release" } - $artifactsToDownload | ForEach-Object { + # Releases only contain default buildMode artifacts + $defaultArtifactTypes | ForEach-Object { DownloadRelease -token $token -projects $projects -api_url $ENV:GITHUB_API_URL -repository $ENV:GITHUB_REPOSITORY -release $release -path $artifactsFolder -mask $_ -unpack } } @@ -72,13 +86,13 @@ elseif ($artifactsVersion -like "PR_*") { $expiredArtifacts = @() $lastKnownGoodBuildArtifacts = @() # Get PR artifacts - $artifactsToDownload | ForEach-Object { + $buildModeArtifactTypes | ForEach-Object { $prArtifacts += GetArtifactsFromWorkflowRun -workflowRun $latestPRBuildId -token $token -api_url $ENV:GITHUB_API_URL -repository $ENV:GITHUB_REPOSITORY -mask $_ -projects $projects -expiredArtifacts ([ref]$expiredArtifacts) } # Get last known good build artifacts referenced from PR if ($lastKnownGoodBuildId -ne 0) { Write-Host "Last known good build id: $lastKnownGoodBuildId" - $artifactsToDownload | ForEach-Object { + $buildModeArtifactTypes | ForEach-Object { $lastKnownGoodBuildArtifacts += GetArtifactsFromWorkflowRun -workflowRun $lastKnownGoodBuildId -token $token -api_url $ENV:GITHUB_API_URL -repository $ENV:GITHUB_REPOSITORY -mask $_ -projects $projects -expiredArtifacts ([ref]$expiredArtifacts) } } @@ -106,7 +120,7 @@ else { if ($searchArtifacts) { $allArtifacts = @() - $artifactsToDownload | ForEach-Object { + $buildModeArtifactTypes | ForEach-Object { $allArtifacts += @(GetArtifacts -token $token -api_url $ENV:GITHUB_API_URL -repository $ENV:GITHUB_REPOSITORY -mask $_ -projects $projects -version $artifactsVersion -branch $ENV:GITHUB_REF_NAME) } if ($allArtifacts) { diff --git a/Actions/GetArtifactsForDeployment/README.md b/Actions/GetArtifactsForDeployment/README.md index 40d153eeee..be7324665c 100644 --- a/Actions/GetArtifactsForDeployment/README.md +++ b/Actions/GetArtifactsForDeployment/README.md @@ -16,6 +16,7 @@ none | token | | The GitHub token running the action | github.token | | artifactsVersion | Yes | Artifacts version to download (current, prerelease, draft, latest or version number) | | | artifactsFolder | Yes | Folder in which the artifacts will be downloaded | | +| buildMode | | Build mode used when building the artifacts | Default | ## OUTPUT diff --git a/Actions/GetArtifactsForDeployment/action.yaml b/Actions/GetArtifactsForDeployment/action.yaml index 67e1578128..5d41a20b34 100644 --- a/Actions/GetArtifactsForDeployment/action.yaml +++ b/Actions/GetArtifactsForDeployment/action.yaml @@ -15,6 +15,10 @@ inputs: artifactsFolder: description: Folder in which the artifacts will be downloaded required: true + buildMode: + description: Build mode used when building the artifacts + required: false + default: 'Default' runs: using: composite steps: @@ -24,9 +28,10 @@ runs: _token: ${{ inputs.token }} _artifactsVersion: ${{ inputs.artifactsVersion }} _artifactsFolder: ${{ inputs.artifactsFolder }} + _buildMode: ${{ inputs.buildMode }} run: | ${{ github.action_path }}/../Invoke-AlGoAction.ps1 -ActionName "GetArtifactsForDeployment" -Action { - ${{ github.action_path }}/GetArtifactsForDeployment.ps1 -token $ENV:_token -artifactsVersion $ENV:_artifactsVersion -artifactsFolder $ENV:_artifactsFolder + ${{ github.action_path }}/GetArtifactsForDeployment.ps1 -token $ENV:_token -artifactsVersion $ENV:_artifactsVersion -artifactsFolder $ENV:_artifactsFolder -buildMode $ENV:_buildMode } branding: icon: terminal diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 1f7b9dec70..f4f94a3df3 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,5 +1,6 @@ ### Issues +- Issue 2107 Publish a specific build mode to an environment - Issue 1915 CICD fails on releases/26.x branch - '26.x' cannot be recognized as a semantic version string ## v8.2 diff --git a/Templates/AppSource App/.github/workflows/PublishToEnvironment.yaml b/Templates/AppSource App/.github/workflows/PublishToEnvironment.yaml index 710d401195..e60df4fc8f 100644 --- a/Templates/AppSource App/.github/workflows/PublishToEnvironment.yaml +++ b/Templates/AppSource App/.github/workflows/PublishToEnvironment.yaml @@ -169,6 +169,7 @@ jobs: shell: ${{ matrix.shell }} artifactsVersion: ${{ github.event.inputs.appVersion }} artifactsFolder: '.artifacts' + buildMode: ${{ matrix.buildMode }} - name: Deploy to Business Central id: Deploy diff --git a/Templates/Per Tenant Extension/.github/workflows/PublishToEnvironment.yaml b/Templates/Per Tenant Extension/.github/workflows/PublishToEnvironment.yaml index 710d401195..e60df4fc8f 100644 --- a/Templates/Per Tenant Extension/.github/workflows/PublishToEnvironment.yaml +++ b/Templates/Per Tenant Extension/.github/workflows/PublishToEnvironment.yaml @@ -169,6 +169,7 @@ jobs: shell: ${{ matrix.shell }} artifactsVersion: ${{ github.event.inputs.appVersion }} artifactsFolder: '.artifacts' + buildMode: ${{ matrix.buildMode }} - name: Deploy to Business Central id: Deploy diff --git a/Tests/DetermineDeploymentEnvironments.Test.ps1 b/Tests/DetermineDeploymentEnvironments.Test.ps1 index e577b2177c..394a9f6aa0 100644 --- a/Tests/DetermineDeploymentEnvironments.Test.ps1 +++ b/Tests/DetermineDeploymentEnvironments.Test.ps1 @@ -58,13 +58,13 @@ Describe "DetermineDeploymentEnvironments Action Test" { $env:Settings = @{ "type" = "PTE"; "runs-on" = "ubuntu-latest"; "shell" = "pwsh"; "environments" = @(); "excludeEnvironments" = @( 'github-pages' ); "alDoc" = @{ "continuousDeployment" = $false; "deployToGitHubPages" = $false } } | ConvertTo-Json -Compress . (Join-Path $scriptRoot $scriptName) -getEnvironments '*' -type 'CD' PassGeneratedOutput - $EnvironmentsMatrixJson | ConvertFrom-Json | ConvertTo-HashTable -recurse | Should -MatchHashtable @{"matrix"=@{"include"=@(@{"environment"="another";"os"="[""ubuntu-latest""]";"shell"="pwsh"};@{"environment"="test";"os"="[""ubuntu-latest""]";"shell"="pwsh"})};"fail-fast"=$false} + $EnvironmentsMatrixJson | ConvertFrom-Json | ConvertTo-HashTable -recurse | Should -MatchHashtable @{"matrix"=@{"include"=@(@{"environment"="another";"os"="[""ubuntu-latest""]";"shell"="pwsh";"buildMode"="Default"};@{"environment"="test";"os"="[""ubuntu-latest""]";"shell"="pwsh";"buildMode"="Default"})};"fail-fast"=$false} $DeploymentEnvironmentsJson | ConvertFrom-Json | ConvertTo-HashTable -recurse | Should -MatchHashtable @{"test"=@{"EnvironmentType"="SaaS";"EnvironmentName"="test";"Branches"=@();"BranchesFromPolicy"=@();"Projects"="*";"DependencyInstallMode"="install";"Scope"=$null;"syncMode"=$null;"buildMode"=$null;"continuousDeployment"=$null;"runs-on"=@("ubuntu-latest");"shell"="pwsh";"ppEnvironmentUrl"="";"companyId"="";"includeTestAppsInSandboxEnvironment"=$false;"excludeAppIds"=@()};"another"=@{"EnvironmentType"="SaaS";"EnvironmentName"="another";"Branches"=@();"BranchesFromPolicy"=@();"Projects"="*";"DependencyInstallMode"="install";"Scope"=$null;"syncMode"=$null;"buildMode"=$null;"continuousDeployment"=$null;"runs-on"=@("ubuntu-latest");"shell"="pwsh";"ppEnvironmentUrl"="";"companyId"="";"includeTestAppsInSandboxEnvironment"=$false;"excludeAppIds"=@()}} $EnvironmentCount | Should -Be 2 . (Join-Path $scriptRoot $scriptName) -getEnvironments 'test' -type 'CD' PassGeneratedOutput - $EnvironmentsMatrixJson | ConvertFrom-Json | ConvertTo-HashTable -recurse | Should -MatchHashtable @{"matrix"=@{"include"=@(@{"environment"="test";"os"="[""ubuntu-latest""]";"shell"="pwsh"})};"fail-fast"=$false} + $EnvironmentsMatrixJson | ConvertFrom-Json | ConvertTo-HashTable -recurse | Should -MatchHashtable @{"matrix"=@{"include"=@(@{"environment"="test";"os"="[""ubuntu-latest""]";"shell"="pwsh";"buildMode"="Default"})};"fail-fast"=$false} $DeploymentEnvironmentsJson | ConvertFrom-Json | ConvertTo-HashTable -recurse | Should -MatchHashtable @{"test"=@{"EnvironmentType"="SaaS";"EnvironmentName"="test";"Branches"=@();"BranchesFromPolicy"=@();"Projects"="*";"DependencyInstallMode"="install";"Scope"=$null;"syncMode"=$null;"buildMode"=$null;"continuousDeployment"=$null;"runs-on"=@("ubuntu-latest");"shell"="pwsh";"ppEnvironmentUrl"="";"companyId"="";"includeTestAppsInSandboxEnvironment"=$false;"excludeAppIds"=@()}} $EnvironmentCount | Should -Be 1 } @@ -81,7 +81,7 @@ Describe "DetermineDeploymentEnvironments Action Test" { $env:Settings = @{ "type" = "PTE"; "runs-on" = "ubuntu-latest"; "shell" = "pwsh"; "environments" = @(); "excludeEnvironments" = @( 'github-pages' ); "alDoc" = @{ "continuousDeployment" = $false; "deployToGitHubPages" = $false } } | ConvertTo-Json -Compress . (Join-Path $scriptRoot $scriptName) -getEnvironments '*' -type 'CD' PassGeneratedOutput - $EnvironmentsMatrixJson | ConvertFrom-Json | ConvertTo-HashTable -recurse | Should -MatchHashtable @{"matrix"=@{"include"=@(@{"environment"="another";"os"="[""ubuntu-latest""]";"shell"="pwsh"})};"fail-fast"=$false} + $EnvironmentsMatrixJson | ConvertFrom-Json | ConvertTo-HashTable -recurse | Should -MatchHashtable @{"matrix"=@{"include"=@(@{"environment"="another";"os"="[""ubuntu-latest""]";"shell"="pwsh";"buildMode"="Default"})};"fail-fast"=$false} $DeploymentEnvironmentsJson | ConvertFrom-Json | ConvertTo-HashTable -recurse | Should -MatchHashtable @{"another"=@{"EnvironmentType"="SaaS";"EnvironmentName"="another";"Branches"=@();"BranchesFromPolicy"=@();"Projects"="*";"DependencyInstallMode"="install";"Scope"=$null;"syncMode"=$null;"buildMode"=$null;"continuousDeployment"=$null;"runs-on"=@("ubuntu-latest");"shell"="pwsh";"ppEnvironmentUrl"="";"companyId"="";"includeTestAppsInSandboxEnvironment"=$false;"excludeAppIds"=@()}} $EnvironmentCount | Should -Be 1 @@ -107,7 +107,7 @@ Describe "DetermineDeploymentEnvironments Action Test" { # Only another environment should be included when deploying from main . (Join-Path $scriptRoot $scriptName) -getEnvironments '*' -type 'CD' PassGeneratedOutput - $EnvironmentsMatrixJson | ConvertFrom-Json | ConvertTo-HashTable -recurse | Should -MatchHashtable @{"matrix"=@{"include"=@(@{"environment"="another";"os"="[""ubuntu-latest""]";"shell"="pwsh"})};"fail-fast"=$false} + $EnvironmentsMatrixJson | ConvertFrom-Json | ConvertTo-HashTable -recurse | Should -MatchHashtable @{"matrix"=@{"include"=@(@{"environment"="another";"os"="[""ubuntu-latest""]";"shell"="pwsh";"buildMode"="Default"})};"fail-fast"=$false} $DeploymentEnvironmentsJson | ConvertFrom-Json | ConvertTo-HashTable -recurse | Should -MatchHashtable @{"another"=@{"EnvironmentType"="SaaS";"EnvironmentName"="another";"Branches"=@();"BranchesFromPolicy"=@();"Projects"="*";"DependencyInstallMode"="install";"Scope"=$null;"syncMode"=$null;"buildMode"=$null;"continuousDeployment"=$null;"runs-on"=@("ubuntu-latest");"shell"="pwsh";"ppEnvironmentUrl"="";"companyId"="";"includeTestAppsInSandboxEnvironment"=$false;"excludeAppIds"=@()}} $EnvironmentCount | Should -Be 1 ($EnvironmentsMatrixJson | ConvertFrom-Json | ConvertTo-HashTable -recurse).matrix.include.environment | Should -Contain "another" @@ -239,6 +239,34 @@ Describe "DetermineDeploymentEnvironments Action Test" { ($EnvironmentsMatrixJson | ConvertFrom-Json | ConvertTo-HashTable -recurse).matrix.include.environment | Should -Contain "test (PROD)" } + # Test that buildMode from DeployTo settings is correctly included in the matrix + It 'Test calling action directly - Custom buildMode from DeployTo settings is included in matrix' { + 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 } + "DeployToTest" = @{ + "buildMode" = "CustomBuildMode" + } + } + + $env:Settings = $settings | ConvertTo-Json -Compress -Depth 5 + . (Join-Path $scriptRoot $scriptName) -getEnvironments '*' -type 'CD' + PassGeneratedOutput + + # Verify buildMode is correctly set to CustomBuildMode in the matrix + $matrix = $EnvironmentsMatrixJson | ConvertFrom-Json | ConvertTo-HashTable -recurse + $matrix.matrix.include[0].buildMode | Should -Be "CustomBuildMode" + $EnvironmentCount | Should -Be 1 + } + # Unknown environment - createEnvIfNotExists = false (default) - should throw error It 'Test calling action directly - Unknown environment without createEnvIfNotExists should throw' { Mock InvokeWebRequest -ParameterFilter { $uri -like '*/environments' } -MockWith {