DevOpsHandling/Get-AndInstallApp.ps1

function  Get-AndInstallApp {
    param (
        [Parameter(Mandatory = $true)]
        [string]$Repository,
        [Parameter(Mandatory = $false)]
        [string]$Version = "latest",
        [Parameter(Mandatory = $false)]
        [pscredential] $Credential,
        [Parameter(Mandatory = $true)]
        [string]$appFolder,
        [switch]$useDevEndpoint,
        [switch]$silentlyContinue
    )

    $settings = import-config

    # if any of the settings are not set, throw an error
    if ($settings.storageAccount -eq "" -or $settings.storageContainer -eq "" -or $settings.storageRelativePath -eq "") {
        if ($silentlyContinue.IsPresent) {
            $false
            return
        }
        Write-Error "Configuration is not complete"
        return
    }

    # create storage context using $settings and Get-Secret
    $storageContext = New-AzStorageContext -StorageAccountName $settings.storageAccount -StorageAccountKey (Get-Secret -SecretName $settings.storageAccount) -ErrorAction SilentlyContinue
    if ($null -eq $storageContext) {
        if ($silentlyContinue.IsPresent) {
            $false
            return
        }
        Write-Error "Storage account $($settings.storageAccount) does not exist or configuration is not complete"
        return
    }

    # test if container in $settings exist in storage account defined in $storageContext
    $container = Get-AzStorageContainer -Context $storageContext -Name $settings.storageContainer -ErrorAction SilentlyContinue
    if ($null -eq $container) {
        if ($silentlyContinue.IsPresent) {
            $false
            return
        }
        Write-Error "Container $($settings.storageContainer) does not exist in storage account $($settings.storageAccount)"
        return
    }

    # create relative path from $settings and replace {repository} and {version}
    $relativePath = $settings.storageRelativePath.Replace("{repository}", $Repository).Replace("{version}", $Version)

    # test if relative path exists in container
    $blob = Get-AzStorageBlob -Container $settings.storageContainer -Context $storageContext -Blob "$($relativePath)*" -ErrorAction SilentlyContinue
    if ($null -eq $blob) {
        # if not, try to check for the same version with 0 patch level, if the version is not latest or preview and it is a semantic version
        if ($Version -ne "latest" -and $Version -ne "preview" -and $Version -match "^\d+\.\d+\.\d+$") {
            $relativePath = $settings.storageRelativePath.Replace("{repository}", $Repository).Replace("{version}", ($Version.Split(".")[0..2] -join ".") + ".0")
            $blob = Get-AzStorageBlob -Container $settings.storageContainer -Context $storageContext -Blob $relativePath -ErrorAction SilentlyContinue
        }

        if ($null -eq $blob) {
            if ($silentlyContinue.IsPresent) {
                $false
                return
            }
            Write-Error "Version $Version for repository $Repository cannot be found (Relative path $relativePath does not exist in container $($settings.storageContainer))"
            return
        }
    }

    # download all zip files in container that contain "-apps" in name from $relativePath and store it in $appFolder
    $apps = Get-AzStorageBlob -Container $settings.storageContainer -Context $storageContext -Blob "$($relativePath)*-apps.zip" -ErrorAction SilentlyContinue
    if ($null -eq $apps) {
        if ($silentlyContinue.IsPresent) {
            $false
            return
        }
        Write-Error "No apps found in for repository $Repository in $relativePath"
        return
    }

    # loop through all apps, save the app in the $appfolder, and unzip the downloaded app into a subdirectory $repository
    foreach ($app in $apps) {
        $appPath = Join-Path $appFolder ($app.Name.Split('/')[-1])
        $app | Get-AzStorageBlobContent -Destination $appPath -Force | Out-Null
        Expand-Archive -Path $appPath -DestinationPath (Join-Path $appFolder $Repository) -Force
        Remove-Item -Path $appPath -Filter *.zip -Force | Out-Null
    }

    # loop through all apps and, if the publisher is not Microsoft, extract the app to a new temp folder
    $tempFolder = New-TempDirectory
    foreach ($appfile in (Get-ChildItem -Path (Join-Path $appFolder $Repository) -filter '*.app' -File)) {
        Extract-AppFileToFolder -appFilename $appfile.FullName -appFolder $tempFolder -generateAppJson | Out-Null
        $appJson = Get-Content -Path (Join-Path $tempFolder 'app.json') | ConvertFrom-Json
        if ($null -ne $appJson.dependencies) {
            foreach($dep in $appJson.dependencies) {
                if ($dep.Publisher -ne "Microsoft") {
                    $tempVersion = [version]$dep.Version
                    $depVersion = ("{0}.{1}.{2}" -f $tempVersion.Major, $tempVersion.Minor, $tempVersion.Build)

                    # Translate the dependency name to an existing GitHub repository
                    $localRepo = $Repository
                    switch ($true) {
                        $dep.Name.StartsWith("NAV-X Allocation") { $localRepo = "nav-x-allocations" }
                        $dep.Name.StartsWith("NAV-X Library") { $localRepo = "nav-x-library" }
                        $dep.Name.StartsWith("NAV-X Base Application") { $localRepo = "nav-x-base-application" }
                        $dep.Name.StartsWith("NAV-X Commission Management") { $localRepo = "nav-x-commission-management" }
                        $dep.Name.StartsWith("NAV-X Credit Card") { $localRepo = "nav-x-credit-card" }
                        $dep.Name.StartsWith("NAV-X Credit Management") { $localRepo = "na-x-credit-management" }
                        $dep.Name.StartsWith("NAV-X National Accounts") { $localRepo = "nav-x-national-accounts" }
                        $dep.Name.StartsWith("NAV-X PayAssist") { $localRepo = "nav-x-payassist" }
                        $dep.Name.StartsWith("NAV-X Search") { $localRepo = "nav-x-search" }
                    }

                    $result = Get-AndInstallApp -Repository $localRepo -Version $depVersion -appFolder $appFolder -useDevEndpoint:$useDevEndpoint -silentlyContinue
                    if (!$result) {
                        $result = Get-AndInstallApp -Repository $localRepo -Version "latest" -appFolder $appFolder -useDevEndpoint:$useDevEndpoint -silentlyContinue
                        if (!$result) {
                            $result = Get-AndInstallApp -Repository $localRepo -Version "preview" -appFolder $appFolder -useDevEndpoint:$useDevEndpoint -silentlyContinue
                            if (!$result) {
                                Write-Error "Dependency $($dep.Name) $depVersion for repository $Repository cannot be found"
                                return
                            }
                        }
                    }
                }
            }

            $parameters = @{}
            if ($useDevEndpoint.IsPresent) {
                $parameters.Add('useDevEndpoint', $true)
                $parameters.Add('credential', $credential)
            }
            Publish-BcContainerApp -containerName $ContainerName -appFile $appFile.FullName -sync -tenant "default" -skipVerification -ignoreIfAppexists -install @parameters
        }
    }

    Remove-Item -Path $tempFolder -Recurse -Force

    if ($silentlyContinue.IsPresent) {
        $true
    }
}