From ad78a9cd24a2e7e518a2f4d1e46deaf7df14b7a2 Mon Sep 17 00:00:00 2001 From: spetersenms Date: Thu, 29 Jan 2026 13:23:01 +0100 Subject: [PATCH 1/5] Improved options for dependency handling --- Actions/.Modules/ReadSettings.psm1 | 2 + Actions/AL-Go-Helper.ps1 | 59 +- .../DownloadProjectDependencies.Action.ps1 | 110 ++ RELEASENOTES.md | 39 + Tests/DetermineProjectsToBuild.Test.ps1 | 1646 +++++++++-------- 5 files changed, 1045 insertions(+), 811 deletions(-) diff --git a/Actions/.Modules/ReadSettings.psm1 b/Actions/.Modules/ReadSettings.psm1 index ab242c3adf..25c29a3e3d 100644 --- a/Actions/.Modules/ReadSettings.psm1 +++ b/Actions/.Modules/ReadSettings.psm1 @@ -190,6 +190,8 @@ function GetDefaultSettings "templateBranch" = "" "appDependencyProbingPaths" = @() "useProjectDependencies" = $false + "staticProjectDependencies" = @() + "skipDependenciesBuiltByCurrentProject" = $false "runs-on" = "windows-latest" "shell" = "" "githubRunner" = "" diff --git a/Actions/AL-Go-Helper.ps1 b/Actions/AL-Go-Helper.ps1 index 82829f4875..8484d9c43d 100644 --- a/Actions/AL-Go-Helper.ps1 +++ b/Actions/AL-Go-Helper.ps1 @@ -1763,13 +1763,24 @@ Function AnalyzeProjectDependencies { # If the project is using project dependencies, add the unknown dependencies to the list of dependencies # If not, the unknown dependencies are ignored $dependenciesForProject = @() + $staticProjectDeps = @() if ($projectSettings.useProjectDependencies -eq $true) { - $dependenciesForProject = @($unknownDependencies | ForEach-Object { $_.Split(':')[0] }) + # Check if staticProjectDependencies are defined (explicit list of project names) + if ($projectSettings.staticProjectDependencies -and $projectSettings.staticProjectDependencies.Count -gt 0) { + # Use static project dependencies - bypass automatic App ID-based discovery + $staticProjectDeps = @($projectSettings.staticProjectDependencies) + Write-Host "Using static project dependencies for '$project': $($staticProjectDeps -join ', ')" + } + else { + # Use automatic App ID-based discovery + $dependenciesForProject = @($unknownDependencies | ForEach-Object { $_.Split(':')[0] }) + } } $appDependencies."$project" = @{ - "apps" = $apps - "dependencies" = $dependenciesForProject + "apps" = $apps + "dependencies" = $dependenciesForProject + "staticProjectDependencies" = $staticProjectDeps } } # AppDependencies is a hashtable with the following structure @@ -1794,18 +1805,38 @@ Function AnalyzeProjectDependencies { # The loop continues until all projects have been added to the build order foreach($project in $projects) { Write-Host "- $project" - # Find all project dependencies for the current project - $dependencies = $appDependencies."$project".dependencies - # Loop through all dependencies and locate the projects, containing the apps for which the current project has a dependency + # Check if static project dependencies are defined (explicit list bypasses App ID-based discovery) + $staticDeps = $appDependencies."$project".staticProjectDependencies $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 }) - # 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" + + if ($staticDeps -and $staticDeps.Count -gt 0) { + # Use static project dependencies directly (only include projects that are in the build) + foreach($staticDep in $staticDeps) { + if ($projects -contains $staticDep) { + $foundDependencies += $staticDep + # Also add transitive dependencies from the static dependency + if ($projectDependencies.Keys -contains $staticDep) { + $foundDependencies += $projectDependencies."$staticDep" + } + } + else { + Write-Host "Static dependency '$staticDep' for project '$project' is not in the build (may have been built already)" + } + } + } + else { + # Use automatic App ID-based discovery + $dependencies = $appDependencies."$project".dependencies + # Loop through all dependencies and locate the projects, containing the apps for which the current project has a dependency + 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 }) + # 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" + } } } } diff --git a/Actions/DownloadProjectDependencies/DownloadProjectDependencies.Action.ps1 b/Actions/DownloadProjectDependencies/DownloadProjectDependencies.Action.ps1 index be9f84fb75..52dbebcad9 100644 --- a/Actions/DownloadProjectDependencies/DownloadProjectDependencies.Action.ps1 +++ b/Actions/DownloadProjectDependencies/DownloadProjectDependencies.Action.ps1 @@ -108,6 +108,97 @@ function DownloadDependenciesFromCurrentBuild { return $downloadedDependencies } +<# + .Synopsis + Gets the App IDs for all apps that a project will build. + .Description + Reads the app.json files from all app folders in the project and returns an array of App IDs. + This is used to identify apps that the current project builds, so they can be excluded from + downloaded dependencies (to avoid overwriting locally-built apps with ones from dependency projects). +#> +function GetProjectAppIds { + param( + $baseFolder, + $project + ) + + $projectSettings = ReadSettings -project $project -baseFolder $baseFolder + ResolveProjectFolders -baseFolder $baseFolder -project $project -projectSettings ([ref] $projectSettings) + + Push-Location $baseFolder + try { + $folders = @($projectSettings.appFolders) + @($projectSettings.testFolders) + @($projectSettings.bcptTestFolders) | + Where-Object { $_ } | + ForEach-Object { + $resolvedPath = Join-Path $baseFolder "$project/$_" + if (Test-Path $resolvedPath) { + return (Resolve-Path $resolvedPath -Relative) + } + } | Where-Object { $_ } + } + finally { + Pop-Location + } + + if (-not $folders -or $folders.Count -eq 0) { + return @() + } + + $unknownDependencies = @() + $appIds = @() + Sort-AppFoldersByDependencies -appFolders $folders -baseFolder $baseFolder -WarningAction SilentlyContinue -unknownDependencies ([ref]$unknownDependencies) -knownApps ([ref]$appIds) | Out-Null + + return $appIds +} + +<# + .Synopsis + Filters downloaded dependencies by excluding apps that the current project builds. + .Description + When project B depends on project A, and both projects build an app with the same App ID, + we should use the one built by project B (the current project) instead of downloading it from project A. + This function filters out downloaded apps whose App ID matches one that the current project will build. +#> +function FilterDependenciesByAppId { + param( + [string[]] $downloadedDependencies, + [string[]] $excludeAppIds + ) + + if (-not $excludeAppIds -or $excludeAppIds.Count -eq 0) { + return $downloadedDependencies + } + + $filteredDependencies = @() + foreach ($dependency in $downloadedDependencies) { + $appPath = $dependency.Trim('()') + $isTestApp = $dependency.StartsWith('(') + + if (-not (Test-Path $appPath)) { + # If the file doesn't exist, keep it in the list (might be a URL or other reference) + $filteredDependencies += $dependency + continue + } + + try { + $appJson = Get-AppJsonFromAppFile -appFile $appPath + if ($excludeAppIds -contains $appJson.Id) { + Write-Host "Excluding downloaded app '$($appJson.Name)' (ID: $($appJson.Id)) - this app is built by the current project" + # Delete the downloaded file to avoid confusion + Remove-Item -Path $appPath -Force -ErrorAction SilentlyContinue + continue + } + } + catch { + Write-Host "Warning: Could not read app info from $appPath - keeping the dependency. Error: $($_.Exception.Message)" + } + + $filteredDependencies += $dependency + } + + return $filteredDependencies +} + . (Join-Path -Path $PSScriptRoot -ChildPath "..\AL-Go-Helper.ps1" -Resolve) Write-Host "Downloading dependencies for project '$project'. BuildMode: $buildMode, Base Folder: $baseFolder, Destination Path: $destinationPath" @@ -123,6 +214,25 @@ Write-Host "::group::Downloading project dependencies from probing paths" $downloadedDependencies += DownloadDependenciesFromProbingPaths -baseFolder $baseFolder -project $project -destinationPath $destinationPath -token $token Write-Host "::endgroup::" +# Filter out apps that the current project builds (to avoid overwriting locally-built apps with dependency versions) +# This is controlled by the 'skipDependenciesBuiltByCurrentProject' setting (defaults to false for backwards compatibility) +$settings = $env:Settings | ConvertFrom-Json +if ($settings.skipDependenciesBuiltByCurrentProject) { + Write-Host "::group::Filtering dependencies by App ID (skipDependenciesBuiltByCurrentProject is enabled)" + $currentProjectAppIds = GetProjectAppIds -baseFolder $baseFolder -project $project + if ($currentProjectAppIds -and $currentProjectAppIds.Count -gt 0) { + OutputMessageAndArray -message "App IDs built by current project '$project'" -arrayOfStrings $currentProjectAppIds + $downloadedDependencies = FilterDependenciesByAppId -downloadedDependencies $downloadedDependencies -excludeAppIds $currentProjectAppIds + } + else { + Write-Host "No apps found in current project '$project' - no filtering needed" + } + Write-Host "::endgroup::" +} +else { + Write-Host "Dependency filtering by App ID is disabled (skipDependenciesBuiltByCurrentProject is false or not set)" +} + $downloadedApps = @() $downloadedTestApps = @() diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 4b9595bae1..1967e51c81 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -9,6 +9,45 @@ - 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 for project dependency handling + +Two new settings have been added to provide more control over how project dependencies are resolved when using `useProjectDependencies`: + +#### skipDependenciesBuiltByCurrentProject + +When set to `true`, downloaded dependency apps that have the same App ID as apps built by the current project will be excluded. This prevents dependency artifacts from overwriting locally-built apps. + +This is useful in scenarios where multiple projects build the same app (e.g., country-specific versions of a base app with the same App ID). Without this setting, the dependency resolution might download an app from a dependency project that overwrites the locally-built version. + +Example configuration in project settings: + +```json +{ + "skipDependenciesBuiltByCurrentProject": true +} +``` + +Defaults to `false` for backwards compatibility. + +#### staticProjectDependencies + +When using `useProjectDependencies`, you can now explicitly specify which projects to depend on instead of relying on automatic App ID-based discovery. This gives you full control over the build order and dependency resolution. + +This is useful when multiple projects build apps with the same App ID, but you want to control exactly which project's artifacts are used as dependencies. + +Example configuration in project settings: + +```json +{ + "useProjectDependencies": true, + "staticProjectDependencies": ["W1"] +} +``` + +In this example, the project will only depend on the `W1` project, even if other projects (like `GB`) also build apps that match the project's dependencies. The project will build in parallel with other projects that also only depend on `W1`. + +Defaults to an empty array `[]`, which means automatic App ID-based discovery is used (existing behavior). + ### 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/Tests/DetermineProjectsToBuild.Test.ps1 b/Tests/DetermineProjectsToBuild.Test.ps1 index 8445567cc8..ff8063286f 100644 --- a/Tests/DetermineProjectsToBuild.Test.ps1 +++ b/Tests/DetermineProjectsToBuild.Test.ps1 @@ -1,797 +1,849 @@ -Import-Module (Join-Path $PSScriptRoot 'TestActionsHelper.psm1') -Force - -Describe "Get-ProjectsToBuild" { - BeforeAll { - . (Join-Path -Path $PSScriptRoot -ChildPath "../Actions/AL-Go-Helper.ps1" -Resolve) - DownloadAndImportBcContainerHelper -baseFolder $([System.IO.Path]::GetTempPath()) - - Import-Module (Join-Path $PSScriptRoot "../Actions/DetermineProjectsToBuild/DetermineProjectsToBuild.psm1" -Resolve) -DisableNameChecking - } - - BeforeEach { - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'baseFolder', Justification = 'False positive.')] - $baseFolder = (New-Item -ItemType Directory -Path (Join-Path $([System.IO.Path]::GetTempPath()) $([System.IO.Path]::GetRandomFileName()))).FullName - } - - It 'loads a single project in the root folder' { - New-Item -Path "$baseFolder/.AL-Go/settings.json" -type File -Force - - # Add AL-Go settings file - $alGoSettings = @{ fullBuildPatterns = @(); projects = @(); powerPlatformSolutionFolder = ''; useProjectDependencies = $false } - $env:Settings = ConvertTo-Json $alGoSettings -Depth 99 -Compress - - $allProjects, $modifiedProjects, $projectsToBuild, $projectDependencies, $buildOrder = Get-ProjectsToBuild -baseFolder $baseFolder - - $allProjects | Should -BeExactly @(".") - $modifiedProjects | Should -BeExactly @() - $projectsToBuild | Should -BeExactly @(".") - - $projectDependencies | Should -BeOfType System.Collections.Hashtable - $projectDependencies['.'] | Should -BeExactly @() - - # Build order should have the following structure: - #[ - # { - # "projects": [ - # "." - # ], - # "projectsCount": 1, - # "buildDimensions": [ - # { - # "buildMode": "Default", - # "project": "." - # } - # ] - # } - #] - $buildOrder.Count | Should -BeExactly 1 - $buildOrder[0] | Should -BeOfType System.Collections.Hashtable - $buildOrder[0].projects | Should -BeExactly @(".") - $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 "." - } - - It 'loads two independent projects with no build modes set' { - New-Item -Path "$baseFolder/Project1/.AL-Go/settings.json" -type File -Force - New-Item -Path "$baseFolder/Project2/.AL-Go/settings.json" -type File -Force - - # Add AL-Go settings file - $alGoSettings = @{ fullBuildPatterns = @(); projects = @(); powerPlatformSolutionFolder = ''; useProjectDependencies = $false } - $env:Settings = ConvertTo-Json $alGoSettings -Depth 99 -Compress - - $allProjects, $modifiedProjects, $projectsToBuild, $projectDependencies, $buildOrder = Get-ProjectsToBuild -baseFolder $baseFolder - - $allProjects | Should -BeExactly @("Project1", "Project2") - $modifiedProjects | Should -BeExactly @() - $projectsToBuild | Should -BeExactly @("Project1", "Project2") - - $projectDependencies | Should -BeOfType System.Collections.Hashtable - $projectDependencies['Project1'] | Should -BeExactly @() - $projectDependencies['Project2'] | Should -BeExactly @() - - # Build order should have the following structure: - #[ - # { - # "projects": [ - # "Project1", - # "Project2" - # ], - # "projectsCount": 2, - # "buildDimensions": [ - # { - # "buildMode": "Default", - # "project": "Project1" - # }, - # { - # "buildMode": "Default", - # "project": "Project2" - # ] - # } - #] - $buildOrder.Count | Should -BeExactly 1 - $buildOrder[0] | Should -BeOfType System.Collections.Hashtable - $buildOrder[0].projects | Should -BeExactly @("Project1", "Project2") - $buildOrder[0].projectsCount | Should -BeExactly 2 - $buildOrder[0].buildDimensions.Count | Should -BeExactly 2 - $buildOrder[0].buildDimensions[0].buildMode | Should -BeExactly "Default" - $buildOrder[0].buildDimensions[0].project | Should -BeExactly "Project1" - $buildOrder[0].buildDimensions[1].buildMode | Should -BeExactly "Default" - $buildOrder[0].buildDimensions[1].project | Should -BeExactly "Project2" - } - - It 'loads two independent projects with build modes set' { - New-Item -Path "$baseFolder/Project1/.AL-Go/settings.json" -Value $(@{ buildModes = @("Default", "Clean") } | ConvertTo-Json ) -type File -Force - New-Item -Path "$baseFolder/Project2/.AL-Go/settings.json" -Value $(@{ buildModes = @("Translated") } | ConvertTo-Json ) -type File -Force - - $allProjects, $modifiedProjects, $projectsToBuild, $projectDependencies, $buildOrder = Get-ProjectsToBuild -baseFolder $baseFolder - - $allProjects | Should -BeExactly @("Project1", "Project2") - $modifiedProjects | Should -BeExactly @() - $projectsToBuild | Should -BeExactly @("Project1", "Project2") - - $projectDependencies | Should -BeOfType System.Collections.Hashtable - $projectDependencies['Project1'] | Should -BeExactly @() - $projectDependencies['Project2'] | Should -BeExactly @() - - # Build order should have the following structure: - #[ - # { - # "projects": [ - # "Project1", - # "Project2" - # ], - # "projectsCount": 2, - # "buildDimensions": [ - # { - # "buildMode": "Default", - # "project": "Project1" - # }, - # { - # "buildMode": "Clean", - # "project": "Project1" - # }, - # { - # "buildMode": "Translated", - # "project": "Project2" - # }, - # ] - # } - #] - $buildOrder.Count | Should -BeExactly 1 - $buildOrder[0] | Should -BeOfType System.Collections.Hashtable - $buildOrder[0].projects | Should -BeExactly @("Project1", "Project2") - $buildOrder[0].projectsCount | Should -BeExactly 2 - $buildOrder[0].buildDimensions.Count | Should -BeExactly 3 - $buildOrder[0].buildDimensions[0].buildMode | Should -BeExactly "Default" - $buildOrder[0].buildDimensions[0].project | Should -BeExactly "Project1" - $buildOrder[0].buildDimensions[1].buildMode | Should -BeExactly "Clean" - $buildOrder[0].buildDimensions[1].project | Should -BeExactly "Project1" - $buildOrder[0].buildDimensions[2].buildMode | Should -BeExactly "Translated" - $buildOrder[0].buildDimensions[2].project | Should -BeExactly "Project2" - } - - It 'loads correct projects, based on the modified files: single modified file in Project1' { - # Setup project structure - $appJson = @{ id = '83fb8305-4079-415d-a25d-8132f0436fd1'; name = 'My app'; publisher = 'Contoso'; version = '1.0.0.0' } - New-Item -Path "$baseFolder/Project1/.AL-Go/settings.json" -type File -Force - New-Item -Path "$baseFolder/Project1/app/app.json" -Value (ConvertTo-Json $appJson) -type File -Force - New-Item -Path "$baseFolder/Project2/.AL-Go/settings.json" -type File -Force - - $modifiedFiles = @('Project1/.AL-Go/settings.json') - $allProjects, $modifiedProjects, $projectsToBuild, $projectDependencies, $buildOrder = Get-ProjectsToBuild -baseFolder $baseFolder -modifiedFiles $modifiedFiles -buildAllProjects $false - - $allProjects | Should -BeExactly @("Project1", "Project2") - $modifiedProjects | Should -BeExactly @("Project1") - $projectsToBuild | Should -BeExactly @("Project1") - - $projectDependencies | Should -BeOfType System.Collections.Hashtable - $projectDependencies['Project1'] | Should -BeExactly @() - $projectDependencies['Project2'] | Should -BeExactly @() - - # Build order should have the following structure: - #[ - # { - # "projects": [ - # "Project1", - # ], - # "projectsCount": 1, - # "buildDimensions": [ - # { - # "buildMode": "Default", - # "project": "Project1" - # } - # ] - # } - #] - $buildOrder.Count | Should -BeExactly 1 - $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" - } - - It 'loads correct projects, based on the modified files: multiple modified files in Project1 and Project2' { - # Setup project structure - $appJson = @{ id = '83fb8305-4079-415d-a25d-8132f0436fd1'; name = 'My app'; publisher = 'Contoso'; version = '1.0.0.0' } - New-Item -Path "$baseFolder/Project1/.AL-Go/settings.json" -type File -Force - New-Item -Path "$baseFolder/Project1/app/app.json" -Value (ConvertTo-Json $appJson) -type File -Force - New-Item -Path "$baseFolder/Project2/.AL-Go/settings.json" -type File -Force - - $modifiedFiles = @('Project1/.AL-Go/settings.json', 'Project2/.AL-Go/settings.json') - $allProjects, $modifiedProjects, $projectsToBuild, $projectDependencies, $buildOrder = Get-ProjectsToBuild -baseFolder $baseFolder -modifiedFiles $modifiedFiles -buildAllProjects $false - - $allProjects | Should -BeExactly @("Project1", "Project2") - $modifiedProjects | Should -BeExactly @("Project1", "Project2") - $projectsToBuild | Should -BeExactly @("Project1", "Project2") - - $projectDependencies | Should -BeOfType System.Collections.Hashtable - $projectDependencies['Project1'] | Should -BeExactly @() - $projectDependencies['Project2'] | Should -BeExactly @() - - # Build order should have the following structure: - #[ - # { - # "projects": [ - # "Project1", - # "Project2" - # ], - # "projectsCount": 2, - # "buildDimensions": [ - # { - # "buildMode": "Default", - # "project": "Project1" - # }, - # { - # "buildMode": "Default", - # "project": "Project2" - # } - # ] - # } - #] - $buildOrder.Count | Should -BeExactly 1 - $buildOrder[0] | Should -BeOfType System.Collections.Hashtable - $buildOrder[0].projects | Should -BeExactly @("Project1", "Project2") - $buildOrder[0].projectsCount | Should -BeExactly 2 - $buildOrder[0].buildDimensions.Count | Should -BeExactly 2 - $buildOrder[0].buildDimensions[0].buildMode | Should -BeExactly "Default" - $buildOrder[0].buildDimensions[0].project | Should -BeExactly "Project1" - $buildOrder[0].buildDimensions[1].buildMode | Should -BeExactly "Default" - $buildOrder[0].buildDimensions[1].project | Should -BeExactly "Project2" - } - - It 'loads correct projects, based on the modified files: multiple modified files only in Project1' { - # Setup project structure - $appJson = @{ id = '83fb8305-4079-415d-a25d-8132f0436fd1'; name = 'My app'; publisher = 'Contoso'; version = '1.0.0.0' } - New-Item -Path "$baseFolder/Project1/.AL-Go/settings.json" -type File -Force - New-Item -Path "$baseFolder/Project1/app/app.json" -Value (ConvertTo-Json $appJson) -type File -Force - New-Item -Path "$baseFolder/Project2/.AL-Go/settings.json" -type File -Force - - $modifiedFiles = @('Project1/.AL-Go/settings.json', 'Project1/app/app.json') - $allProjects, $modifiedProjects, $projectsToBuild, $projectDependencies, $buildOrder = Get-ProjectsToBuild -baseFolder $baseFolder -modifiedFiles $modifiedFiles -buildAllProjects $false - - $allProjects | Should -BeExactly @("Project1", "Project2") - $modifiedProjects | Should -BeExactly @("Project1") - $projectsToBuild | Should -BeExactly @("Project1") - - $projectDependencies | Should -BeOfType System.Collections.Hashtable - $projectDependencies['Project1'] | Should -BeExactly @() - $projectDependencies['Project2'] | Should -BeExactly @() - - # Build order should have the following structure: - #[ - # { - # "projects": [ - # "Project1", - # ], - # "projectsCount": 1, - # "buildDimensions": [ - # { - # "buildMode": "Default", - # "project": "Project1" - # } - # ] - # } - #] - - $buildOrder.Count | Should -BeExactly 1 - $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" - } - - It 'loads correct projects, based on the modified files: no modified files' { - # Setup project structure - $appJson = @{ id = '83fb8305-4079-415d-a25d-8132f0436fd1'; name = 'My app'; publisher = 'Contoso'; version = '1.0.0.0' } - New-Item -Path "$baseFolder/Project1/.AL-Go/settings.json" -type File -Force - New-Item -Path "$baseFolder/Project1/app/app.json" -Value (ConvertTo-Json $appJson) -type File -Force - New-Item -Path "$baseFolder/Project2/.AL-Go/settings.json" -type File -Force - - $modifiedFiles = @() - $allProjects, $modifiedProjects, $projectsToBuild, $projectDependencies, $buildOrder = Get-ProjectsToBuild -baseFolder $baseFolder -modifiedFiles $modifiedFiles -buildAllProjects $true - - $allProjects | Should -BeExactly @("Project1", "Project2") - $modifiedProjects | Should -BeExactly @() - $projectsToBuild | Should -BeExactly @("Project1", "Project2") - - $projectDependencies | Should -BeOfType System.Collections.Hashtable - $projectDependencies['Project1'] | Should -BeExactly @() - $projectDependencies['Project2'] | Should -BeExactly @() - - # Build order should have the following structure: - #[ - # { - # "projects": [ - # "Project1", - # "Project2" - # ], - # "projectsCount": 2, - # "buildDimensions": [ - # { - # "buildMode": "Default", - # "project": "Project1" - # }, - # { - # "buildMode": "Default", - # "project": "Project2" - # } - # ] - # } - #] - $buildOrder.Count | Should -BeExactly 1 - $buildOrder[0] | Should -BeOfType System.Collections.Hashtable - $buildOrder[0].projects | Should -BeExactly @("Project1", "Project2") - $buildOrder[0].projectsCount | Should -BeExactly 2 - $buildOrder[0].buildDimensions.Count | Should -BeExactly 2 - $buildOrder[0].buildDimensions[0].buildMode | Should -BeExactly "Default" - $buildOrder[0].buildDimensions[0].project | Should -BeExactly "Project1" - $buildOrder[0].buildDimensions[1].buildMode | Should -BeExactly "Default" - $buildOrder[0].buildDimensions[1].project | Should -BeExactly "Project2" - } - - It 'loads correct projects, based on the modified files: Project1 is modified, fullBuildPatterns is set to .github' { - # Setup project structure - $appJson = @{ id = '83fb8305-4079-415d-a25d-8132f0436fd1'; name = 'My app'; publisher = 'Contoso'; version = '1.0.0.0' } - New-Item -Path "$baseFolder/Project1/.AL-Go/settings.json" -type File -Force - New-Item -Path "$baseFolder/Project1/app/app.json" -Value (ConvertTo-Json $appJson) -type File -Force - New-Item -Path "$baseFolder/Project2/.AL-Go/settings.json" -type File -Force - - # Add AL-Go settings file - $alGoSettings = @{ projects = @(); powerPlatformSolutionFolder = ''; useProjectDependencies = $false; fullBuildPatterns = @('.github') } - $env:Settings = ConvertTo-Json $alGoSettings -Depth 99 -Compress - - $modifiedFiles = @('Project1/.AL-Go/settings.json') - $allProjects, $modifiedProjects, $projectsToBuild, $projectDependencies, $buildOrder = Get-ProjectsToBuild -baseFolder $baseFolder -modifiedFiles $modifiedFiles -buildAllProjects $false - - $allProjects | Should -BeExactly @("Project1", "Project2") - $modifiedProjects | Should -BeExactly @("Project1") - $projectsToBuild | Should -BeExactly @("Project1") - - $projectDependencies | Should -BeOfType System.Collections.Hashtable - $projectDependencies['Project1'] | Should -BeExactly @() - $projectDependencies['Project2'] | Should -BeExactly @() - - $buildOrder.Count | Should -BeExactly 1 - $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" - } - - It 'loads correct projects, based on the modified files: Project1 is modified, fullBuildPatterns is set to Project1/*' { - # Setup project structure - $appJson = @{ id = '83fb8305-4079-415d-a25d-8132f0436fd1'; name = 'My app'; publisher = 'Contoso'; version = '1.0.0.0' } - New-Item -Path "$baseFolder/Project1/.AL-Go/settings.json" -type File -Force - New-Item -Path "$baseFolder/Project1/app/app.json" -Value (ConvertTo-Json $appJson) -type File -Force - New-Item -Path "$baseFolder/Project2/.AL-Go/settings.json" -type File -Force - - # Add AL-Go settings file - $alGoSettings = @{ projects = @(); powerPlatformSolutionFolder = ''; useProjectDependencies = $false; fullBuildPatterns = @('Project1/*') } - $env:Settings = ConvertTo-Json $alGoSettings -Depth 99 -Compress - - $modifiedFiles = @('Project1/.AL-Go/settings.json') - $allProjects, $modifiedProjects, $projectsToBuild, $projectDependencies, $buildOrder = Get-ProjectsToBuild -baseFolder $baseFolder -modifiedFiles $modifiedFiles - - $allProjects | Should -BeExactly @("Project1", "Project2") - $modifiedProjects | Should -BeExactly @("Project1") - $projectsToBuild | Should -BeExactly @("Project1", "Project2") - - $projectDependencies | Should -BeOfType System.Collections.Hashtable - $projectDependencies['Project1'] | Should -BeExactly @() - $projectDependencies['Project2'] | Should -BeExactly @() - - $buildOrder.Count | Should -BeExactly 1 - $buildOrder[0] | Should -BeOfType System.Collections.Hashtable - $buildOrder[0].projects | Should -BeExactly @("Project1", "Project2") - $buildOrder[0].projectsCount | Should -BeExactly 2 - $buildOrder[0].buildDimensions.Count | Should -BeExactly 2 - $buildOrder[0].buildDimensions[0].buildMode | Should -BeExactly "Default" - $buildOrder[0].buildDimensions[0].project | Should -BeExactly "Project1" - $buildOrder[0].buildDimensions[1].buildMode | Should -BeExactly "Default" - $buildOrder[0].buildDimensions[1].project | Should -BeExactly "Project2" - } - - It 'loads independent projects correctly, if useProjectDependencies is set to false' { - # Two independent projects, no dependencies - New-Item -Path "$baseFolder/Project1/.AL-Go/settings.json" -type File -Force - New-Item -Path "$baseFolder/Project2/.AL-Go/settings.json" -type File -Force - - #Add settings file - $alGoSettings = @{ fullBuildPatterns = @(); projects = @(); powerPlatformSolutionFolder = ''; useProjectDependencies = $false } - $env:Settings = ConvertTo-Json $alGoSettings -Depth 99 -Compress - - $allProjects, $modifiedProjects, $projectsToBuild, $projectDependencies, $buildOrder = Get-ProjectsToBuild -baseFolder $baseFolder - - $allProjects | Should -BeExactly @("Project1", "Project2") - $modifiedProjects | Should -BeExactly @() - $projectsToBuild | Should -BeExactly @("Project1", "Project2") - - $projectDependencies | Should -BeOfType System.Collections.Hashtable - $projectDependencies['Project1'] | Should -BeExactly @() - $projectDependencies['Project2'] | Should -BeExactly @() - - # Build order should have the following structure: - #[ - # { - # "projects": [ - # "Project1", - # "Project2" - # ], - # "projectsCount": 2, - # "buildDimensions": [ - # { - # "buildMode": "Default", - # "project": "Project1" - # }, - # { - # "buildMode": "Default", - # "project": "Project1" - # } - # ] - # } - #] - - $buildOrder.Count | Should -BeExactly 1 - $buildOrder[0] | Should -BeOfType System.Collections.Hashtable - $buildOrder[0].projects | Should -BeExactly @("Project1", "Project2") - $buildOrder[0].projectsCount | Should -BeExactly 2 - $buildOrder[0].buildDimensions.Count | Should -BeExactly 2 - $buildOrder[0].buildDimensions[0].buildMode | Should -BeExactly "Default" - $buildOrder[0].buildDimensions[0].project | Should -BeExactly "Project1" - $buildOrder[0].buildDimensions[1].buildMode | Should -BeExactly "Default" - $buildOrder[0].buildDimensions[1].project | Should -BeExactly "Project2" - } - - It 'loads independent projects correctly, if useProjectDependencies is set to true' { - # Two independent projects, no dependencies - New-Item -Path "$baseFolder/Project1/.AL-Go/settings.json" -type File -Force - New-Item -Path "$baseFolder/Project2/.AL-Go/settings.json" -type File -Force - - #Add settings file - $alGoSettings = @{ fullBuildPatterns = @(); projects = @(); powerPlatformSolutionFolder = ''; useProjectDependencies = $true } - $env:Settings = ConvertTo-Json $alGoSettings -Depth 99 -Compress - - $allProjects, $modifiedProjects, $projectsToBuild, $projectDependencies, $buildOrder = Get-ProjectsToBuild -baseFolder $baseFolder - - $allProjects | Should -BeExactly @("Project1", "Project2") - $modifiedProjects | Should -BeExactly @() - $projectsToBuild | Should -BeExactly @("Project1", "Project2") - - $projectDependencies | Should -BeOfType System.Collections.Hashtable - $projectDependencies['Project1'] | Should -BeExactly @() - $projectDependencies['Project2'] | Should -BeExactly @() - - # Build order should have the following structure: - #[ - # { - # "projects": [ - # "Project1", - # "Project2" - # ], - # "projectsCount": 2, - # "buildDimensions": [ - # { - # "buildMode": "Default", - # "project": "Project1" - # }, - # { - # "buildMode": "Default", - # "project": "Project1" - # } - # ] - # } - #] - - $buildOrder.Count | Should -BeExactly 1 - $buildOrder[0] | Should -BeOfType System.Collections.Hashtable - $buildOrder[0].projects | Should -BeExactly @("Project1", "Project2") - $buildOrder[0].projectsCount | Should -BeExactly 2 - $buildOrder[0].buildDimensions.Count | Should -BeExactly 2 - $buildOrder[0].buildDimensions[0].buildMode | Should -BeExactly "Default" - $buildOrder[0].buildDimensions[0].project | Should -BeExactly "Project1" - $buildOrder[0].buildDimensions[1].buildMode | Should -BeExactly "Default" - $buildOrder[0].buildDimensions[1].project | Should -BeExactly "Project2" - } - - It 'loads dependent projects correctly, if useProjectDependencies is set to false' { - # Two dependent projects - $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 - New-Item -Path "$baseFolder/Project2/app/app.json" -Value (ConvertTo-Json $dependantAppFile -Depth 10) -type File -Force - - #Add settings file - $alGoSettings = @{ fullBuildPatterns = @(); projects = @(); powerPlatformSolutionFolder = ''; useProjectDependencies = $false } - $env:Settings = ConvertTo-Json $alGoSettings -Depth 99 -Compress - - $allProjects, $modifiedProjects, $projectsToBuild, $projectDependencies, $buildOrder = Get-ProjectsToBuild -baseFolder $baseFolder - - $allProjects | Should -BeExactly @("Project1", "Project2") - $modifiedProjects | Should -BeExactly @() - $projectsToBuild | Should -BeExactly @("Project1", "Project2") - - $projectDependencies | Should -BeOfType System.Collections.Hashtable - $projectDependencies['Project1'] | Should -BeExactly @() - $projectDependencies['Project2'] | Should -BeExactly @() - - # Build order should have the following structure: - #[ - # { - # "projects": [ - # "Project1", - # "Project2" - # ], - # "projectsCount": 2, - # "buildDimensions": [ - # { - # "buildMode": "Default", - # "project": "Project1" - # }, - # { - # "buildMode": "Default", - # "project": "Project2" - # } - # ] - # } - #] - - $buildOrder.Count | Should -BeExactly 1 - $buildOrder[0] | Should -BeOfType System.Collections.Hashtable - $buildOrder[0].projects | Should -BeExactly @("Project1", "Project2") - $buildOrder[0].projectsCount | Should -BeExactly 2 - $buildOrder[0].buildDimensions.Count | Should -BeExactly 2 - $buildOrder[0].buildDimensions[0].buildMode | Should -BeExactly "Default" - $buildOrder[0].buildDimensions[0].project | Should -BeExactly "Project1" - $buildOrder[0].buildDimensions[1].buildMode | Should -BeExactly "Default" - $buildOrder[0].buildDimensions[1].project | Should -BeExactly "Project2" - } - - It 'loads dependent projects correctly, if useProjectDependencies is set to true' { - # Two dependent projects - $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 - New-Item -Path "$baseFolder/Project2/app/app.json" -Value (ConvertTo-Json $dependantAppFile -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") - $modifiedProjects | Should -BeExactly @() - $projectsToBuild | Should -BeExactly @("Project1", "Project2") - - $projectDependencies | Should -BeOfType System.Collections.Hashtable - $projectDependencies['Project1'] | Should -BeExactly @() - $projectDependencies['Project2'] | Should -BeExactly @("Project1") - - # Build order should have the following structure: - #[ - # { - # "projects": [ - # "Project1" - # ], - # "projectsCount": 1, - # "buildDimensions": [ - # { - # "buildMode": "Default", - # "project": "Project1" - # } - # ] - # }, - # { - # "projects": [ - # "Project2" - # ], - # "projectsCount": 1, - # "buildDimensions": [ - # { - # "buildMode": "Default", - # "project": "Project2" - # } - # ] - # } - #] - - $buildOrder.Count | Should -BeExactly 2 - $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" - } - - It 'loads dependent projects correctly, if useProjectDependencies is set to false in a project setting' { - # Add three dependent projects - # Project 1 - # Project 2 depends on Project 1 - useProjectDependencies is set to true from the repo settings - # Project 3 depends on Project 1, but has useProjectDependencies set to false in the project settings - $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 - New-Item -Path "$baseFolder/Project2/app/app.json" -Value (ConvertTo-Json $dependantAppFile -Depth 10) -type File -Force - - # Third project that also depends on the first project, but has useProjectDependencies set to false - $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 - @{ useProjectDependencies = $false } | 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 - - #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") - $modifiedProjects | Should -BeExactly @() - $projectsToBuild | Should -BeExactly @('Project1', 'Project2', 'Project3') - - $projectDependencies | Should -BeOfType System.Collections.Hashtable - $projectDependencies['Project1'] | Should -BeExactly @() - $projectDependencies['Project2'] | Should -BeExactly @("Project1") - $projectDependencies['Project3'] | Should -BeExactly @() - - # Build order should have the following structure: - #[ - #{ - # "buildDimensions": [ - # { - # "projectName": "Project1", - # "buildMode": "Default", - # "project": "Project1", - # "githubRunnerShell": "powershell", - # "gitHubRunner": "\"windows-latest\"" - # }, - # { - # "projectName": "Project3", - # "buildMode": "Default", - # "project": "Project3", - # "githubRunnerShell": "powershell", - # "gitHubRunner": "\"windows-latest\"" - # } - # ], - # "projectsCount": 2, - # "projects": [ - # "Project1", - # "Project3" - # ] - #}, - #{ - # "buildDimensions": [ - # { - # "projectName": "Project2", - # "buildMode": "Default", - # "project": "Project2", - # "githubRunnerShell": "powershell", - # "gitHubRunner": "\"windows-latest\"" - # } - # ], - # "projectsCount": 1, - # "projects": [ - # "Project2" - # ] - #} - #] - $buildOrder.Count | Should -BeExactly 2 - $buildOrder[0] | Should -BeOfType System.Collections.Hashtable - $buildOrder[0].projects | Should -BeExactly @("Project1", "Project3") - $buildOrder[0].projectsCount | Should -BeExactly 2 - $buildOrder[0].buildDimensions.Count | Should -BeExactly 2 - $buildOrder[0].buildDimensions[0].buildMode | Should -BeExactly "Default" - $buildOrder[0].buildDimensions[0].project | Should -BeExactly "Project1" - $buildOrder[0].buildDimensions[1].buildMode | Should -BeExactly "Default" - $buildOrder[0].buildDimensions[1].project | Should -BeExactly "Project3" - - $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" - } - - It 'throws if the calculated build depth is more than the maximum supported' { - # Two dependent projects - $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 - New-Item -Path "$baseFolder/Project2/app/app.json" -Value (ConvertTo-Json $dependantAppFile -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 - - { 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" - } - - AfterEach { - Remove-Item $baseFolder -Force -Recurse - } -} - -Describe "Get-BuildAllProjects" { - BeforeAll { - Import-Module (Join-Path $PSScriptRoot "../Actions/DetermineProjectsToBuild/DetermineProjectsToBuild.psm1" -Resolve) -DisableNameChecking - } - - BeforeEach { - [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'baseFolder', Justification = 'False positive.')] - $baseFolder = (New-Item -ItemType Directory -Path (Join-Path $([System.IO.Path]::GetTempPath()) $([System.IO.Path]::GetRandomFileName()))).FullName - } - - It ('returns false if there are no modified files') { - # Add AL-Go settings - $alGoSettings = @{ fullBuildPatterns = @() } - $env:Settings = ConvertTo-Json $alGoSettings -Depth 99 -Compress - - $buildAllProjects = Get-BuildAllProjects -baseFolder $baseFolder - $buildAllProjects | Should -Be $false - } - - It ('returns true if any of the modified files matches any of the patterns in fullBuildPatterns setting') { - # Add AL-Go settings - $alGoSettings = @{ fullBuildPatterns = @('Project1/*') } - $env:Settings = ConvertTo-Json $alGoSettings -Depth 99 -Compress - - $modifiedFiles = @('Project1/.AL-Go/settings.json', 'Project2/.AL-Go/settings.json') - $buildAllProjects = Get-BuildAllProjects -baseFolder $baseFolder -modifiedFiles $modifiedFiles - $buildAllProjects | Should -Be $true - } - - It ('returns false if the modified files are less than 250 and none of them matches any of the patterns in fullBuildPatterns setting') { - # Add AL-Go settings - $alGoSettings = @{ fullBuildPatterns = @('Project1/*') } - $env:Settings = ConvertTo-Json $alGoSettings -Depth 99 -Compress - - $modifiedFiles = @('Project2/.AL-Go/settings.json', 'Project3/.AL-Go/settings.json') - $buildAllProjects = Get-BuildAllProjects -baseFolder $baseFolder -modifiedFiles $modifiedFiles - $buildAllProjects | Should -Be $false - } - - AfterEach { - Remove-Item $baseFolder -Force -Recurse - } -} +Import-Module (Join-Path $PSScriptRoot 'TestActionsHelper.psm1') -Force + +Describe "Get-ProjectsToBuild" { + BeforeAll { + . (Join-Path -Path $PSScriptRoot -ChildPath "../Actions/AL-Go-Helper.ps1" -Resolve) + DownloadAndImportBcContainerHelper -baseFolder $([System.IO.Path]::GetTempPath()) + + Import-Module (Join-Path $PSScriptRoot "../Actions/DetermineProjectsToBuild/DetermineProjectsToBuild.psm1" -Resolve) -DisableNameChecking + } + + BeforeEach { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'baseFolder', Justification = 'False positive.')] + $baseFolder = (New-Item -ItemType Directory -Path (Join-Path $([System.IO.Path]::GetTempPath()) $([System.IO.Path]::GetRandomFileName()))).FullName + } + + It 'loads a single project in the root folder' { + New-Item -Path "$baseFolder/.AL-Go/settings.json" -type File -Force + + # Add AL-Go settings file + $alGoSettings = @{ fullBuildPatterns = @(); projects = @(); powerPlatformSolutionFolder = ''; useProjectDependencies = $false } + $env:Settings = ConvertTo-Json $alGoSettings -Depth 99 -Compress + + $allProjects, $modifiedProjects, $projectsToBuild, $projectDependencies, $buildOrder = Get-ProjectsToBuild -baseFolder $baseFolder + + $allProjects | Should -BeExactly @(".") + $modifiedProjects | Should -BeExactly @() + $projectsToBuild | Should -BeExactly @(".") + + $projectDependencies | Should -BeOfType System.Collections.Hashtable + $projectDependencies['.'] | Should -BeExactly @() + + # Build order should have the following structure: + #[ + # { + # "projects": [ + # "." + # ], + # "projectsCount": 1, + # "buildDimensions": [ + # { + # "buildMode": "Default", + # "project": "." + # } + # ] + # } + #] + $buildOrder.Count | Should -BeExactly 1 + $buildOrder[0] | Should -BeOfType System.Collections.Hashtable + $buildOrder[0].projects | Should -BeExactly @(".") + $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 "." + } + + It 'loads two independent projects with no build modes set' { + New-Item -Path "$baseFolder/Project1/.AL-Go/settings.json" -type File -Force + New-Item -Path "$baseFolder/Project2/.AL-Go/settings.json" -type File -Force + + # Add AL-Go settings file + $alGoSettings = @{ fullBuildPatterns = @(); projects = @(); powerPlatformSolutionFolder = ''; useProjectDependencies = $false } + $env:Settings = ConvertTo-Json $alGoSettings -Depth 99 -Compress + + $allProjects, $modifiedProjects, $projectsToBuild, $projectDependencies, $buildOrder = Get-ProjectsToBuild -baseFolder $baseFolder + + $allProjects | Should -BeExactly @("Project1", "Project2") + $modifiedProjects | Should -BeExactly @() + $projectsToBuild | Should -BeExactly @("Project1", "Project2") + + $projectDependencies | Should -BeOfType System.Collections.Hashtable + $projectDependencies['Project1'] | Should -BeExactly @() + $projectDependencies['Project2'] | Should -BeExactly @() + + # Build order should have the following structure: + #[ + # { + # "projects": [ + # "Project1", + # "Project2" + # ], + # "projectsCount": 2, + # "buildDimensions": [ + # { + # "buildMode": "Default", + # "project": "Project1" + # }, + # { + # "buildMode": "Default", + # "project": "Project2" + # ] + # } + #] + $buildOrder.Count | Should -BeExactly 1 + $buildOrder[0] | Should -BeOfType System.Collections.Hashtable + $buildOrder[0].projects | Should -BeExactly @("Project1", "Project2") + $buildOrder[0].projectsCount | Should -BeExactly 2 + $buildOrder[0].buildDimensions.Count | Should -BeExactly 2 + $buildOrder[0].buildDimensions[0].buildMode | Should -BeExactly "Default" + $buildOrder[0].buildDimensions[0].project | Should -BeExactly "Project1" + $buildOrder[0].buildDimensions[1].buildMode | Should -BeExactly "Default" + $buildOrder[0].buildDimensions[1].project | Should -BeExactly "Project2" + } + + It 'loads two independent projects with build modes set' { + New-Item -Path "$baseFolder/Project1/.AL-Go/settings.json" -Value $(@{ buildModes = @("Default", "Clean") } | ConvertTo-Json ) -type File -Force + New-Item -Path "$baseFolder/Project2/.AL-Go/settings.json" -Value $(@{ buildModes = @("Translated") } | ConvertTo-Json ) -type File -Force + + $allProjects, $modifiedProjects, $projectsToBuild, $projectDependencies, $buildOrder = Get-ProjectsToBuild -baseFolder $baseFolder + + $allProjects | Should -BeExactly @("Project1", "Project2") + $modifiedProjects | Should -BeExactly @() + $projectsToBuild | Should -BeExactly @("Project1", "Project2") + + $projectDependencies | Should -BeOfType System.Collections.Hashtable + $projectDependencies['Project1'] | Should -BeExactly @() + $projectDependencies['Project2'] | Should -BeExactly @() + + # Build order should have the following structure: + #[ + # { + # "projects": [ + # "Project1", + # "Project2" + # ], + # "projectsCount": 2, + # "buildDimensions": [ + # { + # "buildMode": "Default", + # "project": "Project1" + # }, + # { + # "buildMode": "Clean", + # "project": "Project1" + # }, + # { + # "buildMode": "Translated", + # "project": "Project2" + # }, + # ] + # } + #] + $buildOrder.Count | Should -BeExactly 1 + $buildOrder[0] | Should -BeOfType System.Collections.Hashtable + $buildOrder[0].projects | Should -BeExactly @("Project1", "Project2") + $buildOrder[0].projectsCount | Should -BeExactly 2 + $buildOrder[0].buildDimensions.Count | Should -BeExactly 3 + $buildOrder[0].buildDimensions[0].buildMode | Should -BeExactly "Default" + $buildOrder[0].buildDimensions[0].project | Should -BeExactly "Project1" + $buildOrder[0].buildDimensions[1].buildMode | Should -BeExactly "Clean" + $buildOrder[0].buildDimensions[1].project | Should -BeExactly "Project1" + $buildOrder[0].buildDimensions[2].buildMode | Should -BeExactly "Translated" + $buildOrder[0].buildDimensions[2].project | Should -BeExactly "Project2" + } + + It 'loads correct projects, based on the modified files: single modified file in Project1' { + # Setup project structure + $appJson = @{ id = '83fb8305-4079-415d-a25d-8132f0436fd1'; name = 'My app'; publisher = 'Contoso'; version = '1.0.0.0' } + New-Item -Path "$baseFolder/Project1/.AL-Go/settings.json" -type File -Force + New-Item -Path "$baseFolder/Project1/app/app.json" -Value (ConvertTo-Json $appJson) -type File -Force + New-Item -Path "$baseFolder/Project2/.AL-Go/settings.json" -type File -Force + + $modifiedFiles = @('Project1/.AL-Go/settings.json') + $allProjects, $modifiedProjects, $projectsToBuild, $projectDependencies, $buildOrder = Get-ProjectsToBuild -baseFolder $baseFolder -modifiedFiles $modifiedFiles -buildAllProjects $false + + $allProjects | Should -BeExactly @("Project1", "Project2") + $modifiedProjects | Should -BeExactly @("Project1") + $projectsToBuild | Should -BeExactly @("Project1") + + $projectDependencies | Should -BeOfType System.Collections.Hashtable + $projectDependencies['Project1'] | Should -BeExactly @() + $projectDependencies['Project2'] | Should -BeExactly @() + + # Build order should have the following structure: + #[ + # { + # "projects": [ + # "Project1", + # ], + # "projectsCount": 1, + # "buildDimensions": [ + # { + # "buildMode": "Default", + # "project": "Project1" + # } + # ] + # } + #] + $buildOrder.Count | Should -BeExactly 1 + $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" + } + + It 'loads correct projects, based on the modified files: multiple modified files in Project1 and Project2' { + # Setup project structure + $appJson = @{ id = '83fb8305-4079-415d-a25d-8132f0436fd1'; name = 'My app'; publisher = 'Contoso'; version = '1.0.0.0' } + New-Item -Path "$baseFolder/Project1/.AL-Go/settings.json" -type File -Force + New-Item -Path "$baseFolder/Project1/app/app.json" -Value (ConvertTo-Json $appJson) -type File -Force + New-Item -Path "$baseFolder/Project2/.AL-Go/settings.json" -type File -Force + + $modifiedFiles = @('Project1/.AL-Go/settings.json', 'Project2/.AL-Go/settings.json') + $allProjects, $modifiedProjects, $projectsToBuild, $projectDependencies, $buildOrder = Get-ProjectsToBuild -baseFolder $baseFolder -modifiedFiles $modifiedFiles -buildAllProjects $false + + $allProjects | Should -BeExactly @("Project1", "Project2") + $modifiedProjects | Should -BeExactly @("Project1", "Project2") + $projectsToBuild | Should -BeExactly @("Project1", "Project2") + + $projectDependencies | Should -BeOfType System.Collections.Hashtable + $projectDependencies['Project1'] | Should -BeExactly @() + $projectDependencies['Project2'] | Should -BeExactly @() + + # Build order should have the following structure: + #[ + # { + # "projects": [ + # "Project1", + # "Project2" + # ], + # "projectsCount": 2, + # "buildDimensions": [ + # { + # "buildMode": "Default", + # "project": "Project1" + # }, + # { + # "buildMode": "Default", + # "project": "Project2" + # } + # ] + # } + #] + $buildOrder.Count | Should -BeExactly 1 + $buildOrder[0] | Should -BeOfType System.Collections.Hashtable + $buildOrder[0].projects | Should -BeExactly @("Project1", "Project2") + $buildOrder[0].projectsCount | Should -BeExactly 2 + $buildOrder[0].buildDimensions.Count | Should -BeExactly 2 + $buildOrder[0].buildDimensions[0].buildMode | Should -BeExactly "Default" + $buildOrder[0].buildDimensions[0].project | Should -BeExactly "Project1" + $buildOrder[0].buildDimensions[1].buildMode | Should -BeExactly "Default" + $buildOrder[0].buildDimensions[1].project | Should -BeExactly "Project2" + } + + It 'loads correct projects, based on the modified files: multiple modified files only in Project1' { + # Setup project structure + $appJson = @{ id = '83fb8305-4079-415d-a25d-8132f0436fd1'; name = 'My app'; publisher = 'Contoso'; version = '1.0.0.0' } + New-Item -Path "$baseFolder/Project1/.AL-Go/settings.json" -type File -Force + New-Item -Path "$baseFolder/Project1/app/app.json" -Value (ConvertTo-Json $appJson) -type File -Force + New-Item -Path "$baseFolder/Project2/.AL-Go/settings.json" -type File -Force + + $modifiedFiles = @('Project1/.AL-Go/settings.json', 'Project1/app/app.json') + $allProjects, $modifiedProjects, $projectsToBuild, $projectDependencies, $buildOrder = Get-ProjectsToBuild -baseFolder $baseFolder -modifiedFiles $modifiedFiles -buildAllProjects $false + + $allProjects | Should -BeExactly @("Project1", "Project2") + $modifiedProjects | Should -BeExactly @("Project1") + $projectsToBuild | Should -BeExactly @("Project1") + + $projectDependencies | Should -BeOfType System.Collections.Hashtable + $projectDependencies['Project1'] | Should -BeExactly @() + $projectDependencies['Project2'] | Should -BeExactly @() + + # Build order should have the following structure: + #[ + # { + # "projects": [ + # "Project1", + # ], + # "projectsCount": 1, + # "buildDimensions": [ + # { + # "buildMode": "Default", + # "project": "Project1" + # } + # ] + # } + #] + + $buildOrder.Count | Should -BeExactly 1 + $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" + } + + It 'loads correct projects, based on the modified files: no modified files' { + # Setup project structure + $appJson = @{ id = '83fb8305-4079-415d-a25d-8132f0436fd1'; name = 'My app'; publisher = 'Contoso'; version = '1.0.0.0' } + New-Item -Path "$baseFolder/Project1/.AL-Go/settings.json" -type File -Force + New-Item -Path "$baseFolder/Project1/app/app.json" -Value (ConvertTo-Json $appJson) -type File -Force + New-Item -Path "$baseFolder/Project2/.AL-Go/settings.json" -type File -Force + + $modifiedFiles = @() + $allProjects, $modifiedProjects, $projectsToBuild, $projectDependencies, $buildOrder = Get-ProjectsToBuild -baseFolder $baseFolder -modifiedFiles $modifiedFiles -buildAllProjects $true + + $allProjects | Should -BeExactly @("Project1", "Project2") + $modifiedProjects | Should -BeExactly @() + $projectsToBuild | Should -BeExactly @("Project1", "Project2") + + $projectDependencies | Should -BeOfType System.Collections.Hashtable + $projectDependencies['Project1'] | Should -BeExactly @() + $projectDependencies['Project2'] | Should -BeExactly @() + + # Build order should have the following structure: + #[ + # { + # "projects": [ + # "Project1", + # "Project2" + # ], + # "projectsCount": 2, + # "buildDimensions": [ + # { + # "buildMode": "Default", + # "project": "Project1" + # }, + # { + # "buildMode": "Default", + # "project": "Project2" + # } + # ] + # } + #] + $buildOrder.Count | Should -BeExactly 1 + $buildOrder[0] | Should -BeOfType System.Collections.Hashtable + $buildOrder[0].projects | Should -BeExactly @("Project1", "Project2") + $buildOrder[0].projectsCount | Should -BeExactly 2 + $buildOrder[0].buildDimensions.Count | Should -BeExactly 2 + $buildOrder[0].buildDimensions[0].buildMode | Should -BeExactly "Default" + $buildOrder[0].buildDimensions[0].project | Should -BeExactly "Project1" + $buildOrder[0].buildDimensions[1].buildMode | Should -BeExactly "Default" + $buildOrder[0].buildDimensions[1].project | Should -BeExactly "Project2" + } + + It 'loads correct projects, based on the modified files: Project1 is modified, fullBuildPatterns is set to .github' { + # Setup project structure + $appJson = @{ id = '83fb8305-4079-415d-a25d-8132f0436fd1'; name = 'My app'; publisher = 'Contoso'; version = '1.0.0.0' } + New-Item -Path "$baseFolder/Project1/.AL-Go/settings.json" -type File -Force + New-Item -Path "$baseFolder/Project1/app/app.json" -Value (ConvertTo-Json $appJson) -type File -Force + New-Item -Path "$baseFolder/Project2/.AL-Go/settings.json" -type File -Force + + # Add AL-Go settings file + $alGoSettings = @{ projects = @(); powerPlatformSolutionFolder = ''; useProjectDependencies = $false; fullBuildPatterns = @('.github') } + $env:Settings = ConvertTo-Json $alGoSettings -Depth 99 -Compress + + $modifiedFiles = @('Project1/.AL-Go/settings.json') + $allProjects, $modifiedProjects, $projectsToBuild, $projectDependencies, $buildOrder = Get-ProjectsToBuild -baseFolder $baseFolder -modifiedFiles $modifiedFiles -buildAllProjects $false + + $allProjects | Should -BeExactly @("Project1", "Project2") + $modifiedProjects | Should -BeExactly @("Project1") + $projectsToBuild | Should -BeExactly @("Project1") + + $projectDependencies | Should -BeOfType System.Collections.Hashtable + $projectDependencies['Project1'] | Should -BeExactly @() + $projectDependencies['Project2'] | Should -BeExactly @() + + $buildOrder.Count | Should -BeExactly 1 + $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" + } + + It 'loads correct projects, based on the modified files: Project1 is modified, fullBuildPatterns is set to Project1/*' { + # Setup project structure + $appJson = @{ id = '83fb8305-4079-415d-a25d-8132f0436fd1'; name = 'My app'; publisher = 'Contoso'; version = '1.0.0.0' } + New-Item -Path "$baseFolder/Project1/.AL-Go/settings.json" -type File -Force + New-Item -Path "$baseFolder/Project1/app/app.json" -Value (ConvertTo-Json $appJson) -type File -Force + New-Item -Path "$baseFolder/Project2/.AL-Go/settings.json" -type File -Force + + # Add AL-Go settings file + $alGoSettings = @{ projects = @(); powerPlatformSolutionFolder = ''; useProjectDependencies = $false; fullBuildPatterns = @('Project1/*') } + $env:Settings = ConvertTo-Json $alGoSettings -Depth 99 -Compress + + $modifiedFiles = @('Project1/.AL-Go/settings.json') + $allProjects, $modifiedProjects, $projectsToBuild, $projectDependencies, $buildOrder = Get-ProjectsToBuild -baseFolder $baseFolder -modifiedFiles $modifiedFiles + + $allProjects | Should -BeExactly @("Project1", "Project2") + $modifiedProjects | Should -BeExactly @("Project1") + $projectsToBuild | Should -BeExactly @("Project1", "Project2") + + $projectDependencies | Should -BeOfType System.Collections.Hashtable + $projectDependencies['Project1'] | Should -BeExactly @() + $projectDependencies['Project2'] | Should -BeExactly @() + + $buildOrder.Count | Should -BeExactly 1 + $buildOrder[0] | Should -BeOfType System.Collections.Hashtable + $buildOrder[0].projects | Should -BeExactly @("Project1", "Project2") + $buildOrder[0].projectsCount | Should -BeExactly 2 + $buildOrder[0].buildDimensions.Count | Should -BeExactly 2 + $buildOrder[0].buildDimensions[0].buildMode | Should -BeExactly "Default" + $buildOrder[0].buildDimensions[0].project | Should -BeExactly "Project1" + $buildOrder[0].buildDimensions[1].buildMode | Should -BeExactly "Default" + $buildOrder[0].buildDimensions[1].project | Should -BeExactly "Project2" + } + + It 'loads independent projects correctly, if useProjectDependencies is set to false' { + # Two independent projects, no dependencies + New-Item -Path "$baseFolder/Project1/.AL-Go/settings.json" -type File -Force + New-Item -Path "$baseFolder/Project2/.AL-Go/settings.json" -type File -Force + + #Add settings file + $alGoSettings = @{ fullBuildPatterns = @(); projects = @(); powerPlatformSolutionFolder = ''; useProjectDependencies = $false } + $env:Settings = ConvertTo-Json $alGoSettings -Depth 99 -Compress + + $allProjects, $modifiedProjects, $projectsToBuild, $projectDependencies, $buildOrder = Get-ProjectsToBuild -baseFolder $baseFolder + + $allProjects | Should -BeExactly @("Project1", "Project2") + $modifiedProjects | Should -BeExactly @() + $projectsToBuild | Should -BeExactly @("Project1", "Project2") + + $projectDependencies | Should -BeOfType System.Collections.Hashtable + $projectDependencies['Project1'] | Should -BeExactly @() + $projectDependencies['Project2'] | Should -BeExactly @() + + # Build order should have the following structure: + #[ + # { + # "projects": [ + # "Project1", + # "Project2" + # ], + # "projectsCount": 2, + # "buildDimensions": [ + # { + # "buildMode": "Default", + # "project": "Project1" + # }, + # { + # "buildMode": "Default", + # "project": "Project1" + # } + # ] + # } + #] + + $buildOrder.Count | Should -BeExactly 1 + $buildOrder[0] | Should -BeOfType System.Collections.Hashtable + $buildOrder[0].projects | Should -BeExactly @("Project1", "Project2") + $buildOrder[0].projectsCount | Should -BeExactly 2 + $buildOrder[0].buildDimensions.Count | Should -BeExactly 2 + $buildOrder[0].buildDimensions[0].buildMode | Should -BeExactly "Default" + $buildOrder[0].buildDimensions[0].project | Should -BeExactly "Project1" + $buildOrder[0].buildDimensions[1].buildMode | Should -BeExactly "Default" + $buildOrder[0].buildDimensions[1].project | Should -BeExactly "Project2" + } + + It 'loads independent projects correctly, if useProjectDependencies is set to true' { + # Two independent projects, no dependencies + New-Item -Path "$baseFolder/Project1/.AL-Go/settings.json" -type File -Force + New-Item -Path "$baseFolder/Project2/.AL-Go/settings.json" -type File -Force + + #Add settings file + $alGoSettings = @{ fullBuildPatterns = @(); projects = @(); powerPlatformSolutionFolder = ''; useProjectDependencies = $true } + $env:Settings = ConvertTo-Json $alGoSettings -Depth 99 -Compress + + $allProjects, $modifiedProjects, $projectsToBuild, $projectDependencies, $buildOrder = Get-ProjectsToBuild -baseFolder $baseFolder + + $allProjects | Should -BeExactly @("Project1", "Project2") + $modifiedProjects | Should -BeExactly @() + $projectsToBuild | Should -BeExactly @("Project1", "Project2") + + $projectDependencies | Should -BeOfType System.Collections.Hashtable + $projectDependencies['Project1'] | Should -BeExactly @() + $projectDependencies['Project2'] | Should -BeExactly @() + + # Build order should have the following structure: + #[ + # { + # "projects": [ + # "Project1", + # "Project2" + # ], + # "projectsCount": 2, + # "buildDimensions": [ + # { + # "buildMode": "Default", + # "project": "Project1" + # }, + # { + # "buildMode": "Default", + # "project": "Project1" + # } + # ] + # } + #] + + $buildOrder.Count | Should -BeExactly 1 + $buildOrder[0] | Should -BeOfType System.Collections.Hashtable + $buildOrder[0].projects | Should -BeExactly @("Project1", "Project2") + $buildOrder[0].projectsCount | Should -BeExactly 2 + $buildOrder[0].buildDimensions.Count | Should -BeExactly 2 + $buildOrder[0].buildDimensions[0].buildMode | Should -BeExactly "Default" + $buildOrder[0].buildDimensions[0].project | Should -BeExactly "Project1" + $buildOrder[0].buildDimensions[1].buildMode | Should -BeExactly "Default" + $buildOrder[0].buildDimensions[1].project | Should -BeExactly "Project2" + } + + It 'loads dependent projects correctly, if useProjectDependencies is set to false' { + # Two dependent projects + $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 + New-Item -Path "$baseFolder/Project2/app/app.json" -Value (ConvertTo-Json $dependantAppFile -Depth 10) -type File -Force + + #Add settings file + $alGoSettings = @{ fullBuildPatterns = @(); projects = @(); powerPlatformSolutionFolder = ''; useProjectDependencies = $false } + $env:Settings = ConvertTo-Json $alGoSettings -Depth 99 -Compress + + $allProjects, $modifiedProjects, $projectsToBuild, $projectDependencies, $buildOrder = Get-ProjectsToBuild -baseFolder $baseFolder + + $allProjects | Should -BeExactly @("Project1", "Project2") + $modifiedProjects | Should -BeExactly @() + $projectsToBuild | Should -BeExactly @("Project1", "Project2") + + $projectDependencies | Should -BeOfType System.Collections.Hashtable + $projectDependencies['Project1'] | Should -BeExactly @() + $projectDependencies['Project2'] | Should -BeExactly @() + + # Build order should have the following structure: + #[ + # { + # "projects": [ + # "Project1", + # "Project2" + # ], + # "projectsCount": 2, + # "buildDimensions": [ + # { + # "buildMode": "Default", + # "project": "Project1" + # }, + # { + # "buildMode": "Default", + # "project": "Project2" + # } + # ] + # } + #] + + $buildOrder.Count | Should -BeExactly 1 + $buildOrder[0] | Should -BeOfType System.Collections.Hashtable + $buildOrder[0].projects | Should -BeExactly @("Project1", "Project2") + $buildOrder[0].projectsCount | Should -BeExactly 2 + $buildOrder[0].buildDimensions.Count | Should -BeExactly 2 + $buildOrder[0].buildDimensions[0].buildMode | Should -BeExactly "Default" + $buildOrder[0].buildDimensions[0].project | Should -BeExactly "Project1" + $buildOrder[0].buildDimensions[1].buildMode | Should -BeExactly "Default" + $buildOrder[0].buildDimensions[1].project | Should -BeExactly "Project2" + } + + It 'loads dependent projects correctly, if useProjectDependencies is set to true' { + # Two dependent projects + $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 + New-Item -Path "$baseFolder/Project2/app/app.json" -Value (ConvertTo-Json $dependantAppFile -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") + $modifiedProjects | Should -BeExactly @() + $projectsToBuild | Should -BeExactly @("Project1", "Project2") + + $projectDependencies | Should -BeOfType System.Collections.Hashtable + $projectDependencies['Project1'] | Should -BeExactly @() + $projectDependencies['Project2'] | Should -BeExactly @("Project1") + + # Build order should have the following structure: + #[ + # { + # "projects": [ + # "Project1" + # ], + # "projectsCount": 1, + # "buildDimensions": [ + # { + # "buildMode": "Default", + # "project": "Project1" + # } + # ] + # }, + # { + # "projects": [ + # "Project2" + # ], + # "projectsCount": 1, + # "buildDimensions": [ + # { + # "buildMode": "Default", + # "project": "Project2" + # } + # ] + # } + #] + + $buildOrder.Count | Should -BeExactly 2 + $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" + } + + It 'loads dependent projects correctly, if useProjectDependencies is set to false in a project setting' { + # Add three dependent projects + # Project 1 + # Project 2 depends on Project 1 - useProjectDependencies is set to true from the repo settings + # Project 3 depends on Project 1, but has useProjectDependencies set to false in the project settings + $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 + New-Item -Path "$baseFolder/Project2/app/app.json" -Value (ConvertTo-Json $dependantAppFile -Depth 10) -type File -Force + + # Third project that also depends on the first project, but has useProjectDependencies set to false + $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 + @{ useProjectDependencies = $false } | 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 + + #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") + $modifiedProjects | Should -BeExactly @() + $projectsToBuild | Should -BeExactly @('Project1', 'Project2', 'Project3') + + $projectDependencies | Should -BeOfType System.Collections.Hashtable + $projectDependencies['Project1'] | Should -BeExactly @() + $projectDependencies['Project2'] | Should -BeExactly @("Project1") + $projectDependencies['Project3'] | Should -BeExactly @() + + # Build order should have the following structure: + #[ + #{ + # "buildDimensions": [ + # { + # "projectName": "Project1", + # "buildMode": "Default", + # "project": "Project1", + # "githubRunnerShell": "powershell", + # "gitHubRunner": "\"windows-latest\"" + # }, + # { + # "projectName": "Project3", + # "buildMode": "Default", + # "project": "Project3", + # "githubRunnerShell": "powershell", + # "gitHubRunner": "\"windows-latest\"" + # } + # ], + # "projectsCount": 2, + # "projects": [ + # "Project1", + # "Project3" + # ] + #}, + #{ + # "buildDimensions": [ + # { + # "projectName": "Project2", + # "buildMode": "Default", + # "project": "Project2", + # "githubRunnerShell": "powershell", + # "gitHubRunner": "\"windows-latest\"" + # } + # ], + # "projectsCount": 1, + # "projects": [ + # "Project2" + # ] + #} + #] + $buildOrder.Count | Should -BeExactly 2 + $buildOrder[0] | Should -BeOfType System.Collections.Hashtable + $buildOrder[0].projects | Should -BeExactly @("Project1", "Project3") + $buildOrder[0].projectsCount | Should -BeExactly 2 + $buildOrder[0].buildDimensions.Count | Should -BeExactly 2 + $buildOrder[0].buildDimensions[0].buildMode | Should -BeExactly "Default" + $buildOrder[0].buildDimensions[0].project | Should -BeExactly "Project1" + $buildOrder[0].buildDimensions[1].buildMode | Should -BeExactly "Default" + $buildOrder[0].buildDimensions[1].project | Should -BeExactly "Project3" + + $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" + } + + It 'uses staticProjectDependencies to override automatic dependency detection' { + # Three projects where Project2 and Project3 both build an app with the same ID (simulating country-specific builds) + # Project1 (TestProject) depends on the shared app - would normally depend on both Project2 and Project3 + # But staticProjectDependencies is set to only depend on Project2 (W1) + + # Project2 (W1) - builds the shared app + $sharedAppFile = @{ id = '83fb8305-4079-415d-a25d-8132f0436fd1'; name = 'Shared App'; publisher = 'Contoso'; version = '1.0.0.0'; dependencies = @() } + New-Item -Path "$baseFolder/Project2/.AL-Go/settings.json" -type File -Force + New-Item -Path "$baseFolder/Project2/app/app.json" -Value (ConvertTo-Json $sharedAppFile -Depth 10) -type File -Force + + # Project3 (GB) - also builds the shared app with the SAME ID + New-Item -Path "$baseFolder/Project3/.AL-Go/settings.json" -type File -Force + New-Item -Path "$baseFolder/Project3/app/app.json" -Value (ConvertTo-Json $sharedAppFile -Depth 10) -type File -Force + + # Project1 (TestProject) - depends on the shared app, but uses staticProjectDependencies to only depend on Project2 + $dependantAppFile = @{ id = '83fb8305-4079-415d-a25d-8132f0436fd2'; name = 'Test App'; publisher = 'Contoso'; version = '1.0.0.0'; dependencies = @(@{id = '83fb8305-4079-415d-a25d-8132f0436fd1'; name = 'Shared App'; publisher = 'Contoso'; version = '1.0.0.0'} ) } + New-Item -Path "$baseFolder/Project1/.AL-Go/settings.json" -type File -Force + @{ useProjectDependencies = $true; staticProjectDependencies = @('Project2') } | ConvertTo-Json -Depth 99 -Compress | Out-File (Join-Path $baseFolder "Project1/.AL-Go/settings.json") -Encoding UTF8 + New-Item -Path "$baseFolder/Project1/app/app.json" -Value (ConvertTo-Json $dependantAppFile -Depth 10) -type File -Force + + #Add repo 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") + $projectsToBuild | Should -BeExactly @("Project1", "Project2", "Project3") + + $projectDependencies | Should -BeOfType System.Collections.Hashtable + # Project1 should ONLY depend on Project2 (due to staticProjectDependencies), NOT on Project3 + $projectDependencies['Project1'] | Should -BeExactly @("Project2") + $projectDependencies['Project2'] | Should -BeExactly @() + $projectDependencies['Project3'] | Should -BeExactly @() + + # Build order: + # - First batch: Project2 and Project3 (both have no dependencies) + # - Second batch: Project1 (depends only on Project2) + # Without staticProjectDependencies, Project1 would depend on both Project2 AND Project3 + $buildOrder.Count | Should -BeExactly 2 + $buildOrder[0].projects | Should -Contain "Project2" + $buildOrder[0].projects | Should -Contain "Project3" + $buildOrder[0].projectsCount | Should -BeExactly 2 + + $buildOrder[1].projects | Should -BeExactly @("Project1") + $buildOrder[1].projectsCount | Should -BeExactly 1 + } + + It 'throws if the calculated build depth is more than the maximum supported' { + # Two dependent projects + $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 + New-Item -Path "$baseFolder/Project2/app/app.json" -Value (ConvertTo-Json $dependantAppFile -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 + + { 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" + } + + AfterEach { + Remove-Item $baseFolder -Force -Recurse + } +} + +Describe "Get-BuildAllProjects" { + BeforeAll { + Import-Module (Join-Path $PSScriptRoot "../Actions/DetermineProjectsToBuild/DetermineProjectsToBuild.psm1" -Resolve) -DisableNameChecking + } + + BeforeEach { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'baseFolder', Justification = 'False positive.')] + $baseFolder = (New-Item -ItemType Directory -Path (Join-Path $([System.IO.Path]::GetTempPath()) $([System.IO.Path]::GetRandomFileName()))).FullName + } + + It ('returns false if there are no modified files') { + # Add AL-Go settings + $alGoSettings = @{ fullBuildPatterns = @() } + $env:Settings = ConvertTo-Json $alGoSettings -Depth 99 -Compress + + $buildAllProjects = Get-BuildAllProjects -baseFolder $baseFolder + $buildAllProjects | Should -Be $false + } + + It ('returns true if any of the modified files matches any of the patterns in fullBuildPatterns setting') { + # Add AL-Go settings + $alGoSettings = @{ fullBuildPatterns = @('Project1/*') } + $env:Settings = ConvertTo-Json $alGoSettings -Depth 99 -Compress + + $modifiedFiles = @('Project1/.AL-Go/settings.json', 'Project2/.AL-Go/settings.json') + $buildAllProjects = Get-BuildAllProjects -baseFolder $baseFolder -modifiedFiles $modifiedFiles + $buildAllProjects | Should -Be $true + } + + It ('returns false if the modified files are less than 250 and none of them matches any of the patterns in fullBuildPatterns setting') { + # Add AL-Go settings + $alGoSettings = @{ fullBuildPatterns = @('Project1/*') } + $env:Settings = ConvertTo-Json $alGoSettings -Depth 99 -Compress + + $modifiedFiles = @('Project2/.AL-Go/settings.json', 'Project3/.AL-Go/settings.json') + $buildAllProjects = Get-BuildAllProjects -baseFolder $baseFolder -modifiedFiles $modifiedFiles + $buildAllProjects | Should -Be $false + } + + AfterEach { + Remove-Item $baseFolder -Force -Recurse + } +} From 370339c1d321e957b63a27863283d613f51bb223 Mon Sep 17 00:00:00 2001 From: spetersenms Date: Thu, 29 Jan 2026 13:35:36 +0100 Subject: [PATCH 2/5] Removed unused cariable. --- .../DownloadProjectDependencies.Action.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/Actions/DownloadProjectDependencies/DownloadProjectDependencies.Action.ps1 b/Actions/DownloadProjectDependencies/DownloadProjectDependencies.Action.ps1 index 52dbebcad9..7e5522fa43 100644 --- a/Actions/DownloadProjectDependencies/DownloadProjectDependencies.Action.ps1 +++ b/Actions/DownloadProjectDependencies/DownloadProjectDependencies.Action.ps1 @@ -172,7 +172,6 @@ function FilterDependenciesByAppId { $filteredDependencies = @() foreach ($dependency in $downloadedDependencies) { $appPath = $dependency.Trim('()') - $isTestApp = $dependency.StartsWith('(') if (-not (Test-Path $appPath)) { # If the file doesn't exist, keep it in the list (might be a URL or other reference) From 477f6ce91d827560a0a76fac4220b4c63ce6a41b Mon Sep 17 00:00:00 2001 From: spetersenms Date: Thu, 29 Jan 2026 13:43:23 +0100 Subject: [PATCH 3/5] Added new settings to schema --- Actions/.Modules/settings.schema.json | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Actions/.Modules/settings.schema.json b/Actions/.Modules/settings.schema.json index eafcb7bb64..8873a71a58 100644 --- a/Actions/.Modules/settings.schema.json +++ b/Actions/.Modules/settings.schema.json @@ -421,6 +421,17 @@ "type": "boolean", "description": "See https://aka.ms/ALGoSettings#useprojectdependencies" }, + "staticProjectDependencies": { + "type": "array", + "items": { + "type": "string" + }, + "description": "See https://aka.ms/ALGoSettings#staticprojectdependencies" + }, + "skipDependenciesBuiltByCurrentProject": { + "type": "boolean", + "description": "See https://aka.ms/ALGoSettings#skipdependenciesbuiltbycurrentproject" + }, "runs-on": { "type": "string", "minLength": 1, From 518d5959c23e8dd22cd77efcc602790751b6e9db Mon Sep 17 00:00:00 2001 From: spetersenms Date: Fri, 30 Jan 2026 11:53:55 +0100 Subject: [PATCH 4/5] Updated settings documentation --- Scenarios/settings.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Scenarios/settings.md b/Scenarios/settings.md index 6f28ee5b0a..02cc20886a 100644 --- a/Scenarios/settings.md +++ b/Scenarios/settings.md @@ -76,6 +76,8 @@ The repository settings are only read from the repository settings file (.github | DeployTo\ | Structure with additional properties for the environment specified. `` refers to the GitHub environment name. The structure can contain the following properties:
**EnvironmentType** = specifies the type of environment. The environment type can be used to invoke a custom deployment. (Default SaaS)
**EnvironmentName** = specifies the "real" name of the environment if it differs from the GitHub environment.
**Branches** = an array of branch patterns, which are allowed to deploy to this environment. These branches can also be defined under the environment in GitHub settings and both settings are honored. If neither setting is defined, the default is the **main** branch only.
**Projects** = In multi-project repositories, this property can be a comma separated list of project patterns to deploy to this environment. (Default \*)
**DependencyInstallMode** = Determines how dependencies are deployed if `GenerateDependencyArtifact` is true. Default value is `install` to install dependencies if not already installed. Other values are `ignore` for ignoring dependencies and `upgrade` or `forceUpgrade` for upgrading dependencies.
**includeTestAppsInSandboxEnvironment** = deploys test apps and their dependencies if the environment type is sandbox (Default is `false`)
**excludeAppIds** = array of app ids to exclude from deployment. (Default is `[]`)
**Scope** = Determines the mechanism for deployment to the environment (Dev or PTE). If not specified, AL-Go for GitHub will always use the Dev Scope for AppSource Apps, but also for PTEs when deploying to sandbox environments when impersonation (refreshtoken) is used for authentication.
**SyncMode** = ForceSync if deployment to this environment should happen with ForceSync, else Add. If deploying to the development endpoint you can also specify Development or Clean. (Default Add)
**BuildMode** = specifies which buildMode to use for the deployment. Default is to use the Default buildMode
**ContinuousDeployment** = true if this environment should be used for continuous deployment, else false. (Default: AL-Go will continuously deploy to sandbox environments or environments, which doesn't end in (PROD) or (FAT)
**runs-on** = specifies which runner to use when deploying to this environment. (Default is settings.runs-on)
**shell** = specifies which shell to use when deploying to this environment, pwsh or powershell. (Default is settings.shell)
**companyId** = Company Id from Business Central (for PowerPlatform connection)
**ppEnvironmentUrl** = Url of the PowerPlatform environment to deploy to
| | alDoc | Structure with properties for the aldoc reference document generation. The structure can contain the following properties:
**continuousDeployment** = Determines if reference documentation will be deployed continuously as part of CI/CD. You can run the **Deploy Reference Documentation** workflow to deploy manually or on a schedule. (Default false)
**deployToGitHubPages** = Determines whether or not the reference documentation site should be deployed to GitHub Pages for the repository. In order to deploy to GitHub Pages, GitHub Pages must be enabled and set to GitHub Actuibs. (Default true)
**maxReleases** = Maximum number of releases to include in the reference documentation. (Default 3)
**groupByProject** = Determines whether projects in multi-project repositories are used as folders in reference documentation
**includeProjects** = An array of projects to include in the reference documentation. (Default all)
**excludeProjects** = An array of projects to exclude in the reference documentation. (Default none)
**header** = Header for the documentation site. (Default: Documentation for...)
**footer** = Footer for the documentation site. (Default: Made with...)
**defaultIndexMD** = Markdown for the landing page of the documentation site. (Default: Reference documentation...)
**defaultReleaseMD** = Markdown for the landing page of the release sites. (Default: Release reference documentation...)
*Note that in header, footer, defaultIndexMD and defaultReleaseMD you can use the following placeholders: {REPOSITORY}, {VERSION}, {INDEXTEMPLATERELATIVEPATH}, {RELEASENOTES}* | | useProjectDependencies | Determines whether your projects are built using a multi-stage built workflow or single stage. After setting useProjectDependencies to true, you need to run Update AL-Go System Files and your workflows including a build job will change to have multiple build jobs, depending on each other. The number of build jobs will be determined by the dependency depth in your projects.
You can change dependencies between your projects, but if the dependency **depth** changes, AL-Go will warn you that updates for your AL-Go System Files are available and you will need to run the workflow. | +| staticProjectDependencies | When using `useProjectDependencies`, you can use this setting to explicitly specify which projects to depend on instead of relying on automatic App ID-based discovery. This is useful when multiple projects build apps with the same App ID (e.g., country-specific versions of a base app), but you want to control exactly which project's artifacts are used as dependencies.
**Example:** `"staticProjectDependencies": ["W1"]` - The project will only depend on the W1 project, even if other projects also build apps that match the project's dependencies.
Default is an empty array `[]`, which means automatic App ID-based discovery is used. | +| skipDependenciesBuiltByCurrentProject | When set to `true`, downloaded dependency apps that have the same App ID as apps built by the current project will be excluded. This prevents dependency artifacts from overwriting locally-built apps.
This is useful in scenarios where multiple projects build the same app (e.g., country-specific versions of a base app with the same App ID). Without this setting, the dependency resolution might download an app from a dependency project that overwrites the locally-built version.
Default is `false`. | | CICDPushBranches | CICDPushBranches can be specified as an array of branches, which triggers a CI/CD workflow on commit. You need to run the Update AL-Go System Files workflow for the change to take effect.
Default is [ "main", "release/\*", "feature/\*" ] | | CICDPullRequestBranches | CICDPullRequestBranches can be specified as an array of branches, which triggers a CI/CD workflow on a PR. You need to run the Update AL-Go System Files workflow for the change to take effect.
Default is [ "main" ] | | pullRequestTrigger | Setting for specifying the trigger AL-Go should use to trigger Pull Request Builds. You need to run the Update AL-Go System Files workflow for the change to take effect.
Default is [pull_request_target](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target) | From 0b0bddc06b0f12cdc6cfa904a1aab0447ab2f86b Mon Sep 17 00:00:00 2001 From: spetersenms Date: Fri, 30 Jan 2026 15:23:33 +0100 Subject: [PATCH 5/5] Ensuring containerhelper is available. --- .../DownloadProjectDependencies.Action.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Actions/DownloadProjectDependencies/DownloadProjectDependencies.Action.ps1 b/Actions/DownloadProjectDependencies/DownloadProjectDependencies.Action.ps1 index 7e5522fa43..3f4ef07763 100644 --- a/Actions/DownloadProjectDependencies/DownloadProjectDependencies.Action.ps1 +++ b/Actions/DownloadProjectDependencies/DownloadProjectDependencies.Action.ps1 @@ -200,6 +200,9 @@ function FilterDependenciesByAppId { . (Join-Path -Path $PSScriptRoot -ChildPath "..\AL-Go-Helper.ps1" -Resolve) +# Import BcContainerHelper module for Sort-AppFoldersByDependencies function +DownloadAndImportBcContainerHelper + Write-Host "Downloading dependencies for project '$project'. BuildMode: $buildMode, Base Folder: $baseFolder, Destination Path: $destinationPath" $downloadedDependencies = @()