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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions Actions/Deliver/Deliver.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ function ConnectAzStorageAccount {
}

. (Join-Path -Path $PSScriptRoot -ChildPath "../AL-Go-Helper.ps1" -Resolve)
Import-Module (Join-Path $PSScriptRoot "Deliver.psm1") -DisableNameChecking
DownloadAndImportBcContainerHelper

$refname = "$ENV:GITHUB_REF_NAME".Replace('/', '_')
Expand All @@ -66,16 +67,19 @@ $artifacts = $artifacts.Replace('/', ([System.IO.Path]::DirectorySeparatorChar))

$baseFolder = $ENV:GITHUB_WORKSPACE
$settings = ReadSettings -baseFolder $baseFolder
$projectList = @(GetProjectsFromRepository -baseFolder $baseFolder -projectsFromSettings $settings.projects -selectProjects $projects)

# Get the sorted list of projects
$sortedProjectList = @(Get-ProjectsInDeliveryOrder -BaseFolder $baseFolder -ProjectsFromSettings $settings.projects -SelectProjects $projects)

if ($deliveryTarget -eq "AppSource") {
$atypes = "Apps,Dependencies"
}
Write-Host "Artifacts $artifacts"
Write-Host "Projects:"
$projectList | Out-Host
$sortedProjectList | Out-Host

