AL/Get-ALDependencies.ps1

function Get-ALDependencies {
    param (
        [Parameter(Mandatory=$false)]
        [string] $SourcePath = (Get-Location),
        [Parameter(Mandatory=$false)]
        [string] $devOpsToken = "",
        [Parameter(Mandatory=$false)]
        [string] $ContainerName = "",
        [switch] $skipVerification,
        [switch] $Install,
        [switch] $TenantScope
        )
    
    if ($ContainerName -eq "") {
        $ContainerName = (Get-EnvironmentKeyValue -KeyName 'name')
    }

    if ($devOpsToken -eq "") {
        $devOpsToken = Get-EnvironmentKeyvalue -KeyName "token"
    }

    if (!([IO.Directory]::Exists((Join-Path $SourcePath ".alpackages")))) {
        New-Item -Path $SourcePath -Name ".alpackages" -ItemType Directory | out-Null
    }
    if (!(Test-Path (Join-Path $SourcePath ".zipfolder"))) {
        New-Item -Path $SourcePath -Name ".zipfolder" -ItemType Directory | Out-Null
    }
    
    $appJson = (Get-Content (Join-Path $SourcePath "app.json") | ConvertFrom-Json)
    Get-ALDependenciesFromAppJson -appJson $appJson -sourcePath $SourcePath -containerName $containerName -skipVerification:$skipVerification -Install:$Install -TenantScope:$TenantScope -devOpsToken $devOpsToken
       
    if (Test-Path (Join-Path $SourcePath ".zipfolder")) {
        Remove-Item (Join-Path $SourcePath ".zipfolder") -Recurse -Force
    }    
}

function Get-ALDependenciesFromAppJson {
    Param(
        [Parameter(Mandatory=$true)]
        $appJson,
        [Parameter(Mandatory=$true)]
        [string]$sourcePath,
        [Parameter(Mandatory=$true)]
        [string] $devOpsToken,
        [Parameter(Mandatory=$false)]
        [string]$containerName,
        [Parameter(Mandatory=$false)]
        [switch] $skipVerification,
        [Parameter(Mandatory=$false)]
        [switch] $Install,
        [switch] $TenantScope
    )

    
    foreach ($Dependency in $appJson.dependencies | Where-Object Name -NotLike '*Test*' | Where-Object Name -NotLike '*Runtime*') {
        if ($null -ne $Dependency) {
            $envDependency = (Get-DependencyFromEnvironment -sourcePath $sourcePath -name $Dependency.name)
            $IncludeTest = $false
            if ($null -ne $envDependency) {
                if ([bool]($envDependency.PSObject.Properties.name -match "includetest")) {
                    if ($null -ne $envDependency.includetest) {
                        $IncludeTest = $envDependency.includetest
                    }
                }

                Write-Host "Getting dependencies for $($envDependency.project)"
                if ($null -eq $envDependency.branchName) {
                    $apps = Get-DevOpsArtifacts -devOpsOrganization $envDependency.organization -devOpsProjectName $envDependency.project -repositoryName $envDependency.repo -devOpsToken $devOpsToken -destination $sourcePath
                    $dependencyAppJson = Get-AppJsonForProjectAndRepo -devOpsOrganization $envDependency.organization -devOpsProjectName $envDependency.project -repositoryName $envDependency.repo -devOpsToken $devOpsToken
                }
                else {
                    $apps = Get-DevOpsArtifacts -devOpsOrganization $envDependency.organization -devOpsProjectName $envDependency.project -repositoryName $envDependency.repo -devOpsToken $devOpsToken -destination $sourcePath -branchName $envDependency.branchName
                    $dependencyAppJson = Get-AppJsonForProjectAndRepo -devOpsOrganization $envDependency.organization -devOpsProjectName $envDependency.project -repositoryName $envDependency.repo -devOpsToken $devOpsToken
                }
            }
            else {
                if ($Dependency.publisher -eq 'Microsoft') {
                    $Apps = @()
                    $DependencyAppJson = $null #ConvertFrom-Json '{}'
                }
                else {
                    $Apps = Get-DevOpsArtifactsFromLastSuccessfulBuild -devOpsOrganization $Dependency.organization -devOpsProjectName $Dependency.name -repositoryName $RepositoryName -devOpstoken $devOpsToken -destination $sourcePath
                    $dependencyAppJson = Get-AppJsonForProjectAndRepo -devOpsOrganization $Dependency.organization -devOpsProjectName $Dependency.name -repositoryName $RepositoryName -devOpsToken $devOpsToken -destination $sourcePath
                }
            }

            # get dependencies for dependency app
            if ($null -ne $DependencyAppJson) {
                Get-ALDependenciesFromAppJson -AppJson $dependencyAppJson -sourcePath $sourcePath -devOpsToken $devOpsToken -containerName $containerName -skipVerification:$skipVerification -Install:$Install
            }

            # copy and install apps
            foreach ($app in $apps | Where-Object Name -NotLike '*Test*' | Where-Object Name -NotLike '*Runtime*') {
                Copy-Item $app.FullName (Join-Path (Join-Path $sourcePath ".alpackages") $app.Name)

                if ($Install.IsPresent) {
                    try {
                        if ($TenantScope.IsPresent) {
                            Publish-NavContainerApp -containerName $containerName -appFile $app.FullName -sync -install -skipVerification:$skipVerification -scope Tenant -tenant "Default"
                        } else {
                            Publish-NavContainerApp -containerName $containerName -appFile $app.FullName -sync -install -skipVerification:$skipVerification
                        }
                    }
                    catch {
                        if (!($_.Exception.Message.Contains('already published'))) {
                            throw $_.Exception.Message
                        }
                    }
                }
            }

            # should test apps also be installed
            if ($IncludeTest) {
                foreach ($app in $apps | Where-Object Name -Like '*Test*') {
                    Copy-Item $app.FullName (Join-Path (Join-Path $sourcePath '.alpackages') $app.Name)
                    if ($Install.IsPresent) {
                        try {
                            if ($TenantScope.IsPresent) {
                                Publish-NavContainerApp -containerName $ContainerName -appFile $app.FullName -sync -install -skipVerification:$skipVerification -scope Tenant -tenant "Default"
                            } else {
                                Publish-NavContainerApp -containerName $ContainerName -appFile $app.FullName -sync -install -skipVerification:$skipVerification
                            }
                        }
                        catch {
                            if (!($_.Exception.Message.Contains('already published'))) {
                                throw $_.Exception.Message
                            }
                        }
                    }
                }
            }
        }
    }
}

