AL/Get-ALDependencies.ps1

function Get-ALDependencies {
    Param(
        [Parameter(Mandatory = $false)]
        [string]$SourcePath = (Get-Location),
        [Parameter(Mandatory = $false)]
        [string]$ContainerName = (Get-ContainerFromLaunchJson),
        [Parameter(Mandatory = $false)]
        [switch]$Install,
        [Parameter(Mandatory = $false)]
        [switch]$UseDevEndpoint
    )

    $RepositoryName = (Get-EnvironmentKeyValue -SourcePath $SourcePath -KeyName 'repo')

    if ($null -eq $RepositoryName) {

        if (($SourcePath -eq (Get-Location)) -and (Get-IsGitRepo ($SourcePath))) {
            $RepositoryUrl = Get-GitRepoFetchUrl
            if (($RepositoryUrl.EndsWith('-AL')) -or ($RepositoryUrl.EndsWith('-BC'))) {
                $RepositoryName = $RepositoryUrl.Substring($RepositoryUrl.Length - 3)
            }
        }
        
    }

    Write-Host "Repository Name: $RepositoryName"

    if (!([IO.Directory]::Exists((Join-Path $SourcePath '.alpackages')))) {
        Create-EmptyDirectory (Join-Path $SourcePath '.alpackages')
    }

    $AppJson = ConvertFrom-Json (Get-Content (Join-Path $SourcePath 'app.json') -Raw)

    Get-ALDependenciesFromAppJson -AppJson $AppJson -SourcePath $SourcePath -RepositoryName $RepositoryName -ContainerName $ContainerName -Install:$Install -UseDevEndpoint:$UseDevEndpoint
}

function Get-ALDependenciesFromAppJson {
    Param(
        [Parameter(Mandatory = $true)]
        $AppJson,
        [Parameter(Mandatory = $false)]
        [string]$SourcePath = (Get-Location),
        [Parameter(Mandatory = $false)]
        [string]$RepositoryName,
        [Parameter(Mandatory = $false)]
        [string]$ContainerName,
        [Parameter(Mandatory = $false)]
        [switch]$Install,
        [Parameter(Mandatory = $false)]
        [switch]$UseDevEndpoint
    )

    if ($RepositoryName -eq '') {
        $RepositoryName = 'BC'
    }

    foreach ($Dependency in $AppJson.dependencies | Where-Object Name -NotLike '*Tests*') {
        if ($null -ne $Dependency) {
            $DependencyProject = ''
            $DependencyRepo = ''
            $DependencyBranch = ''
            # is the source for this app defined in the environment file?
            $EnvDependency = Get-DependencyFromEnvironment -SourcePath $SourcePath -Name $Dependency.name
            Write-Host "Getting $($AppJson.name) dependency: $($Dependency.name)"
            if ($null -ne $EnvDependency) {
                if ($null -ne $EnvDependency.includetest) {
                    $IncludeTest = $EnvDependency.includetest
                }

                $DependencyProject = $EnvDependency.project
                $DependencyRepo = $EnvDependency.repo
                if ($null -ne $EnvDependency.branch) {
                    $DependencyBranch = $EnvDependency.branch
                }
            }
            # otherwise aquire the app from the last successful build
            else {
                if ($Dependency.publisher -eq 'Microsoft') {
                    $Apps = @()
                    $DependencyAppJson = ConvertFrom-Json '{}'
                }
                else {
                    $DependencyProject = $Dependency.name
                    $DependencyRepo = $RepositoryName
                }
            }

            if ($DependencyProject -ne '') {
                $Apps = $null
                if ($DependencyBranch -eq '') {
                    $DependencyBranch = Get-BranchNameForDependencies -Path $SourcePath -DependencyProject $DependencyProject -DependencyRepo $DependencyRepo
                }
                if ($DependencyBranch -ne '') {
                    Write-Host ("Fetching {0} from branch {1}" -f $Dependency.name, $DependencyBranch)
                    $Apps = Get-AppFromLastSuccessfulBuild -ProjectName $DependencyProject -RepositoryName $DependencyRepo -BranchName $DependencyBranch
                    if ($null -ne $Apps) {
                        $AppVersion = $Apps.Name.Substring($Apps.Name.LastIndexOf('_') + 1)
                        $AppVersion = [System.Version]::new($AppVersion.Substring(0, $AppVersion.LastIndexOf('.')))
                        if ([System.Version]::new($Dependency.version) -gt $AppVersion) {
                            $Apps = $null
                        }
                    }
                }

                if ($null -eq $Apps) {
                    Write-Host ("Fetching {0} from drive" -f $Dependency.name)
                    $Apps = Get-AppFromFTP -AppName $Dependency.name -PlatformVersion $AppJson.platform
                    if ($null -ne $Apps) {
                        $AppVersion = $Apps.Name.Substring($Apps.Name.LastIndexOf('_') + 1)
                        $AppVersion = [System.Version]::new($AppVersion.Substring(0, $AppVersion.LastIndexOf('.')))
                        if ([System.Version]::new($Dependency.version) -gt $AppVersion) {
                            $Apps = $null
                        }
                    }
                }
                
                if ($null -eq $Apps) {
                    Write-Host ("Fetching {0} from last successful build" -f $Dependency.name)
                    $Apps = Get-AppFromLastSuccessfulBuild -ProjectName $DependencyProject -RepositoryName $DependencyRepo
                }

                if ($null -eq $Apps) {
                    throw "$($Dependency.name) could not be downloaded"
                }

                $DependencyAppJson = Get-AppJsonFromAppFile -appFile $Apps.FullName   
            }

            # fetch any dependencies for this app
            Get-ALDependenciesFromAppJson -AppJson $DependencyAppJson -SourcePath $SourcePath -RepositoryName $RepositoryName -ContainerName $ContainerName -Install:$Install
            
            # copy (and optionally install) the apps that have been collected
            foreach ($App in $Apps | Where-Object Name -NotLike '*Tests*') {
                Copy-Item $App.FullName (Join-Path (Join-Path $SourcePath '.alpackages') $App.Name)
                if ($Install.IsPresent) {
                    $AppName = $App.Name.Substring($App.Name.IndexOf('_') + 1, $App.Name.LastIndexOf('_') - $App.Name.IndexOf('_') - 1)
                    $AppVersion = $App.Name.Substring($App.Name.LastIndexOf('_') + 1)
                    $AppVersion = [System.Version]::new($AppVersion.Substring(0, $AppVersion.LastIndexOf('.')))
                    [System.Version]$CurrentVersion = (Get-BcContainerAppInfo -containerName $ContainerName -installedOnly | Where-Object Name -EQ $AppName).version
                    if (($null -eq $CurrentVersion) -or ($CurrentVersion -lt $AppVersion)) {
                        if ($UseDevEndpoint.IsPresent) {
                            $Credential = New-CredentialFromEnvironmentJson
                            if (($null -ne $CurrentVersion) -and ($CurrentVersion -lt $AppVersion)) {
                                Publish-NavContainerApp -containerName $ContainerName -appFile $App.FullName -sync -install -upgrade -useDevEndpoint -credential $Credential 
                            }
                            else {
                                Publish-NavContainerApp -containerName $ContainerName -appFile $App.FullName -sync -install -useDevEndpoint -credential $Credential
                            }
                        }
                        else {
                            if (($null -ne $CurrentVersion) -and ($CurrentVersion -lt $AppVersion)) {
                                Publish-NavContainerApp -containerName $ContainerName -appFile $App.FullName -sync -install -upgrade
                            }
                            else {
                                Publish-NavContainerApp -containerName $ContainerName -appFile $App.FullName -sync -install
                            }
                        }
                    }
                }
            }
            
            # optionally install the test apps that have been collected as well
            if ($IncludeTest) {
                foreach ($App in $Apps | Where-Object Name -Like '*Tests*') {  
                    Copy-Item $App.FullName (Join-Path (Join-Path $SourcePath '.alpackages') $App.Name)
                    if ($Install.IsPresent) {
                        try {
                            Publish-NavContainerApp -containerName $ContainerName -appFile $App.FullName -sync -install
                        }
                        catch {
                            if (!($_.Exception.Message.Contains('already published'))) {
                                throw $_.Exception.Message
                            }
                        }
                    }
                }
            }
        }
    }
}