$secrets = $env:Secrets | ConvertFrom-Json
foreach ($thisProject in $projectList) {
foreach ($thisProject in $sortedProjectList) {
# $project should be the project part of the artifact name generated from the build
if ($thisProject -and ($thisProject -ne '.')) {
$project = $thisProject.Replace('\', '_').Replace('/', '_')
Expand Down
58 changes: 58 additions & 0 deletions Actions/Deliver/Deliver.psm1
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
. (Join-Path -Path $PSScriptRoot -ChildPath "../AL-Go-Helper.ps1" -Resolve)

<#
.SYNOPSIS
Get projects in dependency order for delivery

.DESCRIPTION
Retrieves projects from the repository and returns them sorted in dependency order,
ensuring that base projects are delivered before dependent projects.

.PARAMETER BaseFolder
The base folder of the repository

.PARAMETER ProjectsFromSettings
Projects specified in settings

.PARAMETER SelectProjects
Projects to select (supports wildcards, default is "*" for all projects)

.OUTPUTS
Array of project paths sorted by dependency order
#>
function Get-ProjectsInDeliveryOrder {
Param(
[Parameter(Mandatory = $true)]
[string] $BaseFolder,

[Parameter(Mandatory = $false)]
[string[]] $ProjectsFromSettings = @(),

[Parameter(Mandatory = $false)]
[string] $SelectProjects = "*"
)

# Get the list of projects from the repository
$projectList = @(GetProjectsFromRepository -baseFolder $BaseFolder -projectsFromSettings $ProjectsFromSettings -selectProjects $SelectProjects)

if ($projectList.Count -eq 0) {
return @()
}

if ($projectList.Count -eq 1) {
return $projectList
}

# Analyze project dependencies to determine build order
$projectBuildInfo = AnalyzeProjectDependencies -baseFolder $BaseFolder -projects $projectList

# Flatten the build order into a single sorted list
$sortedProjectList = @()
foreach($buildOrder in $projectBuildInfo.FullProjectsOrder) {
$sortedProjectList += $buildOrder.projects
}

return $sortedProjectList
}

Export-ModuleMember -Function Get-ProjectsInDeliveryOrder
1 change: 1 addition & 0 deletions RELEASENOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Read more at [workflowDefaultInputs](https://aka.ms/algosettings#workflowDefault
- Issue 2016 Running Update AL-Go system files with branches wildcard `*` tries to update _origin_
- Issue 1960 Deploy Reference Documentation fails
- Discussion 1952 Set default values on workflow_dispatch input
- Issue 2004 PublishToAppSource workflow publishes multi-app repos in alphabetical order instead of dependency order

### Deprecations

Expand Down
124 changes: 124 additions & 0 deletions Tests/Deliver.Module.Test.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
Get-Module TestActionsHelper | Remove-Module -Force
Import-Module (Join-Path $PSScriptRoot 'TestActionsHelper.psm1')
$errorActionPreference = "Stop"; $ProgressPreference = "SilentlyContinue"; Set-StrictMode -Version 2.0

Describe "Deliver Module - Get-ProjectsInDeliveryOrder Tests" {
BeforeAll {
. (Join-Path -Path $PSScriptRoot -ChildPath "../Actions/AL-Go-Helper.ps1" -Resolve)
DownloadAndImportBcContainerHelper -baseFolder $([System.IO.Path]::GetTempPath())

# Import the module in the same scope where AL-Go-Helper functions are available
Import-Module (Join-Path $PSScriptRoot "../Actions/Deliver/Deliver.psm1" -Resolve) -DisableNameChecking -Scope Global
}

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 empty array when no projects match selection' {
$result = Get-ProjectsInDeliveryOrder -baseFolder $baseFolder -projectsFromSettings @() -selectProjects 'NonExistent*'
$result | Should -BeExactly @()
}

It 'returns single project unchanged' {
# Create a single project
$appFile = @{
id = '11111111-1111-1111-1111-111111111111'
name = 'Single 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 $appFile -Depth 10) -type File -Force

$result = Get-ProjectsInDeliveryOrder -baseFolder $baseFolder -projectsFromSettings @() -selectProjects 'Project1'
$result | Should -BeExactly @('Project1')
}

It 'sorts projects in linear dependency chain' {
# Setup three projects with linear dependencies:
# Project1 (base) - no dependencies
# Project2 - depends on Project1
# Project3 - depends on Project2

# Create Project1 (base project)
$baseAppFile = @{
id = '11111111-1111-1111-1111-111111111111'
name = 'Base 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 $baseAppFile -Depth 10) -type File -Force

# Create Project2 (depends on Project1)
$dependentApp1File = @{
id = '22222222-2222-2222-2222-222222222222'
name = 'Dependent App 1'
publisher = 'Contoso'
version = '1.0.0.0'
dependencies = @(
@{
id = '11111111-1111-1111-1111-111111111111'
name = 'Base 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 $dependentApp1File -Depth 10) -type File -Force

# Create Project3 (depends on Project2)
$dependentApp2File = @{
id = '33333333-3333-3333-3333-333333333333'
name = 'Dependent App 2'
publisher = 'Contoso'
version = '1.0.0.0'
dependencies = @(
@{
id = '22222222-2222-2222-2222-222222222222'
name = 'Dependent App 1'
publisher = 'Contoso'
version = '1.0.0.0'
}
)
}
New-Item -Path "$baseFolder/Project3/.AL-Go/settings.json" -type File -Force
New-Item -Path "$baseFolder/Project3/app/app.json" -Value (ConvertTo-Json $dependentApp2File -Depth 10) -type File -Force

# Set up AL-Go settings with useProjectDependencies enabled
$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

# Call function - it will discover all projects and sort them
$result = Get-ProjectsInDeliveryOrder -baseFolder $baseFolder -projectsFromSettings @() -selectProjects '*'

# Verify correct dependency order
$result.Count | Should -BeExactly 3
$result[0] | Should -BeExactly 'Project1'
$result[1] | Should -BeExactly 'Project2'
$result[2] | Should -BeExactly 'Project3'

# Verify that Project1 comes before Project2 and Project3
$project1Index = [array]::IndexOf($result, 'Project1')
$project2Index = [array]::IndexOf($result, 'Project2')
$project3Index = [array]::IndexOf($result, 'Project3')

$project1Index | Should -BeLessThan $project2Index
$project2Index | Should -BeLessThan $project3Index
}

AfterEach {
Remove-Item $baseFolder -Force -Recurse -ErrorAction SilentlyContinue
}
}
Loading