AppHandling/Run-AlPipeline.ps1
<# .Synopsis Preview script for running simple AL pipeline .Description Preview script for running simple AL pipeline #> function Run-AlPipeline { Param( [string] $pipelineName, [string] $baseFolder, [string] $licenseFile, [string] $containerName = "$pipelinename-bld".ToLowerInvariant(), [string] $imageName = 'my', [Boolean] $enableTaskScheduler = $false, [string] $memoryLimit = "6G", [PSCredential] $credential, [string] $codeSignCertPfxFile = "", [SecureString] $codeSignCertPfxPassword = $null, $installApps = @(), $appFolders = @("app", "application"), $testFolders = @("test", "testapp"), [string] $testResultsFile = "TestResults.xml", [string] $packagesFolder = ".packages", [string] $outputFolder = ".output", [string] $artifact = "bcartifacts/sandbox//us/latest", [Boolean] $reuseContainer = $false, [switch] $installTestFramework, [switch] $installTestLibraries, [switch] $azureDevOps, [switch] $useDevEndpoint, [switch] $doNotRunTests, [switch] $keepContainer ) function randomchar([string]$str) { $rnd = Get-Random -Maximum $str.length [string]$str[$rnd] } function Get-RandomPassword { $cons = 'bcdfghjklmnpqrstvwxz' $voc = 'aeiouy' $numbers = '0123456789' ((randomchar $cons).ToUpper() + ` (randomchar $voc) + ` (randomchar $cons) + ` (randomchar $voc) + ` (randomchar $numbers) + ` (randomchar $numbers) + ` (randomchar $numbers) + ` (randomchar $numbers)) } $appFolders = @($appFolders | ForEach-Object { if (!$_.contains(':')) { Join-Path $baseFolder $_ } else { $_ } } | Where-Object { Test-Path $_ } ) $testFolders = @($testFolders | ForEach-Object { if (!$_.contains(':')) { Join-Path $baseFolder $_ } else { $_ } } | Where-Object { Test-Path $_ } ) if (!$testResultsFile.Contains(':')) { $testResultsFile = Join-Path $baseFolder $testResultsFile } if (!$packagesFolder.Contains(':')) { $packagesFolder = Join-Path $baseFolder $packagesFolder } if (!$outputFolder.Contains(':')) { $outputFolder = Join-Path $baseFolder $outputFolder } if (!($appFolders)) { throw "No app folders found" } $sortedFolders = Sort-AppFoldersByDependencies -appFolders ($appFolders+$testFolders) -WarningAction SilentlyContinue $segments = "$artifact/////".Split('/') $artifactUrl = Get-BCArtifactUrl -storageAccount $segments[0] -type $segments[1] -version $segments[2] -country $segments[3] -select $segments[4] -sasToken $env:InsiderSasToken | Select-Object -First 1 if (!($artifactUrl)) { throw "Unable to locate artifacts" } if ($reuseContainer -and (!($credential))) { throw "When using -reuseContainer, you have to specify credentials" } Write-Host -ForegroundColor Yellow @' _____ _ | __ \ | | | |__) |_ _ _ __ __ _ _ __ ___ ___| |_ ___ _ __ ___ | ___/ _` | '__/ _` | '_ ` _ \ / _ \ __/ _ \ '__/ __| | | | (_| | | | (_| | | | | | | __/ |_ __/ | \__ \ |_| \__,_|_| \__,_|_| |_| |_|\___|\__\___|_| |___/ '@ Write-Host -NoNewLine -ForegroundColor Yellow "Pipeline name "; Write-Host $pipelineName Write-Host -NoNewLine -ForegroundColor Yellow "Container name "; Write-Host $containerName Write-Host -NoNewLine -ForegroundColor Yellow "Image name "; Write-Host $imageName Write-Host -NoNewLine -ForegroundColor Yellow "ArtifactUrl "; Write-Host $artifactUrl.Split('?')[0] Write-Host -NoNewLine -ForegroundColor Yellow "Credential "; if ($credential) { Write-Host "Specified" } else { $password = Get-RandomPassword Write-Host "admin/$password" $credential= (New-Object pscredential 'admin', (ConvertTo-SecureString -String $password -AsPlainText -Force)) } Write-Host -NoNewLine -ForegroundColor Yellow "MemoryLimit "; Write-Host $memoryLimit Write-Host -NoNewLine -ForegroundColor Yellow "Enable Task Scheduler "; Write-Host $enableTaskScheduler Write-Host -NoNewLine -ForegroundColor Yellow "Install Test Libraries "; Write-Host $installTestLibraries Write-Host -NoNewLine -ForegroundColor Yellow "Install Test Framework "; Write-Host $installTestFramework Write-Host -NoNewLine -ForegroundColor Yellow "reuseContainer "; Write-Host $reuseContainer Write-Host -NoNewLine -ForegroundColor Yellow "azureDevOps "; Write-Host $azureDevOps Write-Host -NoNewLine -ForegroundColor Yellow "License file "; if ($licenseFile) { Write-Host "Specified" } else { "Not specified" } Write-Host -NoNewLine -ForegroundColor Yellow "CodeSignCertPfxFile "; if ($codeSignCertPfxFile) { Write-Host "Specified" } else { "Not specified" } Write-Host -NoNewLine -ForegroundColor Yellow "TestResultsFile "; Write-Host $testResultsFile Write-Host -NoNewLine -ForegroundColor Yellow "PackagesFolder "; Write-Host $packagesFolder Write-Host -NoNewLine -ForegroundColor Yellow "OutputFolder "; Write-Host $outputFolder Write-Host -ForegroundColor Yellow "Install Apps" if ($installApps) { $installApps | ForEach-Object { Write-Host "- $_" } } else { Write-Host "- None" } Write-Host -ForegroundColor Yellow "Application folders" if ($appFolders) { $appFolders | ForEach-Object { Write-Host "- $_" } } else { Write-Host "- None" } Write-Host -ForegroundColor Yellow "Test application folders" if ($testFolders) { $testFolders | ForEach-Object { Write-Host "- $_" } } else { Write-Host "- None" } $signApps = ($codeSignCertPfxFile -ne "") Measure-Command { Measure-Command { Write-Host -ForegroundColor Yellow @' _____ _ _ _ _ _ | __ \ | | (_) (_) (_) | |__) | _| | |_ _ __ __ _ __ _ ___ _ __ ___ _ __ _ ___ _ _ __ ___ __ _ __ _ ___ | ___/ | | | | | | '_ \ / _` | / _` |/ _ \ '_ \ / _ \ '__| |/ __| | | '_ ` _ \ / _` |/ _` |/ _ \ | | | |_| | | | | | | | (_| | | (_| | __/ | | | __/ | | | (__ | | | | | | | (_| | (_| | __/ |_| \__,_|_|_|_|_| |_|\__, | \__, |\___|_| |_|\___|_| |_|\___| |_|_| |_| |_|\__,_|\__, |\___| __/ | __/ | __/ | |___/ |___/ |___/ '@ $genericImageName = Get-BestGenericImageName docker pull $genericImageName } | ForEach-Object { Write-Host -ForegroundColor Yellow "`nPulling generic image took $([int]$_.TotalSeconds) seconds" } $createContainer = $true if ($reuseContainer -and (Test-BcContainer -containerName $containerName) -and (Get-BcContainerArtifactUrl -containerName $containerName) -eq $artifactUrl -and (Get-BcContainerOsVersion -containerOrImageName $containerName) -eq (Get-BcContainerOsVersion -containerOrImageName $genericImageName) -and (Get-BcContainerGenericTag -containerOrImageName $containerName) -eq (Get-BcContainerGenericTag -containerOrImageName $genericImageName)) { Write-Host -ForegroundColor Yellow @' _____ _ _ _ | __ \ (_) | | (_) | |__) |___ _ _ ___ _ _ __ __ _ ___ ___ _ __ | |_ __ _ _ _ __ ___ _ __ | _ // _ \ | | / __| | '_ \ / _` | / __/ _ \| '_ \| __/ _` | | '_ \ / _ \ '__| | | \ \ __/ |_| \__ \ | | | | (_| | | (__ (_) | | | | |_ (_| | | | | | __/ | |_| \_\___|\__,_|___/_|_| |_|\__, | \___\___/|_| |_|\__\__,_|_|_| |_|\___|_| __/ | |___/ '@ try { Measure-Command { Restore-DatabasesInBcContainer ` -containerName $containerName ` -bakFolder $pipelineName Invoke-ScriptInBcContainer -containerName $containerName -scriptblock { $mtstartTime = [DateTime]::Now while ([DateTime]::Now.Subtract($mtstartTime).TotalSeconds -le 60) { $tenantInfo = Get-NAVTenant -ServerInstance $ServerInstance -Tenant "default" if ($tenantInfo.State -eq "Operational") { break } Start-Sleep -Seconds 1 } Write-Host "Tenant is $($TenantInfo.State)" } $createContainer = $false } | ForEach-Object { Write-Host -ForegroundColor Yellow "`nRestoring databases took $([int]$_.TotalSeconds) seconds" } } catch { Write-Host -ForegroundColor Red "`nFailed to restore databases, creating new container." } } if ($createContainer) { Write-Host -ForegroundColor Yellow @' _____ _ _ _ _ / ____| | | (_) | | (_) | | _ __ ___ __ _| |_ _ _ __ __ _ ___ ___ _ __ | |_ __ _ _ _ __ ___ _ __ | | | '__/ _ \/ _` | __| | '_ \ / _` | / __/ _ \| '_ \| __/ _` | | '_ \ / _ \ '__| | |____| | | __/ (_| | |_| | | | | (_| | | (__ (_) | | | | |_ (_| | | | | | __/ | \_____|_| \___|\__,_|\__|_|_| |_|\__, | \___\___/|_| |_|\__\__,_|_|_| |_|\___|_| __/ | |___/ '@ Measure-Command { New-BcContainer ` -accept_eula ` -containerName $containerName ` -imageName $imageName ` -artifactUrl $artifactUrl ` -Credential $credential ` -auth UserPassword ` -updateHosts ` -licenseFile $licenseFile ` -EnableTaskScheduler:$enableTaskScheduler ` -MemoryLimit $memoryLimit ` -additionalParameters @("--volume $($baseFolder):c:\sources") } | ForEach-Object { Write-Host -ForegroundColor Yellow "`nCreating container took $([int]$_.TotalSeconds) seconds" } if (($installApps) -or $installTestFramework -or $installTestLibraries) { Write-Host -ForegroundColor Yellow @' _____ _ _ _ _ |_ _| | | | | (_) | | _ __ ___| |_ __ _| | |_ _ __ __ _ __ _ _ __ _ __ ___ | | | '_ \/ __| __/ _` | | | | '_ \ / _` | / _` | '_ \| '_ \/ __| _| |_| | | \__ \ |_ (_| | | | | | | | (_| | | (_| | |_) | |_) \__ \ |_____|_| |_|___/\__\__,_|_|_|_|_| |_|\__, | \__,_| .__/| .__/|___/ __/ | | | | | |___/ |_| |_| '@ Measure-Command { if ($installTestLibraries) { Import-TestToolkitToBcContainer -containerName $containerName -credential $credential -includeTestLibrariesOnly } elseif ($installTestFramework) { Import-TestToolkitToBcContainer -containerName $containerName -credential $credential -includeTestFrameworkOnly } $installApps | ForEach-Object{ # Install dependency } } | ForEach-Object { Write-Host -ForegroundColor Yellow "`nInstalling apps took $([int]$_.TotalSeconds) seconds" } } if ($reuseContainer) { Write-Host -ForegroundColor Yellow @' ____ _ _ _ _ _ | _ \ | | (_) | | | | | | | |_) | __ _ ___| | ___ _ __ __ _ _ _ _ __ __| | __ _| |_ __ _| |__ __ _ ___ ___ ___ | _ < / _` |/ __| |/ / | '_ \ / _` | | | | | '_ \ / _` |/ _` | __/ _` | '_ \ / _` / __|/ _ \ __| | |_) | (_| | (__| <| | | | | (_| | | |_| | |_) | | (_| | (_| | |_ (_| | |_) | (_| \__ \ __\__ \ |____/ \__,_|\___|_|\_\_|_| |_|\__, | \__,_| .__/ \__,_|\__,_|\__\__,_|_.__/ \__,_|___/\___|___/ __/ | | | |___/ |_| '@ Measure-Command { Backup-BcContainerDatabases ` -containerName $containerName ` -bakFolder $pipelineName } | ForEach-Object { Write-Host -ForegroundColor Yellow "`nBacking up databases took $([int]$_.TotalSeconds) seconds" } } } Write-Host -ForegroundColor Yellow @' _____ _ _ _ / ____| (_) (_) | | ___ _ __ ___ _ __ _| |_ _ __ __ _ __ _ _ __ _ __ ___ | | / _ \| '_ ` _ \| '_ \| | | | '_ \ / _` | / _` | '_ \| '_ \/ __| | |____ (_) | | | | | | |_) | | | | | | | (_| | | (_| | |_) | |_) \__ \ \_____\___/|_| |_| |_| .__/|_|_|_|_| |_|\__, | \__,_| .__/| .__/|___/ | | __/ | | | | | |_| |___/ |_| |_| '@ Measure-Command { $apps = @() $testApps = @() $sortedFolders | ForEach-Object { $folder = $_ $appFile = Compile-AppInBcContainer ` -containerName $containerName ` -credential $credential ` -appProjectFolder $folder ` -appOutputFolder $outputFolder ` -appSymbolsFolder $packagesFolder ` -CopyAppToSymbolsFolder ` -AzureDevOps:$azureDevOps if ($testFolders.Contains($folder)) { $testApps += $appFile } else { $apps += $appFile } } } | ForEach-Object { Write-Host -ForegroundColor Yellow "`nCompiling apps took $([int]$_.TotalSeconds) seconds" } if ($signApps -and !$useDevEndpoint) { Write-Host -ForegroundColor Yellow @' _____ _ _ / ____(_) (_) /\ | (___ _ __ _ _ __ _ _ __ __ _ / \ _ __ _ __ ___ \___ \| |/ _` | '_ \| | '_ \ / _` | / /\ \ | '_ \| '_ \/ __| ____) | | (_| | | | | | | | | (_| | / ____ \| |_) | |_) \__ \ |_____/|_|\__, |_| |_|_|_| |_|\__, | /_/ \_\ .__/| .__/|___/ __/ | __/ | | | | | |___/ |___/ |_| |_| '@ Measure-Command { $apps | ForEach-Object { $appFile = $_ Sign-BcContainerApp ` -containerName $containerName ` -appFile $appFile ` -pfxFile $codeSignPfxFile ` -pfxPassword $codeSignPfxPassword } } | ForEach-Object { Write-Host -ForegroundColor Yellow "`nSigning apps took $([int]$_.TotalSeconds) seconds" } } Write-Host -ForegroundColor Yellow @' _____ _ _ _ _ _ | __ \ | | | (_) | | (_) /\ | |__) | _| |__ | |_ ___| |__ _ _ __ __ _ / \ _ __ _ __ ___ | ___/ | | | '_ \| | / __| '_ \| | '_ \ / _` | / /\ \ | '_ \| '_ \/ __| | | | |_| | |_) | | \__ \ | | | | | | | (_| | / ____ \| |_) | |_) \__ \ |_| \__,_|_.__/|_|_|___/_| |_|_|_| |_|\__, | /_/ \_\ .__/| .__/|___/ __/ | | | | | |___/ |_| |_| '@ Measure-Command { $apps+$testApps | ForEach-Object { $appFile = $_ Publish-BcContainerApp ` -containerName $containerName ` -credential $credential ` -appFile $appFile ` -skipVerification:($testApps.Contains($appFile) -or !$signApps -or $useDevEndpoint) ` -sync ` -install ` -useDevEndpoint:$useDevEndpoint } } | ForEach-Object { Write-Host -ForegroundColor Yellow "`nPublishing apps took $([int]$_.TotalSeconds) seconds" } if (!$doNotRunTests) { Remove-Item -Path $testResultsFile -Force -ErrorAction SilentlyContinue if ($testFolders) { Write-Host -ForegroundColor Yellow @' _____ _ _______ _ | __ \ (_) |__ __| | | | |__) | _ _ __ _ __ _ _ __ __ _ | | ___ ___| |_ ___ | _ / | | | '_ \| '_ \| | '_ \ / _` | | |/ _ \ __| __/ __| | | \ \ |_| | | | | | | | | | | | (_| | | | __\__ \ |_\__ \ |_| \_\__,_|_| |_|_| |_|_|_| |_|\__, | |_|\___|___/\__|___/ __/ | |___/ '@ Measure-Command { $testFolders | ForEach-Object { $appJson = Get-Content -Path (Join-Path $_ "app.json") | ConvertFrom-Json Run-TestsInBcContainer ` -containerName $containerName ` -credential $credential ` -extensionId $appJson.id ` -AzureDevOps "$(if($azureDevOps){'error'}else{'no'})" ` -XUnitResultFileName $testResultsFile ` -AppendToXUnitResultFile } } | ForEach-Object { Write-Host -ForegroundColor Yellow "`nRunning tests took $([int]$_.TotalSeconds) seconds" } } } if (!$reuseContainer -and !$keepContainer) { Write-Host -ForegroundColor Yellow @' _____ _ _____ _ _ | __ \ (_) / ____| | | (_) | |__) |___ _ __ ___ _____ ___ _ __ __ _ | | ___ _ __ | |_ __ _ _ _ __ ___ _ __ | _ // _ \ '_ ` _ \ / _ \ \ / / | '_ \ / _` | | | / _ \| '_ \| __/ _` | | '_ \ / _ \ '__| | | \ \ __/ | | | | | (_) \ V /| | | | | (_| | | |____ (_) | | | | |_ (_| | | | | | __/ | |_| \_\___|_| |_| |_|\___/ \_/ |_|_| |_|\__, | \_____\___/|_| |_|\__\__,_|_|_| |_|\___|_| __/ | |___/ '@ Measure-Command { Remove-BcContainer ` -containerName $containerName } | ForEach-Object { Write-Host -ForegroundColor Yellow "`nRemoving container took $([int]$_.TotalSeconds) seconds" } } } | ForEach-Object { Write-Host -ForegroundColor Yellow "`nAL Pipeline finished in $([int]$_.TotalSeconds) seconds" } } |