From 4f1436410a7a178183d2a9be1464393e0860e9a6 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Thu, 25 Dec 2025 06:16:07 +0100 Subject: [PATCH 01/50] use private containerhelper --- Actions/AL-Go-Helper.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index 82829f487..1294771d6 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -27,7 +27,7 @@ $RepoSettingsFile = Join-Path '.github' 'AL-Go-Settings.json' $defaultCICDPushBranches = @( 'main', 'release/*', 'feature/*' ) [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'defaultCICDPullRequestBranches', Justification = 'False positive.')] $defaultCICDPullRequestBranches = @( 'main' ) -$defaultBcContainerHelperVersion = "preview" # Must be double quotes. Will be replaced by BcContainerHelperVersion if necessary in the deploy step - ex. "https://github.com/organization/navcontainerhelper/archive/refs/heads/branch.zip" +$defaultBcContainerHelperVersion = "https://github.com/freddydk/navcontainerhelper/archive/refs/heads/TestAppDependencies.zip" # Must be double quotes. Will be replaced by BcContainerHelperVersion if necessary in the deploy step - ex. "https://github.com/organization/navcontainerhelper/archive/refs/heads/branch.zip" $notSecretProperties = @("Scopes","TenantId","BlobName","ContainerName","StorageAccountName","ServerUrl","ppUserName","GitHubAppClientId","EnvironmentName") $runAlPipelineOverrides = @( From 001c2984edbbbfa2ce1d84443cb1c661ca4758ed Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Thu, 25 Dec 2025 06:54:17 +0100 Subject: [PATCH 02/50] check for apps/TestApps --- .../DownloadProjectDependencies.Action.ps1 | 6 +++--- Actions/Github-Helper.psm1 | 18 ++++++++++++++++-- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/Actions/DownloadProjectDependencies/DownloadProjectDependencies.Action.ps1 b/Actions/DownloadProjectDependencies/DownloadProjectDependencies.Action.ps1 index be9f84fb7..6e0f8706e 100644 --- a/Actions/DownloadProjectDependencies/DownloadProjectDependencies.Action.ps1 +++ b/Actions/DownloadProjectDependencies/DownloadProjectDependencies.Action.ps1 @@ -46,7 +46,7 @@ function DownloadDependenciesFromCurrentBuild { Write-Host "Dependency projects: $($dependencyProjects -join ', ')" # For each dependency project, calculate the corresponding probing path - $dependeciesProbingPaths = @() + $dependenciesProbingPaths = @() foreach($dependencyProject in $dependencyProjects) { Write-Host "Reading settings for project '$dependencyProject'" $dependencyProjectSettings = ReadSettings -baseFolder $baseFolder -project $dependencyProject @@ -70,7 +70,7 @@ function DownloadDependenciesFromCurrentBuild { $baseBranch = $ENV:GITHUB_REF_NAME } - $dependeciesProbingPaths += @(@{ + $dependenciesProbingPaths += @(@{ "release_status" = "thisBuild" "version" = "latest" "buildMode" = $dependencyBuildMode @@ -85,7 +85,7 @@ function DownloadDependenciesFromCurrentBuild { # For each probing path, download the dependencies $downloadedDependencies = @() - foreach($probingPath in $dependeciesProbingPaths) { + foreach($probingPath in $dependenciesProbingPaths) { $buildMode = $probingPath.buildMode $project = $probingPath.projects $branch = $probingPath.branch diff --git a/Actions/Github-Helper.psm1 b/Actions/Github-Helper.psm1 index 916785613..53bcc1867 100644 --- a/Actions/Github-Helper.psm1 +++ b/Actions/Github-Helper.psm1 @@ -141,9 +141,16 @@ function GetDependencies { $projects = $dependency.projects $buildMode = $dependency.buildMode + if ($mask -eq 'TestApps') { + $altMask = 'Apps' + } + else { + $altMask = 'TestApps' + } # change the mask to include the build mode if($buildMode -ne "Default") { $mask = "$buildMode$mask" + $altMask = "$buildMode$altMask" } Write-Host "Locating $mask artifacts for projects: $projects" @@ -169,8 +176,15 @@ function GetDependencies { } } elseif ($mask -like '*Apps') { - Write-Host "$project not built, downloading from artifacts" - $missingProjects += @($project) + # Check whether Apps/TestApps exists before determining that project isn't built + $altDownloadName = Join-Path $saveToPath "$project-$branchName-$altMask-*" + if (!(Test-Path $altDownloadName -PathType Container)) { + Write-Host "$project not built, downloading from artifacts" + $missingProjects += @($project) + } + else { + Write-Host "$project built, but $mask not found" + } } } if ($missingProjects -and $dependency.baselineWorkflowID) { From bbcbdcdae74e0184eb941d1d3a32eb9faa45890f Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Thu, 25 Dec 2025 07:48:20 +0100 Subject: [PATCH 03/50] add concept of Solo projects --- Actions/AL-Go-Helper.ps1 | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index 1294771d6..edd650a7f 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -1787,6 +1787,28 @@ Function AnalyzeProjectDependencies { $projectsOrder = @() Write-Host "Analyzing dependencies" while ($projects.Count -gt 0) { + # First determine projects, which no other project depends on - these should be build last + # There is no reason for other jobs running in parallel to wait for these projects to be built + $soloProjects = @($projects | Where-Object { + $isSolo = $true + foreach($otherProject in $projects) { + if ($otherProject -ne $_) { + $otherDependencies = $appDependencies."$otherProject".dependencies + foreach($dependency in $otherDependencies) { + if ($appDependencies."$_".apps -contains $dependency) { + $isSolo = $false + } + } + } + } + return $isSolo + }) + if ($soloProjects.Count -gt 0) { + Write-Host "Solo projects found (no other project depends on them): $($soloProjects -join ", ")" + Write-Host "Adding solo projects to the end of the build order" + $projects = @($projects | Where-Object { $soloProjects -notcontains $_ }) + } + $thisJob = @() # Loop through all projects and find projects that do not have dependencies on other projects in the list # These projects can be built in parallel and are added to the build order @@ -1851,11 +1873,17 @@ Function AnalyzeProjectDependencies { if ($thisJob.Count -eq 0) { throw "Circular project reference encountered, cannot determine build order" } + + $projects = @($projects | Where-Object { $thisJob -notcontains $_ }) + if ($projects.Count -eq 0) { + # Last job, add solo projects + $thisJob += $soloProjects + } + Write-Host "#$no - build projects: $($thisJob -join ", ")" $projectsOrder += @{'projects' = $thisJob; 'projectsCount' = $thisJob.Count } - $projects = @($projects | Where-Object { $thisJob -notcontains $_ }) $no++ } From ad0fb9bdddde21c00acd0bd86f5969a5327f0cf4 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Thu, 25 Dec 2025 07:59:41 +0100 Subject: [PATCH 04/50] change solo mechanism --- Actions/AL-Go-Helper.ps1 | 45 +++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index edd650a7f..dea66970a 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -1783,32 +1783,31 @@ Function AnalyzeProjectDependencies { # "dependencies" = @("appid7", "appid8") # } # } - $no = 1 - $projectsOrder = @() - Write-Host "Analyzing dependencies" - while ($projects.Count -gt 0) { - # First determine projects, which no other project depends on - these should be build last - # There is no reason for other jobs running in parallel to wait for these projects to be built - $soloProjects = @($projects | Where-Object { - $isSolo = $true - foreach($otherProject in $projects) { - if ($otherProject -ne $_) { - $otherDependencies = $appDependencies."$otherProject".dependencies - foreach($dependency in $otherDependencies) { - if ($appDependencies."$_".apps -contains $dependency) { - $isSolo = $false - } + + # First determine projects, which no other project depends on - these should be build last + # There is no reason for other jobs running in parallel to wait for these projects to be built + $soloProjects = @($projects | Where-Object { + $isSolo = $true + foreach($otherProject in $projects) { + if ($otherProject -ne $_) { + $otherDependencies = $appDependencies."$otherProject".dependencies + foreach($dependency in $otherDependencies) { + if ($appDependencies."$_".apps -contains $dependency) { + $isSolo = $false } } } - return $isSolo - }) - if ($soloProjects.Count -gt 0) { - Write-Host "Solo projects found (no other project depends on them): $($soloProjects -join ", ")" - Write-Host "Adding solo projects to the end of the build order" - $projects = @($projects | Where-Object { $soloProjects -notcontains $_ }) } + return $isSolo + }) + if ($soloProjects.Count -gt 0) { + Write-Host "Solo projects found (no other project depends on them): $($soloProjects -join ", ")" + } + $no = 1 + $projectsOrder = @() + Write-Host "Analyzing dependencies" + while ($projects.Count -gt 0) { $thisJob = @() # Loop through all projects and find projects that do not have dependencies on other projects in the list # These projects can be built in parallel and are added to the build order @@ -1875,6 +1874,10 @@ Function AnalyzeProjectDependencies { } $projects = @($projects | Where-Object { $thisJob -notcontains $_ }) + + # Do not build solo projects until the last job + $thisJob = $thisJob | Where-Object { $soloProjects -notcontains $_ } + if ($projects.Count -eq 0) { # Last job, add solo projects $thisJob += $soloProjects From d27ff30f9ecb411958480fd9726c170335807378 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Thu, 25 Dec 2025 08:03:44 +0100 Subject: [PATCH 05/50] dump msg --- Actions/AL-Go-Helper.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index dea66970a..a5954bb7e 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -1880,6 +1880,7 @@ Function AnalyzeProjectDependencies { if ($projects.Count -eq 0) { # Last job, add solo projects + Write-Host "Adding solo projects to last build job" $thisJob += $soloProjects } From b164aeacf5ec2e8a9e30441c653d689d7794f3f3 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Thu, 25 Dec 2025 08:09:02 +0100 Subject: [PATCH 06/50] array --- Actions/AL-Go-Helper.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index a5954bb7e..ef23cfa26 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -1876,7 +1876,7 @@ Function AnalyzeProjectDependencies { $projects = @($projects | Where-Object { $thisJob -notcontains $_ }) # Do not build solo projects until the last job - $thisJob = $thisJob | Where-Object { $soloProjects -notcontains $_ } + $thisJob = @($thisJob | Where-Object { $soloProjects -notcontains $_ }) if ($projects.Count -eq 0) { # Last job, add solo projects From 45127f4c93105fcc53a079cdace3ddd50891d56c Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Fri, 26 Dec 2025 22:02:36 +0100 Subject: [PATCH 07/50] push to ghcr --- Actions/AL-Go-Helper.ps1 | 3 ++- Actions/RunPipeline/RunPipeline.ps1 | 21 +++++++++++++++++-- .../AppSource App/.github/workflows/CICD.yaml | 2 +- .../.github/workflows/_BuildALGoProject.yaml | 2 +- .../.github/workflows/CICD.yaml | 2 +- .../.github/workflows/_BuildALGoProject.yaml | 2 +- 6 files changed, 25 insertions(+), 7 deletions(-) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index ef23cfa26..fafa2e5b3 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -1784,8 +1784,9 @@ Function AnalyzeProjectDependencies { # } # } - # First determine projects, which no other project depends on - these should be build last + # First determine projects, which no other project depends on - these should be build in the last job # There is no reason for other jobs running in parallel to wait for these projects to be built + # One example of this is test only jobs, where compilation is done using compilerfolders on linux, and test jobs are postponed until all compilation jobs are done $soloProjects = @($projects | Where-Object { $isSolo = $true foreach($otherProject in $projects) { diff --git a/Actions/RunPipeline/RunPipeline.ps1 b/Actions/RunPipeline/RunPipeline.ps1 index 9b359bfb9..da0a82126 100644 --- a/Actions/RunPipeline/RunPipeline.ps1 +++ b/Actions/RunPipeline/RunPipeline.ps1 @@ -300,8 +300,19 @@ try { $additionalCountries = $settings.additionalCountries - $imageName = "" - if (-not $gitHubHostedRunner) { + $fullImageName = '' + $imageName = '' + if ($gitHubHostedRunner) { + $imageName = $settings.cacheImageName + if (!$imageName.Contains(':')) { + $appUri = [Uri]::new($artifact) + $imageName += ":$($appUri.AbsolutePath.ToLowerInvariant().Replace('/','-').TrimStart('-'))" + } + "$token" | docker login ghcr.io -u freddydk --password-stdin + $fullImageName = "ghcr.io/Freddy-DK/$imageName" + docker pull $fullImageName || true + } + else { $imageName = $settings.cacheImageName if ($imageName) { Write-Host "::group::Flush ContainerHelper Cache" @@ -560,6 +571,12 @@ try { -appBuild $appBuild -appRevision $appRevision ` -uninstallRemovedApps + if ($fullImageName) { + Write-Host "Push updated cache image $fullImageName" + docker tag $imageName $fullImageName + docker push $fullImageName + } + if ($containerBaseFolder) { Write-Host "Copy artifacts and build output back from build container" $destFolder = Join-Path $ENV:GITHUB_WORKSPACE $project diff --git a/Templates/AppSource App/.github/workflows/CICD.yaml b/Templates/AppSource App/.github/workflows/CICD.yaml index f0468361d..fef8fa9ae 100644 --- a/Templates/AppSource App/.github/workflows/CICD.yaml +++ b/Templates/AppSource App/.github/workflows/CICD.yaml @@ -19,7 +19,7 @@ permissions: id-token: write pages: read security-events: write - packages: read + packages: write env: workflowDepth: 1 diff --git a/Templates/AppSource App/.github/workflows/_BuildALGoProject.yaml b/Templates/AppSource App/.github/workflows/_BuildALGoProject.yaml index 14cb2316f..b3c6077f2 100644 --- a/Templates/AppSource App/.github/workflows/_BuildALGoProject.yaml +++ b/Templates/AppSource App/.github/workflows/_BuildALGoProject.yaml @@ -82,7 +82,7 @@ permissions: actions: read contents: read id-token: write - packages: read + packages: write env: ALGoOrgSettings: ${{ vars.ALGoOrgSettings }} diff --git a/Templates/Per Tenant Extension/.github/workflows/CICD.yaml b/Templates/Per Tenant Extension/.github/workflows/CICD.yaml index 2b18a4b83..eb708fe47 100644 --- a/Templates/Per Tenant Extension/.github/workflows/CICD.yaml +++ b/Templates/Per Tenant Extension/.github/workflows/CICD.yaml @@ -19,7 +19,7 @@ permissions: id-token: write pages: read security-events: write - packages: read + packages: write env: workflowDepth: 1 diff --git a/Templates/Per Tenant Extension/.github/workflows/_BuildALGoProject.yaml b/Templates/Per Tenant Extension/.github/workflows/_BuildALGoProject.yaml index 14cb2316f..b3c6077f2 100644 --- a/Templates/Per Tenant Extension/.github/workflows/_BuildALGoProject.yaml +++ b/Templates/Per Tenant Extension/.github/workflows/_BuildALGoProject.yaml @@ -82,7 +82,7 @@ permissions: actions: read contents: read id-token: write - packages: read + packages: write env: ALGoOrgSettings: ${{ vars.ALGoOrgSettings }} From 969a48e54a7128cb119966fe1a3023fa0d92ff29 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Fri, 26 Dec 2025 22:04:56 +0100 Subject: [PATCH 08/50] pull --- Templates/AppSource App/.github/workflows/CICD.yaml | 2 +- .../AppSource App/.github/workflows/_BuildALGoProject.yaml | 2 +- Templates/Per Tenant Extension/.github/workflows/CICD.yaml | 2 +- .../.github/workflows/_BuildALGoProject.yaml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Templates/AppSource App/.github/workflows/CICD.yaml b/Templates/AppSource App/.github/workflows/CICD.yaml index fef8fa9ae..f0468361d 100644 --- a/Templates/AppSource App/.github/workflows/CICD.yaml +++ b/Templates/AppSource App/.github/workflows/CICD.yaml @@ -19,7 +19,7 @@ permissions: id-token: write pages: read security-events: write - packages: write + packages: read env: workflowDepth: 1 diff --git a/Templates/AppSource App/.github/workflows/_BuildALGoProject.yaml b/Templates/AppSource App/.github/workflows/_BuildALGoProject.yaml index b3c6077f2..14cb2316f 100644 --- a/Templates/AppSource App/.github/workflows/_BuildALGoProject.yaml +++ b/Templates/AppSource App/.github/workflows/_BuildALGoProject.yaml @@ -82,7 +82,7 @@ permissions: actions: read contents: read id-token: write - packages: write + packages: read env: ALGoOrgSettings: ${{ vars.ALGoOrgSettings }} diff --git a/Templates/Per Tenant Extension/.github/workflows/CICD.yaml b/Templates/Per Tenant Extension/.github/workflows/CICD.yaml index eb708fe47..2b18a4b83 100644 --- a/Templates/Per Tenant Extension/.github/workflows/CICD.yaml +++ b/Templates/Per Tenant Extension/.github/workflows/CICD.yaml @@ -19,7 +19,7 @@ permissions: id-token: write pages: read security-events: write - packages: write + packages: read env: workflowDepth: 1 diff --git a/Templates/Per Tenant Extension/.github/workflows/_BuildALGoProject.yaml b/Templates/Per Tenant Extension/.github/workflows/_BuildALGoProject.yaml index b3c6077f2..14cb2316f 100644 --- a/Templates/Per Tenant Extension/.github/workflows/_BuildALGoProject.yaml +++ b/Templates/Per Tenant Extension/.github/workflows/_BuildALGoProject.yaml @@ -82,7 +82,7 @@ permissions: actions: read contents: read id-token: write - packages: write + packages: read env: ALGoOrgSettings: ${{ vars.ALGoOrgSettings }} From 55ad671b397ba3d94e50155bd19e16e044f23526 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Fri, 26 Dec 2025 22:22:57 +0100 Subject: [PATCH 09/50] pull --- Actions/RunPipeline/RunPipeline.ps1 | 51 +++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/Actions/RunPipeline/RunPipeline.ps1 b/Actions/RunPipeline/RunPipeline.ps1 index da0a82126..87f1c7fd8 100644 --- a/Actions/RunPipeline/RunPipeline.ps1 +++ b/Actions/RunPipeline/RunPipeline.ps1 @@ -300,17 +300,17 @@ try { $additionalCountries = $settings.additionalCountries - $fullImageName = '' - $imageName = '' + $imageName = "" if ($gitHubHostedRunner) { $imageName = $settings.cacheImageName - if (!$imageName.Contains(':')) { - $appUri = [Uri]::new($artifact) - $imageName += ":$($appUri.AbsolutePath.ToLowerInvariant().Replace('/','-').TrimStart('-'))" - } - "$token" | docker login ghcr.io -u freddydk --password-stdin + $os = (Get-CimInstance Win32_OperatingSystem) + $UBR = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name UBR).UBR + $hostOsVersion = [System.Version]::Parse("$($os.Version).$UBR") + $appUri = [Uri]::new($settings.artifact) + $imageName = "businesscentral:$hostOsVersion-$($appUri.AbsolutePath.ToLowerInvariant().Replace('/','-').TrimStart('-'))" $fullImageName = "ghcr.io/Freddy-DK/$imageName" - docker pull $fullImageName || true + "$token" | docker login ghcr.io -u freddydk --password-stdin + docker pull $imageName || true } else { $imageName = $settings.cacheImageName @@ -320,6 +320,35 @@ try { Write-Host "::endgroup::" } } + + + + + + + + + + $fullImageName = "" + $imageName = "" + if ($gitHubHostedRunner) { + $imageName = $settings.cacheImageName + if (!$imageName.Contains(':')) { + $appUri = [Uri]::new($artifact) + $imageName += ":$($appUri.AbsolutePath.ToLowerInvariant().Replace('/','-').TrimStart('-'))" + } + "$token" | docker login ghcr.io -u freddydk --password-stdin + $fullImageName = "ghcr.io/Freddy-DK/$imageName" + docker pull $fullImageName || true + } + + + + + + + + $authContext = $null $environmentName = "" $CreateRuntimePackages = $false @@ -571,12 +600,6 @@ try { -appBuild $appBuild -appRevision $appRevision ` -uninstallRemovedApps - if ($fullImageName) { - Write-Host "Push updated cache image $fullImageName" - docker tag $imageName $fullImageName - docker push $fullImageName - } - if ($containerBaseFolder) { Write-Host "Copy artifacts and build output back from build container" $destFolder = Join-Path $ENV:GITHUB_WORKSPACE $project From a0755d6ff7eadd780081ecc1992e79aad6859d1c Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Fri, 26 Dec 2025 22:25:35 +0100 Subject: [PATCH 10/50] dump fullname --- Actions/RunPipeline/RunPipeline.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/Actions/RunPipeline/RunPipeline.ps1 b/Actions/RunPipeline/RunPipeline.ps1 index 87f1c7fd8..9e1f37f0f 100644 --- a/Actions/RunPipeline/RunPipeline.ps1 +++ b/Actions/RunPipeline/RunPipeline.ps1 @@ -309,6 +309,7 @@ try { $appUri = [Uri]::new($settings.artifact) $imageName = "businesscentral:$hostOsVersion-$($appUri.AbsolutePath.ToLowerInvariant().Replace('/','-').TrimStart('-'))" $fullImageName = "ghcr.io/Freddy-DK/$imageName" + Write-Host "----------------------------- $fullImageName -----------------------------" "$token" | docker login ghcr.io -u freddydk --password-stdin docker pull $imageName || true } From 80b189abbb4b4b6d5ac91810257df90b8a3c8853 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Fri, 26 Dec 2025 22:28:57 +0100 Subject: [PATCH 11/50] use full --- Actions/RunPipeline/RunPipeline.ps1 | 36 ++--------------------------- 1 file changed, 2 insertions(+), 34 deletions(-) diff --git a/Actions/RunPipeline/RunPipeline.ps1 b/Actions/RunPipeline/RunPipeline.ps1 index 9e1f37f0f..a9252535e 100644 --- a/Actions/RunPipeline/RunPipeline.ps1 +++ b/Actions/RunPipeline/RunPipeline.ps1 @@ -303,15 +303,12 @@ try { $imageName = "" if ($gitHubHostedRunner) { $imageName = $settings.cacheImageName - $os = (Get-CimInstance Win32_OperatingSystem) - $UBR = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name UBR).UBR - $hostOsVersion = [System.Version]::Parse("$($os.Version).$UBR") $appUri = [Uri]::new($settings.artifact) - $imageName = "businesscentral:$hostOsVersion-$($appUri.AbsolutePath.ToLowerInvariant().Replace('/','-').TrimStart('-'))" + $imageName = "$($imageName):$($appUri.AbsolutePath.ToLowerInvariant().Replace('/','-').TrimStart('-'))" $fullImageName = "ghcr.io/Freddy-DK/$imageName" Write-Host "----------------------------- $fullImageName -----------------------------" "$token" | docker login ghcr.io -u freddydk --password-stdin - docker pull $imageName || true + docker pull $fullImageName || true } else { $imageName = $settings.cacheImageName @@ -321,35 +318,6 @@ try { Write-Host "::endgroup::" } } - - - - - - - - - - $fullImageName = "" - $imageName = "" - if ($gitHubHostedRunner) { - $imageName = $settings.cacheImageName - if (!$imageName.Contains(':')) { - $appUri = [Uri]::new($artifact) - $imageName += ":$($appUri.AbsolutePath.ToLowerInvariant().Replace('/','-').TrimStart('-'))" - } - "$token" | docker login ghcr.io -u freddydk --password-stdin - $fullImageName = "ghcr.io/Freddy-DK/$imageName" - docker pull $fullImageName || true - } - - - - - - - - $authContext = $null $environmentName = "" $CreateRuntimePackages = $false From d261c93b180a29691e32dbbf8b56e2bbd5d949c8 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Sat, 27 Dec 2025 00:11:07 +0100 Subject: [PATCH 12/50] lower --- Actions/RunPipeline/RunPipeline.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Actions/RunPipeline/RunPipeline.ps1 b/Actions/RunPipeline/RunPipeline.ps1 index a9252535e..c7a01d154 100644 --- a/Actions/RunPipeline/RunPipeline.ps1 +++ b/Actions/RunPipeline/RunPipeline.ps1 @@ -305,7 +305,7 @@ try { $imageName = $settings.cacheImageName $appUri = [Uri]::new($settings.artifact) $imageName = "$($imageName):$($appUri.AbsolutePath.ToLowerInvariant().Replace('/','-').TrimStart('-'))" - $fullImageName = "ghcr.io/Freddy-DK/$imageName" + $fullImageName = "ghcr.io/freddy-dk/$imageName" Write-Host "----------------------------- $fullImageName -----------------------------" "$token" | docker login ghcr.io -u freddydk --password-stdin docker pull $fullImageName || true From c5ea8f310c111fb1009a1af9d93fc0937cc790be Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Sat, 27 Dec 2025 11:53:10 +0100 Subject: [PATCH 13/50] revert --- Actions/RunPipeline/RunPipeline.ps1 | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/Actions/RunPipeline/RunPipeline.ps1 b/Actions/RunPipeline/RunPipeline.ps1 index c7a01d154..9c94b8227 100644 --- a/Actions/RunPipeline/RunPipeline.ps1 +++ b/Actions/RunPipeline/RunPipeline.ps1 @@ -301,16 +301,7 @@ try { $additionalCountries = $settings.additionalCountries $imageName = "" - if ($gitHubHostedRunner) { - $imageName = $settings.cacheImageName - $appUri = [Uri]::new($settings.artifact) - $imageName = "$($imageName):$($appUri.AbsolutePath.ToLowerInvariant().Replace('/','-').TrimStart('-'))" - $fullImageName = "ghcr.io/freddy-dk/$imageName" - Write-Host "----------------------------- $fullImageName -----------------------------" - "$token" | docker login ghcr.io -u freddydk --password-stdin - docker pull $fullImageName || true - } - else { + if (!$gitHubHostedRunner) { $imageName = $settings.cacheImageName if ($imageName) { Write-Host "::group::Flush ContainerHelper Cache" From 371ab33a1d974e4fe06b135f2d10560c77a6e7aa Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Mon, 29 Dec 2025 08:19:45 +0100 Subject: [PATCH 14/50] use bhg containerhelper --- Actions/AL-Go-Helper.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index fafa2e5b3..b646655f3 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -27,7 +27,7 @@ $RepoSettingsFile = Join-Path '.github' 'AL-Go-Settings.json' $defaultCICDPushBranches = @( 'main', 'release/*', 'feature/*' ) [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'defaultCICDPullRequestBranches', Justification = 'False positive.')] $defaultCICDPullRequestBranches = @( 'main' ) -$defaultBcContainerHelperVersion = "https://github.com/freddydk/navcontainerhelper/archive/refs/heads/TestAppDependencies.zip" # Must be double quotes. Will be replaced by BcContainerHelperVersion if necessary in the deploy step - ex. "https://github.com/organization/navcontainerhelper/archive/refs/heads/branch.zip" +$defaultBcContainerHelperVersion = "https://github.com/freddydk/navcontainerhelper/archive/refs/heads/bhg.zip" # Must be double quotes. Will be replaced by BcContainerHelperVersion if necessary in the deploy step - ex. "https://github.com/organization/navcontainerhelper/archive/refs/heads/branch.zip" $notSecretProperties = @("Scopes","TenantId","BlobName","ContainerName","StorageAccountName","ServerUrl","ppUserName","GitHubAppClientId","EnvironmentName") $runAlPipelineOverrides = @( From ec1416278541ef618bc9c0d69221f2b6a516856c Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Mon, 29 Dec 2025 10:07:01 +0100 Subject: [PATCH 15/50] swallow errors --- Actions/PipelineCleanup/PipelineCleanup.ps1 | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Actions/PipelineCleanup/PipelineCleanup.ps1 b/Actions/PipelineCleanup/PipelineCleanup.ps1 index 81209b175..339cb8e76 100644 --- a/Actions/PipelineCleanup/PipelineCleanup.ps1 +++ b/Actions/PipelineCleanup/PipelineCleanup.ps1 @@ -3,10 +3,15 @@ [string] $project = "." ) -. (Join-Path -Path $PSScriptRoot -ChildPath "..\AL-Go-Helper.ps1" -Resolve) -DownloadAndImportBcContainerHelper +try { + . (Join-Path -Path $PSScriptRoot -ChildPath "..\AL-Go-Helper.ps1" -Resolve) + DownloadAndImportBcContainerHelper -if ($project -eq ".") { $project = "" } + if ($project -eq ".") { $project = "" } -$containerName = GetContainerName($project) -Remove-Bccontainer $containerName + $containerName = GetContainerName($project) + Remove-Bccontainer $containerName +} +catch { + Write-Host "Pipeline Cleanup failed: $($_.Exception.Message)" +} From 0b6e66f5047178dedb1c9da3e4bcad7cc447b197 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Mon, 29 Dec 2025 10:37:24 +0100 Subject: [PATCH 16/50] Only grab the latest version --- Actions/Github-Helper.psm1 | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Actions/Github-Helper.psm1 b/Actions/Github-Helper.psm1 index 53bcc1867..065971e18 100644 --- a/Actions/Github-Helper.psm1 +++ b/Actions/Github-Helper.psm1 @@ -1047,7 +1047,18 @@ function GetArtifactsFromWorkflowRun { continue } - $matchingArtifacts = @($matchingArtifacts) #enforce array + $matchingArtifacts = @($matchingArtifacts | ForEach-Object { + if ($_ -match '^(.*)-(\d+\.\d+\.\d+\.\d+)$') { + [PSCustomObject]@{ + Name = $Matches[1] + Version = [version]$Matches[2] + Full = $_ + } + } + } | Group-Object Name | ForEach-Object { + $_.Group | Sort-Object Version -Descending | Select-Object -First 1 + } | + Select-Object -ExpandProperty Full) foreach($artifact in $matchingArtifacts) { Write-Host "Found artifact $($artifact.name) (ID: $($artifact.id)) for mask $mask and project $project" From 515ee0e44e998f8f8419a83b80a648ce33ea4ca4 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Mon, 29 Dec 2025 10:42:58 +0100 Subject: [PATCH 17/50] dumps --- Actions/Github-Helper.psm1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Actions/Github-Helper.psm1 b/Actions/Github-Helper.psm1 index 065971e18..0f407d2d2 100644 --- a/Actions/Github-Helper.psm1 +++ b/Actions/Github-Helper.psm1 @@ -1047,6 +1047,8 @@ function GetArtifactsFromWorkflowRun { continue } + $matchingArtifacts | Out-Host + $matchingArtifacts = @($matchingArtifacts | ForEach-Object { if ($_ -match '^(.*)-(\d+\.\d+\.\d+\.\d+)$') { [PSCustomObject]@{ @@ -1060,6 +1062,8 @@ function GetArtifactsFromWorkflowRun { } | Select-Object -ExpandProperty Full) + $matchingArtifacts | Out-Host + foreach($artifact in $matchingArtifacts) { Write-Host "Found artifact $($artifact.name) (ID: $($artifact.id)) for mask $mask and project $project" From ad29d157a786ae0746dfef0c75b8d39057363629 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Mon, 29 Dec 2025 10:46:56 +0100 Subject: [PATCH 18/50] select Obj --- Actions/Github-Helper.psm1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Actions/Github-Helper.psm1 b/Actions/Github-Helper.psm1 index 0f407d2d2..8b2b52bab 100644 --- a/Actions/Github-Helper.psm1 +++ b/Actions/Github-Helper.psm1 @@ -1050,17 +1050,17 @@ function GetArtifactsFromWorkflowRun { $matchingArtifacts | Out-Host $matchingArtifacts = @($matchingArtifacts | ForEach-Object { - if ($_ -match '^(.*)-(\d+\.\d+\.\d+\.\d+)$') { + if ($_.name -match '^(.*)-(\d+\.\d+\.\d+\.\d+)$') { [PSCustomObject]@{ Name = $Matches[1] Version = [version]$Matches[2] - Full = $_ + Obj = $_ } } } | Group-Object Name | ForEach-Object { $_.Group | Sort-Object Version -Descending | Select-Object -First 1 } | - Select-Object -ExpandProperty Full) + Select-Object -ExpandProperty Obj) $matchingArtifacts | Out-Host From b402ad0feec59c94d0a8333ad14ad1eb53923db7 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Mon, 29 Dec 2025 10:59:51 +0100 Subject: [PATCH 19/50] Grab latest version --- Actions/Github-Helper.psm1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Actions/Github-Helper.psm1 b/Actions/Github-Helper.psm1 index 8b2b52bab..2bdd736f4 100644 --- a/Actions/Github-Helper.psm1 +++ b/Actions/Github-Helper.psm1 @@ -1047,8 +1047,10 @@ function GetArtifactsFromWorkflowRun { continue } - $matchingArtifacts | Out-Host - + # If there are reruns of the build we found, we might see artifacts like: + # Test DBC-BHG-SAF-T-main-TestApps-1.0.48.0 + # Test DBC-BHG-SAF-T-main-TestApps-1.0.48.1 + # We want to keep only the latest version of each artifact (based on the last segment of the version) $matchingArtifacts = @($matchingArtifacts | ForEach-Object { if ($_.name -match '^(.*)-(\d+\.\d+\.\d+\.\d+)$') { [PSCustomObject]@{ @@ -1062,8 +1064,6 @@ function GetArtifactsFromWorkflowRun { } | Select-Object -ExpandProperty Obj) - $matchingArtifacts | Out-Host - foreach($artifact in $matchingArtifacts) { Write-Host "Found artifact $($artifact.name) (ID: $($artifact.id)) for mask $mask and project $project" From 7e94d8255a922f7d5ff60d11cda712d165fc0458 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Mon, 5 Jan 2026 09:41:34 +0100 Subject: [PATCH 20/50] revert --- Actions/RunPipeline/RunPipeline.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Actions/RunPipeline/RunPipeline.ps1 b/Actions/RunPipeline/RunPipeline.ps1 index 9c94b8227..9b359bfb9 100644 --- a/Actions/RunPipeline/RunPipeline.ps1 +++ b/Actions/RunPipeline/RunPipeline.ps1 @@ -301,7 +301,7 @@ try { $additionalCountries = $settings.additionalCountries $imageName = "" - if (!$gitHubHostedRunner) { + if (-not $gitHubHostedRunner) { $imageName = $settings.cacheImageName if ($imageName) { Write-Host "::group::Flush ContainerHelper Cache" From fdbb93f6c6e32417437688b872a5364fa2911e33 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Tue, 6 Jan 2026 05:33:29 +0100 Subject: [PATCH 21/50] better output --- Actions/AL-Go-Helper.ps1 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index b646655f3..cdc279f6e 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -1738,7 +1738,7 @@ Function AnalyzeProjectDependencies { # Get all apps in the project # Get all dependencies for the apps foreach($project in $projects) { - Write-Host "- Analyzing project: $project" + Write-Host -NoNewline "Analyzing project: $project, " $projectSettings = ReadSettings -project $project -baseFolder $baseFolder ResolveProjectFolders -baseFolder $baseFolder -project $project -projectSettings ([ref] $projectSettings) @@ -1754,7 +1754,7 @@ Function AnalyzeProjectDependencies { Pop-Location } - OutputMessageAndArray -Message "Folders containing apps" -arrayOfStrings $folders + OutputMessageAndArray -Message "folders containing apps" -arrayOfStrings $folders $unknownDependencies = @() $apps = @() @@ -1771,6 +1771,7 @@ Function AnalyzeProjectDependencies { "apps" = $apps "dependencies" = $dependenciesForProject } + Write-Host "AppDependencies for project $($appDependencies."$project" | CopnvertTo-Json -Compress)" } # AppDependencies is a hashtable with the following structure # $appDependencies = @{ From 956725988f7285fa0babd725106f5757cb7cd734 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Tue, 6 Jan 2026 05:35:41 +0100 Subject: [PATCH 22/50] spell --- Actions/AL-Go-Helper.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index cdc279f6e..70f9d5da8 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -1771,7 +1771,7 @@ Function AnalyzeProjectDependencies { "apps" = $apps "dependencies" = $dependenciesForProject } - Write-Host "AppDependencies for project $($appDependencies."$project" | CopnvertTo-Json -Compress)" + Write-Host "AppDependencies for project $($appDependencies."$project" | ConvertTo-Json -Compress)" } # AppDependencies is a hashtable with the following structure # $appDependencies = @{ From aeaf93f868a8d0c4429925798aa87e37f7c7615b Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Tue, 6 Jan 2026 05:46:45 +0100 Subject: [PATCH 23/50] only one project that builds the app is needed --- Actions/AL-Go-Helper.ps1 | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index 70f9d5da8..810cea6d7 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -1822,14 +1822,12 @@ Function AnalyzeProjectDependencies { # Loop through all dependencies and locate the projects, containing the apps for which the current project has a dependency $foundDependencies = @() foreach($dependency in $dependencies) { - # Find the project that contains the app for which the current project has a dependency - $depProjects = @($projects | Where-Object { $_ -ne $project -and $appDependencies."$_".apps -contains $dependency }) + # Find the first project that contains the app for which the current project has a dependency + $depProject = @($projects | Where-Object { $_ -ne $project -and $appDependencies."$_".apps -contains $dependency }) | Select-Object -First 1 # Add this project and all projects on which that project has a dependency to the list of dependencies for the current project - foreach($depProject in $depProjects) { - $foundDependencies += $depProject - if ($projectDependencies.Keys -contains $depProject) { - $foundDependencies += $projectDependencies."$depProject" - } + $foundDependencies += $depProject + if ($projectDependencies.Keys -contains $depProject) { + $foundDependencies += $projectDependencies."$depProject" } } $foundDependencies = @($foundDependencies | Select-Object -Unique) From 06737018d0d5c6dd62b2ee5254c11444a6b96236 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Tue, 6 Jan 2026 05:59:05 +0100 Subject: [PATCH 24/50] check previously build projects --- Actions/AL-Go-Helper.ps1 | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index 810cea6d7..965c0e67f 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -1808,6 +1808,7 @@ Function AnalyzeProjectDependencies { $no = 1 $projectsOrder = @() + $projectsBuild = @() Write-Host "Analyzing dependencies" while ($projects.Count -gt 0) { $thisJob = @() @@ -1823,11 +1824,14 @@ Function AnalyzeProjectDependencies { $foundDependencies = @() foreach($dependency in $dependencies) { # Find the first project that contains the app for which the current project has a dependency - $depProject = @($projects | Where-Object { $_ -ne $project -and $appDependencies."$_".apps -contains $dependency }) | Select-Object -First 1 + $depProject = @(($projectsBuild + $projects) | Where-Object { $_ -ne $project -and $appDependencies."$_".apps -contains $dependency }) | Select-Object -First 1 # Add this project and all projects on which that project has a dependency to the list of dependencies for the current project - $foundDependencies += $depProject - if ($projectDependencies.Keys -contains $depProject) { - $foundDependencies += $projectDependencies."$depProject" + # Only if the dependency wasn't already resolved by a previous build project + if ($projectsBuild -notcontains $depProject) { + $foundDependencies += $depProject + if ($projectDependencies.Keys -contains $depProject) { + $foundDependencies += $projectDependencies."$depProject" + } } } $foundDependencies = @($foundDependencies | Select-Object -Unique) @@ -1887,6 +1891,7 @@ Function AnalyzeProjectDependencies { Write-Host "#$no - build projects: $($thisJob -join ", ")" $projectsOrder += @{'projects' = $thisJob; 'projectsCount' = $thisJob.Count } + $projectsBuild += $thisJob $no++ } From 541b4657d6a1047243c3faa4a713b3c88aec6b2e Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Tue, 6 Jan 2026 06:06:02 +0100 Subject: [PATCH 25/50] just check previously build projects --- Actions/AL-Go-Helper.ps1 | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index 965c0e67f..da4f5aa7e 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -1823,11 +1823,15 @@ Function AnalyzeProjectDependencies { # Loop through all dependencies and locate the projects, containing the apps for which the current project has a dependency $foundDependencies = @() foreach($dependency in $dependencies) { - # Find the first project that contains the app for which the current project has a dependency - $depProject = @(($projectsBuild + $projects) | Where-Object { $_ -ne $project -and $appDependencies."$_".apps -contains $dependency }) | Select-Object -First 1 + $depProject = @($projectsBuild | Where-Object { $_ -ne $project -and $appDependencies."$_".apps -contains $dependency }) + if ($depProject.Count -gt 0) { + # Dependency already resolved by a previous build project + continue + } + # Find the project that contains the app for which the current project has a dependency + $depProjects = @($projects | Where-Object { $_ -ne $project -and $appDependencies."$_".apps -contains $dependency }) # Add this project and all projects on which that project has a dependency to the list of dependencies for the current project - # Only if the dependency wasn't already resolved by a previous build project - if ($projectsBuild -notcontains $depProject) { + foreach($depProject in $depProjects) { $foundDependencies += $depProject if ($projectDependencies.Keys -contains $depProject) { $foundDependencies += $projectDependencies."$depProject" From a698be74fc40482609abb8def15ed217cac9023e Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Tue, 6 Jan 2026 06:09:59 +0100 Subject: [PATCH 26/50] just check --- Actions/AL-Go-Helper.ps1 | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index da4f5aa7e..e2a716673 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -1808,7 +1808,6 @@ Function AnalyzeProjectDependencies { $no = 1 $projectsOrder = @() - $projectsBuild = @() Write-Host "Analyzing dependencies" while ($projects.Count -gt 0) { $thisJob = @() @@ -1823,9 +1822,9 @@ Function AnalyzeProjectDependencies { # Loop through all dependencies and locate the projects, containing the apps for which the current project has a dependency $foundDependencies = @() foreach($dependency in $dependencies) { - $depProject = @($projectsBuild | Where-Object { $_ -ne $project -and $appDependencies."$_".apps -contains $dependency }) + # Check whether dependency is already resolved by a previous build project + $depProject = @($projectsOrder | ForEach-Object { $_.Projects | Where-Object { $_ -ne $project -and $appDependencies."$_".apps -contains $dependency } }) if ($depProject.Count -gt 0) { - # Dependency already resolved by a previous build project continue } # Find the project that contains the app for which the current project has a dependency @@ -1895,7 +1894,6 @@ Function AnalyzeProjectDependencies { Write-Host "#$no - build projects: $($thisJob -join ", ")" $projectsOrder += @{'projects' = $thisJob; 'projectsCount' = $thisJob.Count } - $projectsBuild += $thisJob $no++ } From 2de55ca499a90f53b18baccd18f8e6b214196adc Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Tue, 6 Jan 2026 08:32:59 +0100 Subject: [PATCH 27/50] try --- Actions/AL-Go-Helper.ps1 | 61 +++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 22 deletions(-) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index e2a716673..93e2a50f7 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -1788,26 +1788,27 @@ Function AnalyzeProjectDependencies { # First determine projects, which no other project depends on - these should be build in the last job # There is no reason for other jobs running in parallel to wait for these projects to be built # One example of this is test only jobs, where compilation is done using compilerfolders on linux, and test jobs are postponed until all compilation jobs are done - $soloProjects = @($projects | Where-Object { - $isSolo = $true - foreach($otherProject in $projects) { - if ($otherProject -ne $_) { - $otherDependencies = $appDependencies."$otherProject".dependencies - foreach($dependency in $otherDependencies) { - if ($appDependencies."$_".apps -contains $dependency) { - $isSolo = $false - } - } - } - } - return $isSolo - }) - if ($soloProjects.Count -gt 0) { - Write-Host "Solo projects found (no other project depends on them): $($soloProjects -join ", ")" - } + #$soloProjects = @($projects | Where-Object { + # $isSolo = $true + # foreach($otherProject in $projects) { + # if ($otherProject -ne $_) { + # $otherDependencies = $appDependencies."$otherProject".dependencies + # foreach($dependency in $otherDependencies) { + # if ($appDependencies."$_".apps -contains $dependency) { + # $isSolo = $false + # } + # } + # } + # } + # return $isSolo + #}) + #if ($soloProjects.Count -gt 0) { + # Write-Host "Solo projects found (no other project depends on them): $($soloProjects -join ", ")" + #} $no = 1 $projectsOrder = @() + $jobsWithoutDependants = @() Write-Host "Analyzing dependencies" while ($projects.Count -gt 0) { $thisJob = @() @@ -1880,15 +1881,31 @@ Function AnalyzeProjectDependencies { throw "Circular project reference encountered, cannot determine build order" } + # Check whether any of the projects in $thisJob can be built later (no remaining dependencies) + $jobsWithoutDependants += @($thisJob | Where-Object { + $hasRemainingDependencies = $false + $dependencies = $appDependencies."$_".dependencies + foreach($dependency in $dependencies) { + $depProjects = @($projects | Where-Object { $_ -ne $_ -and $appDependencies."$_".apps -contains $dependency }) + if ($depProjects.Count -gt 0) { + $hasRemainingDependencies = $true + } + } + if (!$hasRemainingDependencies) { + Write-Host "Project $_ has no remaining dependendants, can be built later" + } + return -not $hasRemainingDependencies + }) + $projects = @($projects | Where-Object { $thisJob -notcontains $_ }) - # Do not build solo projects until the last job - $thisJob = @($thisJob | Where-Object { $soloProjects -notcontains $_ }) + # Do not build jobs without dependencies until the last job + $thisJob = @($thisJob | Where-Object { $jobsWithoutDependants -notcontains $_ }) if ($projects.Count -eq 0) { - # Last job, add solo projects - Write-Host "Adding solo projects to last build job" - $thisJob += $soloProjects + # Last job, add jobs without dependendants + Write-Host "Adding jobs without dependendants to last build job" + $thisJob += $jobsWithoutDependants } Write-Host "#$no - build projects: $($thisJob -join ", ")" From 27c6a1bb94dd02551adfb6ec79254458478deb0f Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Tue, 6 Jan 2026 08:43:07 +0100 Subject: [PATCH 28/50] recalc --- Actions/AL-Go-Helper.ps1 | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index 93e2a50f7..d332ca31a 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -1883,18 +1883,21 @@ Function AnalyzeProjectDependencies { # Check whether any of the projects in $thisJob can be built later (no remaining dependencies) $jobsWithoutDependants += @($thisJob | Where-Object { - $hasRemainingDependencies = $false - $dependencies = $appDependencies."$_".dependencies - foreach($dependency in $dependencies) { - $depProjects = @($projects | Where-Object { $_ -ne $_ -and $appDependencies."$_".apps -contains $dependency }) - if ($depProjects.Count -gt 0) { - $hasRemainingDependencies = $true + $hasRemainingDependendants = $false + foreach($otherProject in $projects) { + if ($otherProject -ne $_) { + $otherDependencies = $appDependencies."$otherProject".dependencies + foreach($dependency in $otherDependencies) { + if ($appDependencies."$_".apps -contains $dependency) { + $hasRemainingDependendants = $true + } + } } } - if (!$hasRemainingDependencies) { + if (!$hasRemainingDependendants) { Write-Host "Project $_ has no remaining dependendants, can be built later" } - return -not $hasRemainingDependencies + return -not $hasRemainingDependendants }) $projects = @($projects | Where-Object { $thisJob -notcontains $_ }) From e823b151a6bf53070c844e6f517a59b76e02e6fb Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Tue, 6 Jan 2026 10:57:35 +0100 Subject: [PATCH 29/50] check built --- Actions/AL-Go-Helper.ps1 | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index d332ca31a..953161301 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -1881,12 +1881,17 @@ Function AnalyzeProjectDependencies { throw "Circular project reference encountered, cannot determine build order" } + $projects = @($projects | Where-Object { $thisJob -notcontains $_ }) + # Check whether any of the projects in $thisJob can be built later (no remaining dependencies) $jobsWithoutDependants += @($thisJob | Where-Object { $hasRemainingDependendants = $false foreach($otherProject in $projects) { if ($otherProject -ne $_) { - $otherDependencies = $appDependencies."$otherProject".dependencies + # Grab dependencies from other project, which haven't been build yet + $otherDependencies = $appDependencies."$otherProject".dependencies | Where-Object { + $projects -contains $_ + } foreach($dependency in $otherDependencies) { if ($appDependencies."$_".apps -contains $dependency) { $hasRemainingDependendants = $true @@ -1900,8 +1905,6 @@ Function AnalyzeProjectDependencies { return -not $hasRemainingDependendants }) - $projects = @($projects | Where-Object { $thisJob -notcontains $_ }) - # Do not build jobs without dependencies until the last job $thisJob = @($thisJob | Where-Object { $jobsWithoutDependants -notcontains $_ }) From b674381b4c1fc67a2d44d5bad6bafed90e267d2e Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Tue, 6 Jan 2026 11:15:38 +0100 Subject: [PATCH 30/50] check other --- Actions/AL-Go-Helper.ps1 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index 953161301..9bbac3d13 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -1881,8 +1881,6 @@ Function AnalyzeProjectDependencies { throw "Circular project reference encountered, cannot determine build order" } - $projects = @($projects | Where-Object { $thisJob -notcontains $_ }) - # Check whether any of the projects in $thisJob can be built later (no remaining dependencies) $jobsWithoutDependants += @($thisJob | Where-Object { $hasRemainingDependendants = $false @@ -1890,7 +1888,8 @@ Function AnalyzeProjectDependencies { if ($otherProject -ne $_) { # Grab dependencies from other project, which haven't been build yet $otherDependencies = $appDependencies."$otherProject".dependencies | Where-Object { - $projects -contains $_ + $dependency = $_ + return (-not ($projectsOrder | ForEach-Object { $_.Projects | Where-Object { $_ -eq $dependency } })) } foreach($dependency in $otherDependencies) { if ($appDependencies."$_".apps -contains $dependency) { @@ -1905,6 +1904,8 @@ Function AnalyzeProjectDependencies { return -not $hasRemainingDependendants }) + $projects = @($projects | Where-Object { $thisJob -notcontains $_ }) + # Do not build jobs without dependencies until the last job $thisJob = @($thisJob | Where-Object { $jobsWithoutDependants -notcontains $_ }) From 6b3ab8dec14a7ccbfed77d0cba00c72b9dbae97d Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Tue, 6 Jan 2026 11:33:05 +0100 Subject: [PATCH 31/50] dumps --- Actions/AL-Go-Helper.ps1 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index 9bbac3d13..6ef0eb75e 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -1882,17 +1882,22 @@ Function AnalyzeProjectDependencies { } # Check whether any of the projects in $thisJob can be built later (no remaining dependencies) + Write-Host "------------------ CHECK JOBS WITHOUT REMAINING DEPENDANTS ------------------" $jobsWithoutDependants += @($thisJob | Where-Object { $hasRemainingDependendants = $false foreach($otherProject in $projects) { if ($otherProject -ne $_) { + Write-Host "Check Other project $otherProject" # Grab dependencies from other project, which haven't been build yet $otherDependencies = $appDependencies."$otherProject".dependencies | Where-Object { $dependency = $_ - return (-not ($projectsOrder | ForEach-Object { $_.Projects | Where-Object { $_ -eq $dependency } })) + $alreadyBuilt = ($projectsOrder | ForEach-Object { $_.Projects | Where-Object { $_ -eq $dependency } }) + return -not $alreadyBuilt } + Write-Host "Other project $otherProject has unbuilt dependencies: $($otherDependencies -join ", ")" foreach($dependency in $otherDependencies) { if ($appDependencies."$_".apps -contains $dependency) { + Write-Host "Project $otherProject is still a dependency for project $_" $hasRemainingDependendants = $true } } From 8c99adccc0decbd298626de75efa224dc832c1c2 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Tue, 6 Jan 2026 11:53:24 +0100 Subject: [PATCH 32/50] check alreadybuilt --- Actions/AL-Go-Helper.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index 6ef0eb75e..edd709dd9 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -1883,7 +1883,7 @@ Function AnalyzeProjectDependencies { # Check whether any of the projects in $thisJob can be built later (no remaining dependencies) Write-Host "------------------ CHECK JOBS WITHOUT REMAINING DEPENDANTS ------------------" - $jobsWithoutDependants += @($thisJob | Where-Object { + $projectsWithoutDependants += @($thisJob | Where-Object { $hasRemainingDependendants = $false foreach($otherProject in $projects) { if ($otherProject -ne $_) { @@ -1891,7 +1891,7 @@ Function AnalyzeProjectDependencies { # Grab dependencies from other project, which haven't been build yet $otherDependencies = $appDependencies."$otherProject".dependencies | Where-Object { $dependency = $_ - $alreadyBuilt = ($projectsOrder | ForEach-Object { $_.Projects | Where-Object { $_ -eq $dependency } }) + $alreadyBuilt = ($projectsOrder | ForEach-Object { $_.Projects | Where-Object { $appDependencies."$_".apps -contains $dependency } }) return -not $alreadyBuilt } Write-Host "Other project $otherProject has unbuilt dependencies: $($otherDependencies -join ", ")" From c43f03a155078a57691a28f36575e53e78b26d9d Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Tue, 6 Jan 2026 12:01:00 +0100 Subject: [PATCH 33/50] correct dump --- Actions/AL-Go-Helper.ps1 | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index edd709dd9..bb6756e87 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -1881,13 +1881,11 @@ Function AnalyzeProjectDependencies { throw "Circular project reference encountered, cannot determine build order" } - # Check whether any of the projects in $thisJob can be built later (no remaining dependencies) - Write-Host "------------------ CHECK JOBS WITHOUT REMAINING DEPENDANTS ------------------" + # Check whether any of the projects in $thisJob can be built later (no remaining dependendants) $projectsWithoutDependants += @($thisJob | Where-Object { $hasRemainingDependendants = $false foreach($otherProject in $projects) { if ($otherProject -ne $_) { - Write-Host "Check Other project $otherProject" # Grab dependencies from other project, which haven't been build yet $otherDependencies = $appDependencies."$otherProject".dependencies | Where-Object { $dependency = $_ @@ -1897,7 +1895,7 @@ Function AnalyzeProjectDependencies { Write-Host "Other project $otherProject has unbuilt dependencies: $($otherDependencies -join ", ")" foreach($dependency in $otherDependencies) { if ($appDependencies."$_".apps -contains $dependency) { - Write-Host "Project $otherProject is still a dependency for project $_" + Write-Host "Project $_ is still a dependency for project $otherProject" $hasRemainingDependendants = $true } } From b58b310885ad24cc0ed6faaffd44a29f1a08b346 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Tue, 6 Jan 2026 12:09:37 +0100 Subject: [PATCH 34/50] use projectswithoutdependants --- Actions/AL-Go-Helper.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index bb6756e87..19dc8c1a8 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -1808,7 +1808,7 @@ Function AnalyzeProjectDependencies { $no = 1 $projectsOrder = @() - $jobsWithoutDependants = @() + $projectsWithoutDependants = @() Write-Host "Analyzing dependencies" while ($projects.Count -gt 0) { $thisJob = @() @@ -1910,12 +1910,12 @@ Function AnalyzeProjectDependencies { $projects = @($projects | Where-Object { $thisJob -notcontains $_ }) # Do not build jobs without dependencies until the last job - $thisJob = @($thisJob | Where-Object { $jobsWithoutDependants -notcontains $_ }) + $thisJob = @($thisJob | Where-Object { $projectsWithoutDependants -notcontains $_ }) if ($projects.Count -eq 0) { # Last job, add jobs without dependendants Write-Host "Adding jobs without dependendants to last build job" - $thisJob += $jobsWithoutDependants + $thisJob += $projectsWithoutDependants } Write-Host "#$no - build projects: $($thisJob -join ", ")" From acee7d5ccfe99384f5ae2b47de96a67675589c94 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Tue, 6 Jan 2026 12:28:21 +0100 Subject: [PATCH 35/50] remove comment --- Actions/AL-Go-Helper.ps1 | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index 19dc8c1a8..cc0c81947 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -1785,29 +1785,10 @@ Function AnalyzeProjectDependencies { # } # } - # First determine projects, which no other project depends on - these should be build in the last job - # There is no reason for other jobs running in parallel to wait for these projects to be built - # One example of this is test only jobs, where compilation is done using compilerfolders on linux, and test jobs are postponed until all compilation jobs are done - #$soloProjects = @($projects | Where-Object { - # $isSolo = $true - # foreach($otherProject in $projects) { - # if ($otherProject -ne $_) { - # $otherDependencies = $appDependencies."$otherProject".dependencies - # foreach($dependency in $otherDependencies) { - # if ($appDependencies."$_".apps -contains $dependency) { - # $isSolo = $false - # } - # } - # } - # } - # return $isSolo - #}) - #if ($soloProjects.Count -gt 0) { - # Write-Host "Solo projects found (no other project depends on them): $($soloProjects -join ", ")" - #} - $no = 1 $projectsOrder = @() + # Collect projects without dependants, which can be build later + # This is done to collect avoid building projects at an earlier stage than needed and increase the time until next job subsequently $projectsWithoutDependants = @() Write-Host "Analyzing dependencies" while ($projects.Count -gt 0) { From 7a11bbe9e2ba4258ca2e0829d4b56efd24603b0a Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Tue, 6 Jan 2026 12:54:51 +0100 Subject: [PATCH 36/50] try old build mechanism --- Actions/AL-Go-Helper.ps1 | 56 ++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index cc0c81947..92b0e968b 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -1805,10 +1805,10 @@ Function AnalyzeProjectDependencies { $foundDependencies = @() foreach($dependency in $dependencies) { # Check whether dependency is already resolved by a previous build project - $depProject = @($projectsOrder | ForEach-Object { $_.Projects | Where-Object { $_ -ne $project -and $appDependencies."$_".apps -contains $dependency } }) - if ($depProject.Count -gt 0) { - continue - } +# $depProject = @($projectsOrder | ForEach-Object { $_.Projects | Where-Object { $_ -ne $project -and $appDependencies."$_".apps -contains $dependency } }) +# if ($depProject.Count -gt 0) { +# continue +# } # Find the project that contains the app for which the current project has a dependency $depProjects = @($projects | Where-Object { $_ -ne $project -and $appDependencies."$_".apps -contains $dependency }) # Add this project and all projects on which that project has a dependency to the list of dependencies for the current project @@ -1863,30 +1863,30 @@ Function AnalyzeProjectDependencies { } # Check whether any of the projects in $thisJob can be built later (no remaining dependendants) - $projectsWithoutDependants += @($thisJob | Where-Object { - $hasRemainingDependendants = $false - foreach($otherProject in $projects) { - if ($otherProject -ne $_) { - # Grab dependencies from other project, which haven't been build yet - $otherDependencies = $appDependencies."$otherProject".dependencies | Where-Object { - $dependency = $_ - $alreadyBuilt = ($projectsOrder | ForEach-Object { $_.Projects | Where-Object { $appDependencies."$_".apps -contains $dependency } }) - return -not $alreadyBuilt - } - Write-Host "Other project $otherProject has unbuilt dependencies: $($otherDependencies -join ", ")" - foreach($dependency in $otherDependencies) { - if ($appDependencies."$_".apps -contains $dependency) { - Write-Host "Project $_ is still a dependency for project $otherProject" - $hasRemainingDependendants = $true - } - } - } - } - if (!$hasRemainingDependendants) { - Write-Host "Project $_ has no remaining dependendants, can be built later" - } - return -not $hasRemainingDependendants - }) +# $projectsWithoutDependants += @($thisJob | Where-Object { +# $hasRemainingDependendants = $false +# foreach($otherProject in $projects) { +# if ($otherProject -ne $_) { +# # Grab dependencies from other project, which haven't been build yet +# $otherDependencies = $appDependencies."$otherProject".dependencies | Where-Object { +# $dependency = $_ +# $alreadyBuilt = ($projectsOrder | ForEach-Object { $_.Projects | Where-Object { $appDependencies."$_".apps -contains $dependency } }) +# return -not $alreadyBuilt +# } +# Write-Host "Other project $otherProject has unbuilt dependencies: $($otherDependencies -join ", ")" +# foreach($dependency in $otherDependencies) { +# if ($appDependencies."$_".apps -contains $dependency) { +# Write-Host "Project $_ is still a dependency for project $otherProject" +# $hasRemainingDependendants = $true +# } +# } +# } +# } +# if (!$hasRemainingDependendants) { +# Write-Host "Project $_ has no remaining dependendants, can be built later" +# } +# return -not $hasRemainingDependendants +# }) $projects = @($projects | Where-Object { $thisJob -notcontains $_ }) From feabb735f30689c02175e97e20e64754a7259543 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Tue, 6 Jan 2026 19:49:12 +0100 Subject: [PATCH 37/50] sort projects --- Actions/AL-Go-Helper.ps1 | 56 ++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index 92b0e968b..cc0c81947 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -1805,10 +1805,10 @@ Function AnalyzeProjectDependencies { $foundDependencies = @() foreach($dependency in $dependencies) { # Check whether dependency is already resolved by a previous build project -# $depProject = @($projectsOrder | ForEach-Object { $_.Projects | Where-Object { $_ -ne $project -and $appDependencies."$_".apps -contains $dependency } }) -# if ($depProject.Count -gt 0) { -# continue -# } + $depProject = @($projectsOrder | ForEach-Object { $_.Projects | Where-Object { $_ -ne $project -and $appDependencies."$_".apps -contains $dependency } }) + if ($depProject.Count -gt 0) { + continue + } # Find the project that contains the app for which the current project has a dependency $depProjects = @($projects | Where-Object { $_ -ne $project -and $appDependencies."$_".apps -contains $dependency }) # Add this project and all projects on which that project has a dependency to the list of dependencies for the current project @@ -1863,30 +1863,30 @@ Function AnalyzeProjectDependencies { } # Check whether any of the projects in $thisJob can be built later (no remaining dependendants) -# $projectsWithoutDependants += @($thisJob | Where-Object { -# $hasRemainingDependendants = $false -# foreach($otherProject in $projects) { -# if ($otherProject -ne $_) { -# # Grab dependencies from other project, which haven't been build yet -# $otherDependencies = $appDependencies."$otherProject".dependencies | Where-Object { -# $dependency = $_ -# $alreadyBuilt = ($projectsOrder | ForEach-Object { $_.Projects | Where-Object { $appDependencies."$_".apps -contains $dependency } }) -# return -not $alreadyBuilt -# } -# Write-Host "Other project $otherProject has unbuilt dependencies: $($otherDependencies -join ", ")" -# foreach($dependency in $otherDependencies) { -# if ($appDependencies."$_".apps -contains $dependency) { -# Write-Host "Project $_ is still a dependency for project $otherProject" -# $hasRemainingDependendants = $true -# } -# } -# } -# } -# if (!$hasRemainingDependendants) { -# Write-Host "Project $_ has no remaining dependendants, can be built later" -# } -# return -not $hasRemainingDependendants -# }) + $projectsWithoutDependants += @($thisJob | Where-Object { + $hasRemainingDependendants = $false + foreach($otherProject in $projects) { + if ($otherProject -ne $_) { + # Grab dependencies from other project, which haven't been build yet + $otherDependencies = $appDependencies."$otherProject".dependencies | Where-Object { + $dependency = $_ + $alreadyBuilt = ($projectsOrder | ForEach-Object { $_.Projects | Where-Object { $appDependencies."$_".apps -contains $dependency } }) + return -not $alreadyBuilt + } + Write-Host "Other project $otherProject has unbuilt dependencies: $($otherDependencies -join ", ")" + foreach($dependency in $otherDependencies) { + if ($appDependencies."$_".apps -contains $dependency) { + Write-Host "Project $_ is still a dependency for project $otherProject" + $hasRemainingDependendants = $true + } + } + } + } + if (!$hasRemainingDependendants) { + Write-Host "Project $_ has no remaining dependendants, can be built later" + } + return -not $hasRemainingDependendants + }) $projects = @($projects | Where-Object { $thisJob -notcontains $_ }) From 167d3d3f0ea72d43db5b0a963f092be32293f300 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Sun, 11 Jan 2026 06:07:27 +0100 Subject: [PATCH 38/50] Get branch for artifacts --- Actions/Github-Helper.psm1 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Actions/Github-Helper.psm1 b/Actions/Github-Helper.psm1 index 2bdd736f4..81ddafd6a 100644 --- a/Actions/Github-Helper.psm1 +++ b/Actions/Github-Helper.psm1 @@ -1029,6 +1029,10 @@ function GetArtifactsFromWorkflowRun { # Get sanitized project names (the way they appear in the artifact names) $projectArr = @(@($projects.Split(',')) | ForEach-Object { $_.Replace('\','_').Replace('/','_') }) + # Get branch used in workflowRun + $workflowRunInfo = (InvokeWebRequest -Headers $headers -Uri "$api_url/repos/$repository/actions/runs/$workflowRun").Content | ConvertFrom-Json + $branch = $workflowRunInfo.head_branch.Replace('\', '_').Replace('/', '_') + # Get the artifacts from the the workflow run while($true) { $artifactsURI = "$api_url/repos/$repository/actions/runs/$workflowRun/artifacts?per_page=$per_page&page=$page" @@ -1040,7 +1044,7 @@ function GetArtifactsFromWorkflowRun { } foreach($project in $projectArr) { - $artifactPattern = "$project-*-$mask-*" # e.g. "MyProject-*-Apps-*", format is: "project-branch-mask-version" + $artifactPattern = "$project-$branch-$mask-*" # e.g. "MyProject-*-Apps-*", format is: "project-branch-mask-version" $matchingArtifacts = @($artifacts.artifacts | Where-Object { $_.name -like $artifactPattern }) if ($matchingArtifacts.Count -eq 0) { From 09dd39db9984d9c6b86ab7fc8550a664902cf5e5 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Sun, 11 Jan 2026 06:08:31 +0100 Subject: [PATCH 39/50] dump branch --- Actions/Github-Helper.psm1 | 1 + 1 file changed, 1 insertion(+) diff --git a/Actions/Github-Helper.psm1 b/Actions/Github-Helper.psm1 index 81ddafd6a..20dded13a 100644 --- a/Actions/Github-Helper.psm1 +++ b/Actions/Github-Helper.psm1 @@ -1032,6 +1032,7 @@ function GetArtifactsFromWorkflowRun { # Get branch used in workflowRun $workflowRunInfo = (InvokeWebRequest -Headers $headers -Uri "$api_url/repos/$repository/actions/runs/$workflowRun").Content | ConvertFrom-Json $branch = $workflowRunInfo.head_branch.Replace('\', '_').Replace('/', '_') + Write-Host "Branch for workflow run $workflowRun is $branch" # Get the artifacts from the the workflow run while($true) { From 92d8916bf4b92a2d230b8faeed7bce1c3975d5b1 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Sun, 11 Jan 2026 07:53:31 +0100 Subject: [PATCH 40/50] comments --- Actions/Github-Helper.psm1 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Actions/Github-Helper.psm1 b/Actions/Github-Helper.psm1 index 20dded13a..b4664489b 100644 --- a/Actions/Github-Helper.psm1 +++ b/Actions/Github-Helper.psm1 @@ -1045,7 +1045,9 @@ function GetArtifactsFromWorkflowRun { } foreach($project in $projectArr) { - $artifactPattern = "$project-$branch-$mask-*" # e.g. "MyProject-*-Apps-*", format is: "project-branch-mask-version" + # e.g. "MyProject-main-Apps-*", format is: "project-branch-mask-version" + # Mask might include buildMode like TranslatedTestApps + $artifactPattern = "$project-$branch-$mask-*" $matchingArtifacts = @($artifacts.artifacts | Where-Object { $_.name -like $artifactPattern }) if ($matchingArtifacts.Count -eq 0) { From 13e36b867bbead75bc8f321dee4f8261a6350d8a Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Sun, 11 Jan 2026 08:09:00 +0100 Subject: [PATCH 41/50] sort pr builds --- Actions/Github-Helper.psm1 | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Actions/Github-Helper.psm1 b/Actions/Github-Helper.psm1 index b4664489b..ff937c554 100644 --- a/Actions/Github-Helper.psm1 +++ b/Actions/Github-Helper.psm1 @@ -1059,6 +1059,7 @@ function GetArtifactsFromWorkflowRun { # Test DBC-BHG-SAF-T-main-TestApps-1.0.48.1 # We want to keep only the latest version of each artifact (based on the last segment of the version) $matchingArtifacts = @($matchingArtifacts | ForEach-Object { + # Sort on version number object if ($_.name -match '^(.*)-(\d+\.\d+\.\d+\.\d+)$') { [PSCustomObject]@{ Name = $Matches[1] @@ -1066,6 +1067,14 @@ function GetArtifactsFromWorkflowRun { Obj = $_ } } + else { + # artifacts from PR builds doesn't match the versioning pattern but are sortable + [PSCustomObject]@{ + Name = $_.name + Version = $_.name + Obj = $_ + } + } } | Group-Object Name | ForEach-Object { $_.Group | Sort-Object Version -Descending | Select-Object -First 1 } | From 88031aef4e015a83a3597397f2a8b908b7b69954 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Thu, 15 Jan 2026 06:28:24 +0100 Subject: [PATCH 42/50] use trim --- Actions/Github-Helper.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Actions/Github-Helper.psm1 b/Actions/Github-Helper.psm1 index ff937c554..4b46d44e3 100644 --- a/Actions/Github-Helper.psm1 +++ b/Actions/Github-Helper.psm1 @@ -958,7 +958,7 @@ function FindLatestSuccessfulCICDRun { break } - $CICDRuns = @($workflowRuns.workflow_runs | Where-Object { $_.name -eq ' CI/CD' }) + $CICDRuns = @($workflowRuns.workflow_runs | Where-Object { $_.name.Trim() -eq 'CI/CD' }) foreach($CICDRun in $CICDRuns) { if($CICDRun.conclusion -eq 'success') { From 9d153ae0b7751e018691aa320aa2c7c093267772 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Sun, 18 Jan 2026 06:01:52 +0100 Subject: [PATCH 43/50] remove dump and fix comments --- Actions/AL-Go-Helper.ps1 | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index cc0c81947..3f4b2aca6 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -1771,7 +1771,6 @@ Function AnalyzeProjectDependencies { "apps" = $apps "dependencies" = $dependenciesForProject } - Write-Host "AppDependencies for project $($appDependencies."$project" | ConvertTo-Json -Compress)" } # AppDependencies is a hashtable with the following structure # $appDependencies = @{ @@ -1784,11 +1783,12 @@ Function AnalyzeProjectDependencies { # "dependencies" = @("appid7", "appid8") # } # } - $no = 1 $projectsOrder = @() # Collect projects without dependants, which can be build later # This is done to collect avoid building projects at an earlier stage than needed and increase the time until next job subsequently + # For every time we have determined a set of projects that can be build in parallel, we check whether any of these projects has no dependants + # If so, we remove these projects from the build order and add them at the end of the build order (by adding them to projectsWithoutDependants) $projectsWithoutDependants = @() Write-Host "Analyzing dependencies" while ($projects.Count -gt 0) { @@ -1888,14 +1888,15 @@ Function AnalyzeProjectDependencies { return -not $hasRemainingDependendants }) + # Remove projects in this job from the list of projects to be built (including the projects without dependants) $projects = @($projects | Where-Object { $thisJob -notcontains $_ }) - # Do not build jobs without dependencies until the last job + # Do not build jobs without dependendants until the last job, remove them from this job $thisJob = @($thisJob | Where-Object { $projectsWithoutDependants -notcontains $_ }) if ($projects.Count -eq 0) { - # Last job, add jobs without dependendants - Write-Host "Adding jobs without dependendants to last build job" + # Last job, add jobs without dependants + Write-Host "Adding jobs without dependants to last build job" $thisJob += $projectsWithoutDependants } From 6993edbc9238ba217c755fc74830024b480619c1 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Sun, 18 Jan 2026 06:25:49 +0100 Subject: [PATCH 44/50] release notes --- RELEASENOTES.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 50d56d70e..3cf8f147b 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -1,5 +1,8 @@ ### Issues +- Issue 2084 Multiple artifacts failure if you re-run failed jobs after flaky tests +- Issue 2085 Projects that doesn't contain both Apps and TestApps are wrongly seen as not built. +- Issue 2086 Postpone jobs, which doesn't have any dependants to the end of the build order. - Issue 2078 Workflows run since January 14th '26 have space before CI/CD removed - Issue 2070 Support public GitHub Packages feeds without requiring a Personal Access Token (PAT) - Issue 2004 PublishToAppSource workflow publishes multi-app repos in alphabetical order instead of dependency order From 716979eba6390e4af3057d74bdf42cb233f45e42 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Mon, 19 Jan 2026 06:10:21 +0100 Subject: [PATCH 45/50] Update Actions/AL-Go-Helper.ps1 Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Actions/AL-Go-Helper.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index 3f4b2aca6..82e0ddfcb 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -1786,7 +1786,7 @@ Function AnalyzeProjectDependencies { $no = 1 $projectsOrder = @() # Collect projects without dependants, which can be build later - # This is done to collect avoid building projects at an earlier stage than needed and increase the time until next job subsequently + # This is done to avoid building projects at an earlier stage than needed and increase the time until next job subsequently # For every time we have determined a set of projects that can be build in parallel, we check whether any of these projects has no dependants # If so, we remove these projects from the build order and add them at the end of the build order (by adding them to projectsWithoutDependants) $projectsWithoutDependants = @() From 7c4ca5d76f055652bcff04e758d1fd0c853435e7 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Mon, 19 Jan 2026 06:15:49 +0100 Subject: [PATCH 46/50] review --- Actions/AL-Go-Helper.ps1 | 34 +++++++++++++++++----------------- RELEASENOTES.md | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index 3f4b2aca6..32d1d8f33 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -1785,11 +1785,11 @@ Function AnalyzeProjectDependencies { # } $no = 1 $projectsOrder = @() - # Collect projects without dependants, which can be build later + # Collect projects without dependents, which can be build later # This is done to collect avoid building projects at an earlier stage than needed and increase the time until next job subsequently - # For every time we have determined a set of projects that can be build in parallel, we check whether any of these projects has no dependants - # If so, we remove these projects from the build order and add them at the end of the build order (by adding them to projectsWithoutDependants) - $projectsWithoutDependants = @() + # For every time we have determined a set of projects that can be build in parallel, we check whether any of these projects has no dependents + # If so, we remove these projects from the build order and add them at the end of the build order (by adding them to projectsWithoutDependents) + $projectsWithoutDependents = @() Write-Host "Analyzing dependencies" while ($projects.Count -gt 0) { $thisJob = @() @@ -1862,9 +1862,9 @@ Function AnalyzeProjectDependencies { throw "Circular project reference encountered, cannot determine build order" } - # Check whether any of the projects in $thisJob can be built later (no remaining dependendants) - $projectsWithoutDependants += @($thisJob | Where-Object { - $hasRemainingDependendants = $false + # Check whether any of the projects in $thisJob can be built later (no remaining dependents) + $projectsWithoutDependents += @($thisJob | Where-Object { + $hasRemainingDependents = $false foreach($otherProject in $projects) { if ($otherProject -ne $_) { # Grab dependencies from other project, which haven't been build yet @@ -1877,27 +1877,27 @@ Function AnalyzeProjectDependencies { foreach($dependency in $otherDependencies) { if ($appDependencies."$_".apps -contains $dependency) { Write-Host "Project $_ is still a dependency for project $otherProject" - $hasRemainingDependendants = $true + $hasRemainingDependents = $true } } } } - if (!$hasRemainingDependendants) { - Write-Host "Project $_ has no remaining dependendants, can be built later" + if (!$hasRemainingDependents) { + Write-Host "Project $_ has no remaining dependents, can be built later" } - return -not $hasRemainingDependendants + return -not $hasRemainingDependents }) - # Remove projects in this job from the list of projects to be built (including the projects without dependants) + # Remove projects in this job from the list of projects to be built (including the projects without dependents) $projects = @($projects | Where-Object { $thisJob -notcontains $_ }) - # Do not build jobs without dependendants until the last job, remove them from this job - $thisJob = @($thisJob | Where-Object { $projectsWithoutDependants -notcontains $_ }) + # Do not build jobs without dependents until the last job, remove them from this job + $thisJob = @($thisJob | Where-Object { $projectsWithoutDependents -notcontains $_ }) if ($projects.Count -eq 0) { - # Last job, add jobs without dependants - Write-Host "Adding jobs without dependants to last build job" - $thisJob += $projectsWithoutDependants + # Last job, add jobs without dependents + Write-Host "Adding jobs without dependents to last build job" + $thisJob += $projectsWithoutDependents } Write-Host "#$no - build projects: $($thisJob -join ", ")" diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 3cf8f147b..5b58ac6bb 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -2,7 +2,7 @@ - Issue 2084 Multiple artifacts failure if you re-run failed jobs after flaky tests - Issue 2085 Projects that doesn't contain both Apps and TestApps are wrongly seen as not built. -- Issue 2086 Postpone jobs, which doesn't have any dependants to the end of the build order. +- Issue 2086 Postpone jobs, which doesn't have any dependents to the end of the build order. - Issue 2078 Workflows run since January 14th '26 have space before CI/CD removed - Issue 2070 Support public GitHub Packages feeds without requiring a Personal Access Token (PAT) - Issue 2004 PublishToAppSource workflow publishes multi-app repos in alphabetical order instead of dependency order From 6098e23e79a34ae5d7b9e05a3285fbd9efac938c Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Mon, 19 Jan 2026 06:17:41 +0100 Subject: [PATCH 47/50] use preview --- Actions/AL-Go-Helper.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index 81e6a5c91..c99126c1f 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -27,7 +27,7 @@ $RepoSettingsFile = Join-Path '.github' 'AL-Go-Settings.json' $defaultCICDPushBranches = @( 'main', 'release/*', 'feature/*' ) [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'defaultCICDPullRequestBranches', Justification = 'False positive.')] $defaultCICDPullRequestBranches = @( 'main' ) -$defaultBcContainerHelperVersion = "https://github.com/freddydk/navcontainerhelper/archive/refs/heads/bhg.zip" # Must be double quotes. Will be replaced by BcContainerHelperVersion if necessary in the deploy step - ex. "https://github.com/organization/navcontainerhelper/archive/refs/heads/branch.zip" +$defaultBcContainerHelperVersion = "preview" # Must be double quotes. Will be replaced by BcContainerHelperVersion if necessary in the deploy step - ex. "https://github.com/organization/navcontainerhelper/archive/refs/heads/branch.zip" $notSecretProperties = @("Scopes","TenantId","BlobName","ContainerName","StorageAccountName","ServerUrl","ppUserName","GitHubAppClientId","EnvironmentName") $runAlPipelineOverrides = @( From 640923effc3cd6c810304358fbfbf652aedbfe3d Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Thu, 22 Jan 2026 03:53:07 +0100 Subject: [PATCH 48/50] Implement postponeProjectInBuildOrder setting --- Actions/.Modules/ReadSettings.psm1 | 3 ++- Actions/.Modules/settings.schema.json | 4 ++++ Actions/AL-Go-Helper.ps1 | 8 ++++++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Actions/.Modules/ReadSettings.psm1 b/Actions/.Modules/ReadSettings.psm1 index ab242c3ad..6945acacc 100644 --- a/Actions/.Modules/ReadSettings.psm1 +++ b/Actions/.Modules/ReadSettings.psm1 @@ -251,9 +251,10 @@ function GetDefaultSettings "reportSuppressedDiagnostics" = $false "workflowDefaultInputs" = @() "customALGoFiles" = [ordered]@{ - "filesToInclude" = @() + "filesToInclude" = @() "filesToExclude" = @() } + "postponeProjectInBuildOrder" = $false } } diff --git a/Actions/.Modules/settings.schema.json b/Actions/.Modules/settings.schema.json index eafcb7bb6..af08720d3 100644 --- a/Actions/.Modules/settings.schema.json +++ b/Actions/.Modules/settings.schema.json @@ -744,6 +744,10 @@ } } }, + "postponeProjectInBuildOrder": { + "type": "boolean", + "description": "Indicates whether the project can be postponed in the build order to optimize build times. See https://aka.ms/ALGoSettings#postponeProjectInBuildOrder" + }, "workflowDefaultInputs": { "type": "array", "items": { diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index c99126c1f..5c9775950 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -1737,10 +1737,14 @@ Function AnalyzeProjectDependencies { # Loop through all projects # Get all apps in the project # Get all dependencies for the apps + $projectsThatCanBePostponed = @() foreach($project in $projects) { Write-Host -NoNewline "Analyzing project: $project, " $projectSettings = ReadSettings -project $project -baseFolder $baseFolder + if ($projectSettings.postponeProjectInBuildOrder) { + $projectsThatCanBePostponed += $project + } ResolveProjectFolders -baseFolder $baseFolder -project $project -projectSettings ([ref] $projectSettings) # App folders are relative to the AL-Go project folder. Convert them to relative to the base folder @@ -1862,8 +1866,8 @@ Function AnalyzeProjectDependencies { throw "Circular project reference encountered, cannot determine build order" } - # Check whether any of the projects in $thisJob can be built later (no remaining dependents) - $projectsWithoutDependents += @($thisJob | Where-Object { + # Check whether any of the projects in $thisJob can be built later (has postponeProjectInBuildOrder set to true and no remaining dependents) + $projectsWithoutDependents += @($thisJob | Where-Object { $projectsThatCanBePostponed -contains $_ } | Where-Object { $hasRemainingDependents = $false foreach($otherProject in $projects) { if ($otherProject -ne $_) { From 9a19dfdd96b0f057ded540aef79103dc30483653 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Thu, 22 Jan 2026 15:58:55 +0100 Subject: [PATCH 49/50] add test for postpone --- Tests/DetermineProjectsToBuild.Test.ps1 | 125 ++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/Tests/DetermineProjectsToBuild.Test.ps1 b/Tests/DetermineProjectsToBuild.Test.ps1 index 8445567cc..575962910 100644 --- a/Tests/DetermineProjectsToBuild.Test.ps1 +++ b/Tests/DetermineProjectsToBuild.Test.ps1 @@ -747,6 +747,131 @@ Describe "Get-ProjectsToBuild" { { Get-ProjectsToBuild -baseFolder $baseFolder -maxBuildDepth 1 } | Should -Throw "The build depth is too deep, the maximum build depth is 1. You need to run 'Update AL-Go System Files' to update the workflows" } + It 'postpones projects if postponeProjectInBuildOrder is set to true' { + # Add three dependent projects + # Project 1 + # Project 2 depends on Project 1, has postponeProjectInBuildOrder set to true + # Project 3 depends on Project 1, has postponeProjectInBuildOrder set to true + # Project 4 depends on Project 2 + $dependecyAppFile = @{ id = '83fb8305-4079-415d-a25d-8132f0436fd1'; name = 'First App'; publisher = 'Contoso'; version = '1.0.0.0'; dependencies = @() } + New-Item -Path "$baseFolder/Project1/.AL-Go/settings.json" -type File -Force + New-Item -Path "$baseFolder/Project1/app/app.json" -Value (ConvertTo-Json $dependecyAppFile -Depth 10) -type File -Force + + $dependantAppFile = @{ id = '83fb8305-4079-415d-a25d-8132f0436fd2'; name = 'Second App'; publisher = 'Contoso'; version = '1.0.0.0'; dependencies = @(@{id = '83fb8305-4079-415d-a25d-8132f0436fd1'; name = 'First App'; publisher = 'Contoso'; version = '1.0.0.0'} ) } + New-Item -Path "$baseFolder/Project2/.AL-Go/settings.json" -type File -Force + @{ postponeProjectInBuildOrder = $true } | ConvertTo-Json -Depth 99 -Compress | Out-File (Join-Path $baseFolder "Project2/.AL-Go/settings.json") -Encoding UTF8 + New-Item -Path "$baseFolder/Project2/app/app.json" -Value (ConvertTo-Json $dependantAppFile -Depth 10) -type File -Force + + $dependantAppFile3 = @{ id = '83fb8305-4079-415d-a25d-8132f0436fd3'; name = 'Third App'; publisher = 'Contoso'; version = '1.0.0.0'; dependencies = @(@{id = '83fb8305-4079-415d-a25d-8132f0436fd1'; name = 'First App'; publisher = 'Contoso'; version = '1.0.0.0'} ) } + New-Item -Path "$baseFolder/Project3/.AL-Go/settings.json" -type File -Force + @{ postponeProjectInBuildOrder = $true } | ConvertTo-Json -Depth 99 -Compress | Out-File (Join-Path $baseFolder "Project3/.AL-Go/settings.json") -Encoding UTF8 + New-Item -Path "$baseFolder/Project3/app/app.json" -Value (ConvertTo-Json $dependantAppFile3 -Depth 10) -type File -Force + + $depedantAppFile4 = @{ id = '83fb8305-4079-415d-a25d-8132f0436fd4'; name = 'Fourth App'; publisher = 'Contoso'; version = '1.0.0.0'; dependencies = @(@{id = '83fb8305-4079-415d-a25d-8132f0436fd2'; name = 'Second App'; publisher = 'Contoso'; version = '1.0.0.0'} ) } + New-Item -Path "$baseFolder/Project4/.AL-Go/settings.json" -type File -Force + New-Item -Path "$baseFolder/Project4/app/app.json" -Value (ConvertTo-Json $depedantAppFile4 -Depth 10) -type File -Force + + #Add settings file + $alGoSettings = @{ fullBuildPatterns = @(); projects = @(); powerPlatformSolutionFolder = ''; useProjectDependencies = $true } + New-Item -Path "$baseFolder/.github" -type Directory -Force + $alGoSettings | ConvertTo-Json -Depth 99 -Compress | Out-File (Join-Path $baseFolder ".github/AL-Go-Settings.json") -Encoding UTF8 + + # Add settings as environment variable to simulate we've run ReadSettings + $env:Settings = ConvertTo-Json $alGoSettings -Depth 99 -Compress + + $allProjects, $modifiedProjects, $projectsToBuild, $projectDependencies, $buildOrder = Get-ProjectsToBuild -baseFolder $baseFolder + + $allProjects | Should -BeExactly @("Project1", "Project2", "Project3", "Project4") + $modifiedProjects | Should -BeExactly @() + $projectsToBuild | Should -BeExactly @('Project1', 'Project2', 'Project3', 'Project4') + + $projectDependencies | Should -BeOfType System.Collections.Hashtable + $projectDependencies['Project1'] | Should -BeExactly @() + $projectDependencies['Project2'] | Should -BeExactly @("Project1") + $projectDependencies['Project3'] | Should -BeExactly @("Project1") + $projectDependencies['Project4'] | Should -BeExactly @("Project2", "Project1") + + # Build order should have the following structure: + #[ + #{ + # "buildDimensions": [ + # { + # "projectName": "Project1", + # "buildMode": "Default", + # "project": "Project1", + # "githubRunnerShell": "powershell", + # "gitHubRunner": "\"windows-latest\"" + # }, + # ], + # "projectsCount": 1, + # "projects": [ + # "Project1" + # ] + #}, + #{ + # "buildDimensions": [ + # { + # "projectName": "Project2", + # "buildMode": "Default", + # "project": "Project2", + # "githubRunnerShell": "powershell", + # "gitHubRunner": "\"windows-latest\"" + # } + # ], + # "projectsCount": 1, + # "projects": [ + # "Project2" + # ] + #} + #{ + # "buildDimensions": [ + # { + # "projectName": "Project3", + # "buildMode": "Default", + # "project": "Project3", + # "githubRunnerShell": "powershell", + # "gitHubRunner": "\"windows-latest\"" + # }, + # { + # "projectName": "Project4", + # "buildMode": "Default", + # "project": "Project4", + # "githubRunnerShell": "powershell", + # "gitHubRunner": "\"windows-latest\"" + # } + # ], + # "projectsCount": 2, + # "projects": [ + # "Project3", + # "Project4" + # ] + #} + #] + $buildOrder.Count | Should -BeExactly 3 + $buildOrder[0] | Should -BeOfType System.Collections.Hashtable + $buildOrder[0].projects | Should -BeExactly @("Project1") + $buildOrder[0].projectsCount | Should -BeExactly 1 + $buildOrder[0].buildDimensions.Count | Should -BeExactly 1 + $buildOrder[0].buildDimensions[0].buildMode | Should -BeExactly "Default" + $buildOrder[0].buildDimensions[0].project | Should -BeExactly "Project1" + + $buildOrder[1] | Should -BeOfType System.Collections.Hashtable + $buildOrder[1].projects | Should -BeExactly @("Project2") + $buildOrder[1].projectsCount | Should -BeExactly 1 + $buildOrder[1].buildDimensions.Count | Should -BeExactly 1 + $buildOrder[1].buildDimensions[0].buildMode | Should -BeExactly "Default" + $buildOrder[1].buildDimensions[0].project | Should -BeExactly "Project2" + + $buildOrder[2] | Should -BeOfType System.Collections.Hashtable + $buildOrder[2].projects | Should -BeExactly @("Project4", "Project3") + $buildOrder[2].projectsCount | Should -BeExactly 2 + $buildOrder[2].buildDimensions.Count | Should -BeExactly 2 + $buildOrder[2].buildDimensions[0].buildMode | Should -BeExactly "Default" + $buildOrder[2].buildDimensions[0].project | Should -BeExactly "Project4" + $buildOrder[2].buildDimensions[1].buildMode | Should -BeExactly "Default" + $buildOrder[2].buildDimensions[1].project | Should -BeExactly "Project3" + } + AfterEach { Remove-Item $baseFolder -Force -Recurse } From e44504d285fd5eb185fb2631c383a3ad4d7c2e63 Mon Sep 17 00:00:00 2001 From: Freddy Kristiansen Date: Thu, 22 Jan 2026 17:03:44 +0100 Subject: [PATCH 50/50] add docs --- RELEASENOTES.md | 4 ++++ Scenarios/settings.md | 1 + 2 files changed, 5 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 80695ac93..814e307b2 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -12,6 +12,10 @@ - AL-Go repositories with large amounts of projects may run into issues with too large environment variables - Discussion 1855 Add trigger 'workflow_call' to workflow 'Update AL-Go System Files' for reusability +### New Settings + +- `postponeProjectInBuildOrder` is a new project setting, which will (if set to true) cause the project to be postponed until the last build job when possible. If set on test projects, then all tests can be deferred until all builds have succeeded. + ### Set default values for workflow inputs The `workflowDefaultInputs` setting now also applies to `workflow_call` inputs when an input with the same name exists for `workflow_dispatch`. diff --git a/Scenarios/settings.md b/Scenarios/settings.md index 6f28ee5b0..f8b2a2d58 100644 --- a/Scenarios/settings.md +++ b/Scenarios/settings.md @@ -48,6 +48,7 @@ When running a workflow or a local script, the settings are applied by reading s | appDependencyProbingPaths | Array of dependency specifications, from which apps will be downloaded when the CI/CD workflow is starting. Every dependency specification consists of the following properties:
**repo** = repository
**version** = version (default latest)
**release_status** = latestBuild/release/prerelease/draft (default release)
**projects** = projects (default * = all)
**branch** = branch (default main)
**AuthTokenSecret** = Name of secret containing auth token (default none)
| [ ] | | preprocessorSymbols | List of preprocessor symbols to use when building the apps. This setting can be specified in [workflow specific settings files](https://aka.ms/algosettings#where-are-the-settings-located) or in [conditional settings](https://aka.ms/algosettings#conditional-settings). | [ ] | | bcptThresholds | Structure with properties for the thresholds when running performance tests using the Business Central Performance Toolkit.
**DurationWarning** = a warning is shown if the duration of a bcpt test degrades more than this percentage (default 10)
**DurationError** - an error is shown if the duration of a bcpt test degrades more than this percentage (default 25)
**NumberOfSqlStmtsWarning** - a warning is shown if the number of SQL statements from a bcpt test increases more than this percentage (default 5)
**NumberOfSqlStmtsError** - an error is shown if the number of SQL statements from a bcpt test increases more than this percentage (default 10)
*Note that errors and warnings on the build in GitHub are only issued when a threshold is exceeded on the codeunit level, when an individual operation threshold is exceeded, it is only shown in the test results viewer.* | +| postponeProjectInBuildOrder | Setting this project setting to true will cause the project to be postponed until the last build job when possible (i.e. if no other projects depends on it). If set on test projects, then all tests can be deferred until all builds have succeeded. | false | ## AppSource specific basic project settings