371 lines
12 KiB
PowerShell
371 lines
12 KiB
PowerShell
# Copyright (c) Microsoft Corporation.
|
|
# Licensed under the MIT License.
|
|
|
|
$script:forcePull = $true
|
|
# Get docker Engine OS
|
|
function Get-DockerEngineOs
|
|
{
|
|
docker info --format '{{ .OperatingSystem }}'
|
|
}
|
|
|
|
# Call Docker with appropriate result checksfunction Invoke-Docker
|
|
function Invoke-Docker
|
|
{
|
|
param(
|
|
[Parameter(Mandatory=$true)]
|
|
[string[]]
|
|
$Command,
|
|
[ValidateSet("error","warning",'ignore')]
|
|
$FailureAction = 'error',
|
|
|
|
[Parameter(Mandatory=$true)]
|
|
[string[]]
|
|
$Params,
|
|
|
|
[switch]
|
|
$PassThru,
|
|
[switch]
|
|
$SuppressHostOutput
|
|
)
|
|
|
|
$ErrorActionPreference = 'Continue'
|
|
|
|
# Log how we are running docker for troubleshooting issues
|
|
Write-Verbose "Running docker $command $params" -Verbose
|
|
if($SuppressHostOutput.IsPresent)
|
|
{
|
|
$result = docker $command $params 2>&1
|
|
}
|
|
else
|
|
{
|
|
&'docker' $command $params 2>&1 | Tee-Object -Variable result -ErrorAction SilentlyContinue | Out-String -Stream -ErrorAction SilentlyContinue | Write-Host -ErrorAction SilentlyContinue
|
|
}
|
|
|
|
$dockerExitCode = $LASTEXITCODE
|
|
if($PassThru.IsPresent)
|
|
{
|
|
Write-Verbose "passing through docker result$($result.length)..." -Verbose
|
|
return $result
|
|
}
|
|
elseif($dockerExitCode -ne 0 -and $FailureAction -eq 'error')
|
|
{
|
|
Write-Error "docker $command failed with: $result" -ErrorAction Stop
|
|
return $false
|
|
}
|
|
elseif($dockerExitCode -ne 0 -and $FailureAction -eq 'warning')
|
|
{
|
|
Write-Warning "docker $command failed with: $result"
|
|
return $false
|
|
}
|
|
elseif($dockerExitCode -ne 0)
|
|
{
|
|
return $false
|
|
}
|
|
|
|
return $true
|
|
}
|
|
|
|
# Return a list of Linux Container Test Cases
|
|
function Get-LinuxContainer
|
|
{
|
|
foreach($os in 'centos7','ubuntu16.04')
|
|
{
|
|
Write-Output @{
|
|
Name = $os
|
|
Path = "$PSScriptRoot/../release/$os"
|
|
}
|
|
}
|
|
}
|
|
|
|
# Return a list of Windows Container Test Cases
|
|
function Get-WindowsContainer
|
|
{
|
|
foreach($os in 'windowsservercore','nanoserver')
|
|
{
|
|
Write-Output @{
|
|
Name = $os
|
|
Path = "$PSScriptRoot/../release/$os"
|
|
}
|
|
}
|
|
}
|
|
|
|
$script:repoName = 'microsoft/powershell'
|
|
function Get-RepoName
|
|
{
|
|
return $script:repoName
|
|
}
|
|
|
|
function Set-RepoName
|
|
{
|
|
param([string]$RepoName)
|
|
|
|
$script:repoName = $RepoName
|
|
$script:forcePull = $false
|
|
}
|
|
|
|
function Test-SkipWindows
|
|
{
|
|
[bool] $canRunWindows = (Get-DockerEngineOs) -like 'Windows*'
|
|
return ($IsLinux -or $IsMacOS -or !$canRunWindows)
|
|
}
|
|
|
|
function Test-SkipLinux
|
|
{
|
|
$os = Get-DockerEngineOs
|
|
|
|
switch -wildcard ($os)
|
|
{
|
|
'*Linux*' {
|
|
return $false
|
|
}
|
|
'*Mac' {
|
|
return $false
|
|
}
|
|
# Docker for Windows means we are running the linux kernel
|
|
'Docker for Windows' {
|
|
return $false
|
|
}
|
|
'Windows*' {
|
|
return $true
|
|
}
|
|
default {
|
|
throw "Unknown docker os '$os'"
|
|
}
|
|
}
|
|
}
|
|
|
|
function Get-TestContext
|
|
{
|
|
param(
|
|
[ValidateSet('Linux','Windows','macOS')]
|
|
[string]$Type
|
|
)
|
|
|
|
$resultFileName = 'results.xml'
|
|
$logFileName = 'results.log'
|
|
$containerTestDrive = '/test'
|
|
|
|
# Return a windows context if the Context in Windows *AND*
|
|
# the current system is windows, otherwise Join-path will fail.
|
|
if($Type -eq 'Windows' -and $IsWindows)
|
|
{
|
|
$ContainerTestDrive = 'C:\test'
|
|
}
|
|
$resolvedTestDrive = (Resolve-Path "Testdrive:\").providerPath
|
|
|
|
return @{
|
|
ResolvedTestDrive = $resolvedTestDrive
|
|
ResolvedXmlPath = Join-Path $resolvedTestDrive -ChildPath $resultFileName
|
|
ResolvedLogPath = Join-Path $resolvedTestDrive -ChildPath $logFileName
|
|
ContainerTestDrive = $ContainerTestDrive
|
|
ContainerXmlPath = Join-Path $containerTestDrive -ChildPath $resultFileName
|
|
ContainerLogPath = Join-Path $containerTestDrive -ChildPath $logFileName
|
|
Type = $Type
|
|
ForcePull = $script:forcePull
|
|
}
|
|
}
|
|
|
|
function Get-ContainerPowerShellVersion
|
|
{
|
|
param(
|
|
[HashTable] $TestContext,
|
|
[string] $RepoName,
|
|
[string] $Name
|
|
)
|
|
|
|
$imageTag = "${script:repoName}:${Name}"
|
|
|
|
if($TestContext.ForcePull)
|
|
{
|
|
$null=Invoke-Docker -Command 'image', 'pull' -Params $imageTag -SuppressHostOutput
|
|
}
|
|
|
|
$runParams = @()
|
|
$localVolumeName = $testContext.resolvedTestDrive
|
|
$runParams += '--rm'
|
|
if($TestContext.Type -ne 'Windows' -and $IsWindows)
|
|
{
|
|
# use a container volume on windows because host volumes are not automatic
|
|
$volumeName = "test-volume-" + (Get-Random -Minimum 100 -Maximum 999)
|
|
|
|
# using alpine because it's tiny
|
|
$null=Invoke-Docker -Command create -Params '-v', '/test', '--name', $volumeName, 'alpine' -SuppressHostOutput
|
|
$runParams += '--volumes-from'
|
|
$runParams += $volumeName
|
|
}
|
|
else {
|
|
$runParams += '-v'
|
|
$runParams += "${localVolumeName}:$($testContext.containerTestDrive)"
|
|
}
|
|
|
|
$runParams += $imageTag
|
|
$runParams += 'pwsh'
|
|
$runParams += '-c'
|
|
$runParams += ('$PSVersionTable.PSVersion.ToString() | out-string | out-file -encoding ascii -FilePath '+$testContext.containerLogPath)
|
|
|
|
$null = Invoke-Docker -Command run -Params $runParams -SuppressHostOutput
|
|
if($TestContext.Type -ne 'Windows' -and $IsWindows)
|
|
{
|
|
$null = Invoke-Docker -Command cp -Params "${volumeName}:$($testContext.containerLogPath)", $TestContext.ResolvedLogPath
|
|
$null = Invoke-Docker -Command container, rm -Params $volumeName, '--force' -SuppressHostOutput
|
|
}
|
|
return (Get-Content -Encoding Ascii $testContext.resolvedLogPath)[0]
|
|
}
|
|
|
|
# Function defines a config mapping for testing Preview packages.
|
|
# The list of supported OS for each release can be found here:
|
|
# https://github.com/PowerShell/PowerShell-Docs/blob/staging/reference/docs-conceptual/PowerShell-Core-Support.md#supported-platforms
|
|
function Get-DefaultPreviewConfigForPackageValidation
|
|
{
|
|
# format: <DockerfileFolderName>=<PartOfPackageFilename>
|
|
@{ 'centos7'='rhel.7';
|
|
'debian.9'='debian.9';
|
|
'fedora28'='rhel.7';
|
|
'opensuse42.3'='linux-x64.tar.gz';
|
|
'ubuntu16.04'='ubuntu.16.04';
|
|
'ubuntu18.04'='ubuntu.18.04';
|
|
'fxdependent-centos7'='linux-x64-fxdependent.tar.gz';
|
|
'fxdependent-debian.9'='linux-x64-fxdependent.tar.gz';
|
|
'fxdependent-fedora28'='linux-x64-fxdependent.tar.gz';
|
|
'fxdependent-opensuse42.3'='linux-x64-fxdependent.tar.gz';
|
|
'fxdependent-ubuntu16.04'='linux-x64-fxdependent.tar.gz';
|
|
'fxdependent-ubuntu18.04'='linux-x64-fxdependent.tar.gz';
|
|
'fxdependent-dotnetsdk-latest'='linux-x64-fxd-dotnetsdk.tar.gz'
|
|
}
|
|
}
|
|
|
|
# Function defines a config mapping for testing Stable packages.
|
|
# The list of supported OS for each release can be found here:
|
|
# https://github.com/PowerShell/PowerShell-Docs/blob/staging/reference/docs-conceptual/PowerShell-Core-Support.md#supported-platforms
|
|
function Get-DefaultStableConfigForPackageValidation
|
|
{
|
|
# format: <DockerfileFolderName>=<PartOfPackageFilename>
|
|
@{ 'centos7'='rhel.7';
|
|
'debian.9'='debian.9';
|
|
'opensuse42.3'='linux-x64.tar.gz';
|
|
'ubuntu16.04'='ubuntu.16.04';
|
|
'fxdependent-centos7'='linux-x64-fxdependent.tar.gz';
|
|
'fxdependent-debian.9'='linux-x64-fxdependent.tar.gz';
|
|
'fxdependent-opensuse42.3'='linux-x64-fxdependent.tar.gz';
|
|
'fxdependent-ubuntu16.04'='linux-x64-fxdependent.tar.gz'
|
|
}
|
|
}
|
|
|
|
# Returns a list of files in a specified Azure container.
|
|
function Get-PackageNamesOnAzureBlob
|
|
{
|
|
param(
|
|
[string]
|
|
$ContainerUrl,
|
|
|
|
# $SAS (shared access signature) param should include beginning '?' and trailing '&'
|
|
[string]
|
|
$SAS
|
|
)
|
|
|
|
|
|
$response = Invoke-RestMethod -Method Get -Uri $($ContainerUrl + $SAS + 'restype=container&comp=list')
|
|
|
|
$xmlResponce = [xml]$response.Substring($response.IndexOf('<EnumerationResults')) # remove some bad chars in the beginning that break XML parsing
|
|
($xmlResponce.EnumerationResults.Blobs.Blob).Name
|
|
}
|
|
|
|
# This function is used for basic validation of PS packages during a release;
|
|
# During the process Docker files are filled out and executed with Docker build;
|
|
# During the build PS packages are downloaded onto Docker containers, installed and selected Pester tests from PowerShell Github repo are executed.
|
|
# This function must be run on a Docker host machine in 'Linux containers' mode, such as Windows 10 server with Hyper-V role installed.
|
|
function Test-PSPackage
|
|
{
|
|
param(
|
|
[string]
|
|
[Parameter(Mandatory=$true)]
|
|
$PSPackageLocation, # e.g. Azure container storage url
|
|
[string]
|
|
$SAS,# $SAS (shared access signature) param should include beginning '?' and trailing '&'
|
|
[Hashtable]
|
|
$Config, # hashtable that maps packages to dockerfiles; for example see Get-DefaultConfigForPackageValidation
|
|
[string]
|
|
$TestList = "/PowerShell/test/powershell/Modules/PackageManagement/PackageManagement.Tests.ps1,/PowerShell/test/powershell/engine/Module",
|
|
[string]
|
|
$TestDownloadCommand = "git clone --recursive https://github.com/PowerShell/PowerShell.git",
|
|
[switch]
|
|
$Preview = $false
|
|
)
|
|
|
|
$PSPackageLocation = $PSPackageLocation.TrimEnd('/','\') # code below assumes there is no trailing separator in PSPackageLocation url
|
|
$RootFolder = Join-Path $PSScriptRoot 'Templates'
|
|
|
|
|
|
$packageList = Get-PackageNamesOnAzureBlob -ContainerUrl $PSPackageLocation -SAS $SAS
|
|
if (!$Config)
|
|
{
|
|
if ($Preview)
|
|
{
|
|
$Config = Get-DefaultPreviewConfigForPackageValidation
|
|
}
|
|
else
|
|
{
|
|
$Config = Get-DefaultStableConfigForPackageValidation
|
|
}
|
|
}
|
|
|
|
# pre-process $Config: verify build directories and packages exist
|
|
$map = @{}
|
|
foreach($kp in $Config.GetEnumerator())
|
|
{
|
|
$buildDir = Join-Path $RootFolder $kp.Key
|
|
$packageName = $packageList | Where-Object {$_ -like $('*'+$kp.Value+'*')}
|
|
|
|
if (-not (Test-Path $buildDir))
|
|
{
|
|
Write-Error "Directory does Not exist - $buildDir; Check `$Config parameter and '$RootFolder' folder"
|
|
}
|
|
elseif (-not ($packageName))
|
|
{
|
|
Write-Error "Can not find package that matches filter *$($kp.Value)*; Check `$Config parameter and '$PSPackageLocation'"
|
|
}
|
|
else
|
|
{
|
|
$map.Add($buildDir, $packageName)
|
|
}
|
|
}
|
|
|
|
Write-Verbose "Using configuration:" -Verbose
|
|
Write-Verbose ($map | Format-List | Out-String) -Verbose
|
|
|
|
$results = @{}
|
|
$returnValue = $true
|
|
|
|
# run builds sequentially, but don't block for errors so that configs after failed one can run
|
|
foreach($kp in $map.GetEnumerator())
|
|
{
|
|
$dockerDirPath = $kp.Key
|
|
$packageFileName = $kp.Value
|
|
|
|
$buildArgs = @()
|
|
|
|
$buildArgs += "--build-arg","PACKAGENAME=$packageFileName"
|
|
$buildArgs += "--build-arg","PACKAGELOCATION=$PSPackageLocation"
|
|
if ($Preview)
|
|
{
|
|
$buildArgs += "--build-arg","PREVIEWSUFFIX=-preview"
|
|
}
|
|
$buildArgs += "--build-arg","TESTLIST=$TestList"
|
|
$buildArgs += "--build-arg","TESTDOWNLOADCOMMAND=$TestDownloadCommand"
|
|
$buildArgs += "--no-cache"
|
|
$buildArgs += $dockerDirPath
|
|
|
|
$dockerResult = Invoke-Docker -Command 'build' -Params $buildArgs -FailureAction warning
|
|
|
|
$confName = Split-Path -Leaf $dockerDirPath
|
|
$results.Add($confName, $dockerResult)
|
|
if (-not $dockerResult) {$returnValue = $false}
|
|
}
|
|
|
|
# in the end print results for all configurations
|
|
Write-Verbose "Package validation results:" -Verbose
|
|
$results
|
|
|
|
return $returnValue
|
|
}
|