function Get-AppJsonFromAppFile {
    param (
        [Parameter(Mandatory = $true)]
        [string]$appFile
    )

    $tempFolder = Create-TempDirectory
    Extract-AppFileToFolder -appFilename $appFile -appFolder $tempFolder -generateAppJson
    [System.IO.File]::ReadAllLines((Join-Path $tempFolder "app.json")) | ConvertFrom-Json
}

function Get-AppJsonForProjectAndRepo {
    Param(
        [Parameter(Mandatory = $true)]
        [string]$ProjectName,
        [Parameter(Mandatory = $false)]
        [string]$RepositoryName,
        [Parameter(Mandatory = $false)]
        [string]$Publisher
    )
    if ($Publisher -eq 'Microsoft') {
        return '{}'
    }
    
    $VSTSProjectName = Get-ProjectName $ProjectName

    if ($RepositoryName -eq '') {
        $RepositoryName = 'BC'
    }

    $AppContent = Invoke-TFSAPI ('{0}{1}/_apis/git/repositories/{2}/items?path=app.json' -f (Get-TFSCollectionURL), $VSTSProjectName, (Get-RepositoryId -ProjectName $VSTSProjectName -RepositoryName $RepositoryName)) -GetContents
    $AppJson = ConvertFrom-Json $AppContent
    $AppJson
}

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

    Get-EnvironmentKeyValue -SourcePath $SourcePath -KeyName 'dependencies' | Where-Object name -eq $Name
}

Export-ModuleMember -Function Get-ALDependencies
Export-ModuleMember -Function Get-ALDependenciesFromAppJson
Export-ModuleMember -Function Get-AppJsonForProjectAndRepo