function Get-AppJsonForProjectAndRepo {
    Param(
        [Parameter(Mandatory=$true)]
        [string] $devOpsOrganization,
        [Parameter(Mandatory=$true)]
        [string]$devOpsProjectName,
        [Parameter(Mandatory=$true)]
        [string] $devOpsToken,
        [Parameter(Mandatory=$false)]
        [string]$RepositoryName,
        [Parameter(Mandatory=$false)]
        [string]$Publisher,
        [switch] $GetTestApp
    )
    if ($Publisher -eq 'Microsoft') {
        return '{}'
    }
    
    $devOpsProjectName = (Get-DevOpsProjects -devOpsOrganization $devOpsOrganization -devOpsToken $devOpsToken | Where-Object name -like ('*{0}*' -f $devOpsProjectName)).name

    if ($null -eq $RepositoryName -or $RepositoryName -eq '') {
        $RepositoryName = $devOpsProjectName
    }

    $AppContent = Invoke-AzureDevOpsApi ('https://dev.azure.com/{0}/{1}/_apis/git/repositories/{2}/items?recursionLevel=full&scopePath=app.json' -f $devOpsOrganization, $devOpsProjectName, (Get-RepositoryId -devOpsOrganization $devOpsOrganization -devOpsProjectName $devOpsProjectName -RepositoryName $RepositoryName -devOpsToken $devOpsToken)) -devOpsToken $devOpsToken -GetContents
    $AppJson = ConvertFrom-Json $AppContent
    $AppJson
}

function Get-DependencyFromEnvironment {
    Param(
        [Parameter(Mandatory=$true)]
        [string]$SourcePath,
        [Parameter(Mandatory=$true)]
        [string]$Name
    )

    $dependencies = Get-EnvironmentKeyValue -SourcePath $SourcePath -KeyName 'dependencies' 
    if ($null -ne $dependencies) {
        if ($dependencies -ne '') {
            return $dependencies | Where-Object name -eq $Name
        }
    }

    return @()
}

Export-ModuleMember Get-ALDependencies
Export-ModuleMember Get-ALDependenciesFromAppJson