PowerShell/tools/ci.psm1
Aditya Patwardhan cbd255e461 Code coverage artifacts (#8993)
Move the `TestPackage.zip` under code coverage and remove `tests.zip` as it is not needed anymore.
2019-02-28 14:38:45 -08:00

825 lines
27 KiB
PowerShell

# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
$ErrorActionPreference = 'continue'
$repoRoot = Join-Path $PSScriptRoot '..'
$script:administratorsGroupSID = "S-1-5-32-544"
$script:usersGroupSID = "S-1-5-32-545"
# set .NET path
$dotNetPath = "$env:USERPROFILE\Appdata\Local\Microsoft\dotnet"
if(Test-Path $dotNetPath)
{
$env:PATH = $dotNetPath + ';' + $env:PATH
}
# import build into the global scope so it can be used by packaging
Import-Module (Join-Path $repoRoot 'build.psm1') -Scope Global
Import-Module (Join-Path $repoRoot 'tools\packaging')
function New-LocalUser
{
<#
.SYNOPSIS
Creates a local user with the specified username and password
.DESCRIPTION
.EXAMPLE
.PARAMETER
username Username of the user which will be created
.PARAMETER
password Password of the user which will be created
.OUTPUTS
.NOTES
#>
param(
[Parameter(Mandatory=$true)]
[string] $username,
[Parameter(Mandatory=$true)]
[string] $password
)
$LocalComputer = [ADSI] "WinNT://$env:computername";
$user = $LocalComputer.Create('user', $username);
$user.SetPassword($password) | out-null;
$user.SetInfo() | out-null;
}
<#
Converts SID to NT Account Name
#>
function ConvertTo-NtAccount
{
param(
[Parameter(Mandatory=$true)]
[string] $sid
)
(new-object System.Security.Principal.SecurityIdentifier($sid)).translate([System.Security.Principal.NTAccount]).Value
}
<#
Add a user to a local security group
#>
function Add-UserToGroup
{
param(
[Parameter(Mandatory=$true)]
[string] $username,
[Parameter(Mandatory=$true, ParameterSetName = "SID")]
[string] $groupSid,
[Parameter(Mandatory=$true, ParameterSetName = "Name")]
[string] $group
)
$userAD = [ADSI] "WinNT://$env:computername/${username},user"
if($PsCmdlet.ParameterSetName -eq "SID")
{
$ntAccount=ConvertTo-NtAccount $groupSid
$group =$ntAccount.Split("\\")[1]
}
$groupAD = [ADSI] "WinNT://$env:computername/${group},group"
$groupAD.Add($userAD.AdsPath);
}
# tests if we should run a daily build
# returns true if the build is scheduled
# or is a pushed tag
Function Test-DailyBuild
{
$trueString = 'True'
if(($env:PS_DAILY_BUILD -eq $trueString) -or $env:BUILD_REASON -eq 'Schedule')
{
return $true
}
# if [feature] is in the commit message,
# Run Daily tests
$commitMessage = Get-CommitMessage
Write-log -message "commitMessage: $commitMessage"
if($commitMessage -match '\[feature\]' -or $env:FORCE_FEATURE -eq 'True')
{
Set-BuildVariable -Name PS_DAILY_BUILD -Value $trueString
return $true
}
else
{
return $false
}
}
# Returns the commit message for the current build
function Get-CommitMessage
{
if ($env:BUILD_SOURCEVERSIONMESSAGE -match 'Merge\s*([0-9A-F]*)')
{
# We are in VSTS and have a commit ID in the Source Version Message
$commitId = $Matches[1]
return &git log --format=%B -n 1 $commitId
}
else
{
Write-Log "Unknown BUILD_SOURCEVERSIONMESSAGE format '$env:BUILD_SOURCEVERSIONMESSAGE'" -Verbose
}
}
# Sets a build variable
Function Set-BuildVariable
{
param(
[Parameter(Mandatory=$true)]
[string]
$Name,
[Parameter(Mandatory=$true)]
[string]
$Value
)
if($env:TF_BUILD)
{
# In VSTS
Write-Host "##vso[task.setvariable variable=$Name;]$Value"
# The variable will not show up until the next task.
# Setting in the current session for the same behavior as the CI
Set-Item env:/$name -Value $Value
}
else
{
Set-Item env:/$name -Value $Value
}
}
# Emulates running all of CI but locally
function Invoke-CIFull
{
param(
[switch] $CleanRepo
)
if($CleanRepo)
{
Clear-PSRepo
}
Invoke-CIInstall
Invoke-CIBuild
Invoke-CITest -ErrorAction Continue
Invoke-CIFinish
}
# Implements the CI 'build_script' step
function Invoke-CIBuild
{
$releaseTag = Get-ReleaseTag
# check to be sure our test tags are correct
$result = Get-PesterTag
if ( $result.Result -ne "Pass" )
{
$result.Warnings
throw "Tags must be CI, Feature, Scenario, or Slow"
}
if(Test-DailyBuild)
{
Start-PSBuild -Configuration 'CodeCoverage' -PSModuleRestore -CI -ReleaseTag $releaseTag
}
Start-PSBuild -CrossGen -PSModuleRestore -Configuration 'Release' -CI -ReleaseTag $releaseTag
Save-PSOptions
$options = (Get-PSOptions)
$path = split-path -path $options.Output
$psOptionsPath = (Join-Path -Path $PSScriptRoot -ChildPath '../psoptions.json')
$buildZipPath = (Join-Path -Path $PSScriptRoot -ChildPath '../build.zip')
Compress-Archive -Path $path -DestinationPath $buildZipPath
Push-Artifact -Path $psOptionsPath -Name 'build'
Push-Artifact -Path $buildZipPath -Name 'build'
}
# Implements the CI 'install' step
function Invoke-CIInstall
{
# Make sure we have all the tags
Sync-PSTags -AddRemoteIfMissing
$releaseTag = Get-ReleaseTag
if(Test-DailyBuild)
{
if ($env:BUILD_REASON -eq 'Schedule')
{
Write-Host "##vso[build.updatebuildnumber]Daily-$env:BUILD_SOURCEBRANCHNAME-$env:BUILD_SOURCEVERSION-$((get-date).ToString("yyyyMMddhhss"))"
}
}
if ($env:TF_BUILD)
{
# Generate new credential for CI (only) remoting tests.
Write-Log -Message "Creating account for remoting tests in CI."
# Password
$randomObj = [System.Random]::new()
$password = ""
1..(Get-Random -Minimum 15 -Maximum 126) | ForEach-Object { $password = $password + [char]$randomObj.next(45,126) }
# Account
$userName = 'ciRemote'
New-LocalUser -username $userName -password $password
Add-UserToGroup -username $userName -groupSid $script:administratorsGroupSID
# Provide credentials globally for remote tests.
$ss = ConvertTo-SecureString -String $password -AsPlainText -Force
$ciRemoteCredential = [PSCredential]::new("$env:COMPUTERNAME\$userName", $ss)
$ciRemoteCredential | Export-Clixml -Path "$env:TEMP\CIRemoteCred.xml" -Force
# Check that LocalAccountTokenFilterPolicy policy is set, since it is needed for remoting
# using above local admin account.
Write-Log -Message "Checking for LocalAccountTokenFilterPolicy in the CI."
$haveLocalAccountTokenFilterPolicy = $false
try
{
$haveLocalAccountTokenFilterPolicy = ((Get-ItemPropertyValue -Path HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System -Name LocalAccountTokenFilterPolicy) -eq 1)
}
# ignore if anything is caught:
catch {}
if (!$haveLocalAccountTokenFilterPolicy)
{
Write-Verbose "Setting the LocalAccountTokenFilterPolicy for remoting tests"
Set-ItemProperty -Path HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System -Name LocalAccountTokenFilterPolicy -Value 1
}
}
Set-BuildVariable -Name TestPassed -Value False
Start-PSBootstrap -Confirm:$false
}
function Invoke-CIxUnit
{
param(
[switch]
$SkipFailing
)
$env:CoreOutput = Split-Path -Parent (Get-PSOutput -Options (Get-PSOptions))
if(!(Test-Path "$env:CoreOutput\pwsh.exe"))
{
throw "CoreCLR pwsh.exe was not built"
}
$xUnitTestResultsFile = "$pwd\xUnitTestResults.xml"
Start-PSxUnit -xUnitTestResultsFile $xUnitTestResultsFile
Push-Artifact -Path $xUnitTestResultsFile -name xunit
if(!$SkipFailing.IsPresent)
{
# Fail the build, if tests failed
Test-XUnitTestResults -TestResultsFile $xUnitTestResultsFile
}
}
# Implement CI 'Test_script'
function Invoke-CITest
{
[CmdletBinding()]
param(
[ValidateSet('UnelevatedPesterTests', 'ElevatedPesterTests')]
[string] $Purpose,
[ValidateSet('CI', 'Others')]
[string] $TagSet
)
# CoreCLR
$env:CoreOutput = Split-Path -Parent (Get-PSOutput -Options (Get-PSOptions))
Write-Host -Foreground Green 'Run CoreCLR tests'
$testResultsNonAdminFile = "$pwd\TestsResultsNonAdmin-$TagSet.xml"
$testResultsAdminFile = "$pwd\TestsResultsAdmin-$TagSet.xml"
if(!(Test-Path "$env:CoreOutput\pwsh.exe"))
{
throw "CoreCLR pwsh.exe was not built"
}
# Pester doesn't allow Invoke-Pester -TagAll@('CI', 'RequireAdminOnWindows') currently
# https://github.com/pester/Pester/issues/608
# To work-around it, we exlude all categories, but 'CI' from the list
switch ($TagSet) {
'CI' {
Write-Host -Foreground Green 'Running "CI" CoreCLR tests..'
$ExcludeTag = @('Slow', 'Feature', 'Scenario')
}
'Others' {
Write-Host -Foreground Green 'Running non-CI CoreCLR tests..'
$ExcludeTag = @('CI')
}
Default {
throw "Unknow TagSet: '$TagSet'"
}
}
# Get the experimental feature names and the tests associated with them
$ExperimentalFeatureTests = Get-ExperimentalFeatureTests
if ($Purpose -eq 'UnelevatedPesterTests') {
$arguments = @{
Bindir = $env:CoreOutput
OutputFile = $testResultsNonAdminFile
Unelevate = $true
Terse = $true
Tag = @()
ExcludeTag = $ExcludeTag + 'RequireAdminOnWindows'
}
Start-PSPester @arguments -Title "Pester Unelevated - $TagSet"
# Fail the build, if tests failed
Test-PSPesterResults -TestResultsFile $testResultsNonAdminFile
# Run tests with specified experimental features enabled
foreach ($entry in $ExperimentalFeatureTests.GetEnumerator())
{
$featureName = $entry.Key
$testFiles = $entry.Value
$expFeatureTestResultFile = "$pwd\TestsResultsNonAdmin.$featureName.xml"
$arguments['OutputFile'] = $expFeatureTestResultFile
$arguments['ExperimentalFeatureName'] = $featureName
if ($testFiles.Count -eq 0) {
# If an empty array is specified for the feature name, we run all tests with the feature enabled.
# This allows us to prevent regressions to a critical engine experimental feature.
$arguments.Remove('Path')
} else {
# If a non-empty string or array is specified for the feature name, we only run those test files.
$arguments['Path'] = $testFiles
}
Start-PSPester @arguments -Title "Pester Experimental Unelevated - $featureName"
# Fail the build, if tests failed
Test-PSPesterResults -TestResultsFile $expFeatureTestResultFile
}
}
if ($Purpose -eq 'ElevatedPesterTests') {
$arguments = @{
Terse = $true
Bindir = $env:CoreOutput
OutputFile = $testResultsAdminFile
Tag = @('RequireAdminOnWindows')
ExcludeTag = $ExcludeTag
}
Start-PSPester @arguments -Title "Pester Elevated - $TagSet"
# Fail the build, if tests failed
Test-PSPesterResults -TestResultsFile $testResultsAdminFile
# Run tests with specified experimental features enabled
foreach ($entry in $ExperimentalFeatureTests.GetEnumerator())
{
$featureName = $entry.Key
$testFiles = $entry.Value
$expFeatureTestResultFile = "$pwd\TestsResultsAdmin.$featureName.xml"
$arguments['OutputFile'] = $expFeatureTestResultFile
$arguments['ExperimentalFeatureName'] = $featureName
if ($testFiles.Count -eq 0)
{
# If an empty array is specified for the feature name, we run all tests with the feature enabled.
# This allows us to prevent regressions to a critical engine experimental feature.
$arguments.Remove('Path')
}
else
{
# If a non-empty string or array is specified for the feature name, we only run those test files.
$arguments['Path'] = $testFiles
}
Start-PSPester @arguments -Title "Pester Experimental Elevated - $featureName"
# Fail the build, if tests failed
Test-PSPesterResults -TestResultsFile $expFeatureTestResultFile
}
}
Set-BuildVariable -Name TestPassed -Value True
}
# Implement CI 'after_test' phase
function Invoke-CIAfterTest
{
[CmdletBinding()]
param()
if (Test-DailyBuild)
{
Start-PSBuild -Configuration 'CodeCoverage' -Clean
$codeCoverageOutput = Split-Path -Parent (Get-PSOutput)
$codeCoverageArtifacts = Compress-CoverageArtifacts -CodeCoverageOutput $codeCoverageOutput
Write-Host -ForegroundColor Green 'Upload CodeCoverage artifacts'
$codeCoverageArtifacts | ForEach-Object {
Push-Artifact -Path $_ -Name 'CodeCoverage'
}
New-TestPackage -Destination (Get-Location).Path
$testPackageFullName = Join-Path $pwd 'TestPackage.zip'
Write-Verbose "Created TestPackage.zip" -Verbose
Write-Host -ForegroundColor Green 'Upload test package'
Push-Artifact $testPackageFullName -Name 'CodeCoverage'
}
}
# Wrapper to push artifact
function Push-Artifact
{
param(
[Parameter(Mandatory)]
[ValidateScript({Test-Path -Path $_})]
$Path,
[string]
$Name
)
if(!$Name)
{
$artifactName = [system.io.path]::GetFileName($Path)
}
else
{
$artifactName = $Name
}
if ($env:TF_BUILD) {
# In Azure DevOps
Write-Host "##vso[artifact.upload containerfolder=$artifactName;artifactname=$artifactName;]$Path"
}
}
function Compress-CoverageArtifacts
{
param([string] $CodeCoverageOutput)
# Create archive for test content, OpenCover module and CodeCoverage build
$artifacts = New-Object System.Collections.ArrayList
Add-Type -AssemblyName System.IO.Compression.FileSystem
$resolvedPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath((Join-Path $PSScriptRoot '..\test\tools\OpenCover'))
$zipOpenCoverPath = Join-Path $pwd 'OpenCover.zip'
[System.IO.Compression.ZipFile]::CreateFromDirectory($resolvedPath, $zipOpenCoverPath)
$null = $artifacts.Add($zipOpenCoverPath)
$zipCodeCoveragePath = Join-Path $pwd "CodeCoverage.zip"
Write-Verbose "Zipping ${CodeCoverageOutput} into $zipCodeCoveragePath" -verbose
[System.IO.Compression.ZipFile]::CreateFromDirectory($CodeCoverageOutput, $zipCodeCoveragePath)
$null = $artifacts.Add($zipCodeCoveragePath)
return $artifacts
}
function Get-ReleaseTag
{
$metaDataPath = Join-Path -Path $PSScriptRoot -ChildPath 'metadata.json'
$metaData = Get-Content $metaDataPath | ConvertFrom-Json
$releaseTag = $metadata.PreviewReleaseTag
if($env:BUILD_BUILID)
{
$releaseTag = $releaseTag.split('.')[0..2] -join '.'
$releaseTag = $releaseTag + '.' + $env:BUILD_BUILID
}
return $releaseTag
}
# Implements CI 'on_finish' step
function Invoke-CIFinish
{
param(
[string] $NuGetKey
)
try {
$releaseTag = Get-ReleaseTag
$previewVersion = $releaseTag.Split('-')
$previewPrefix = $previewVersion[0]
$previewLabel = $previewVersion[1].replace('.','')
if(Test-DailyBuild)
{
$previewLabel= "daily{0}" -f $previewLabel
}
$preReleaseVersion = "$previewPrefix-$previewLabel.$env:BUILD_BUILDID"
# Build clean before backing to remove files from testing
Start-PSBuild -CrossGen -PSModuleRestore -Configuration 'Release' -ReleaseTag $preReleaseVersion -Clean
# Build packages
$packages = Start-PSPackage -Type msi,nupkg,zip -ReleaseTag $preReleaseVersion -SkipReleaseChecks
$artifacts = New-Object System.Collections.ArrayList
foreach ($package in $packages) {
if (Test-Path $package)
{
Write-Log "Package found: $package"
}
else
{
Write-Warning -Message "Package NOT found: $package"
}
if($package -is [string])
{
$null = $artifacts.Add($package)
}
elseif($package -is [pscustomobject] -and $package.msi)
{
$null = $artifacts.Add($package.msi)
$null = $artifacts.Add($package.wixpdb)
}
}
# the packaging tests find the MSI package using env:PSMsiX64Path
$env:PSMsiX64Path = $artifacts | Where-Object { $_.EndsWith(".msi")}
# Install the latest Pester and import it
Install-Module Pester -Force -SkipPublisherCheck
Import-Module Pester -Force
# start the packaging tests and get the results
$packagingTestResult = Invoke-Pester -Script (Join-Path $repoRoot '.\test\packaging\windows\') -PassThru
# fail the CI job if the tests failed, or nothing passed
if($packagingTestResult.FailedCount -ne 0 -or !$packagingTestResult.PassedCount)
{
throw "Packaging tests failed ($($packagingTestResult.FailedCount) failed/$($packagingTestResult.PassedCount) passed)"
}
# only publish assembly nuget packages if it is a daily build and tests passed
if((Test-DailyBuild) -and $env:TestPassed -eq 'True')
{
Publish-NuGetFeed -OutputPath .\nuget-artifacts -ReleaseTag $preReleaseVersion
$nugetArtifacts = Get-ChildItem .\nuget-artifacts -ErrorAction SilentlyContinue | ForEach-Object { $_.FullName }
if($nugetArtifacts)
{
$artifacts.AddRange($nugetArtifacts)
}
}
if (Test-DailyBuild)
{
# produce win-arm and win-arm64 packages if it is a daily build
Start-PSBuild -Restore -Runtime win-arm -PSModuleRestore -Configuration 'Release' -ReleaseTag $releaseTag
$arm32Package = Start-PSPackage -Type zip -WindowsRuntime win-arm -ReleaseTag $releaseTag -SkipReleaseChecks
$artifacts.Add($arm32Package)
Start-PSBuild -Restore -Runtime win-arm64 -PSModuleRestore -Configuration 'Release' -ReleaseTag $releaseTag
$arm64Package = Start-PSPackage -Type zip -WindowsRuntime win-arm64 -ReleaseTag $releaseTag -SkipReleaseChecks
$artifacts.Add($arm64Package)
}
$pushedAllArtifacts = $true
$artifacts | ForEach-Object {
Write-Log -Message "Pushing $_ as CI artifact"
if(Test-Path $_)
{
Push-Artifact -Path $_ -Name 'artifacts'
}
else
{
$pushedAllArtifacts = $false
Write-Warning "Artifact $_ does not exist."
}
if($NuGetKey -and $env:NUGET_URL -and [system.io.path]::GetExtension($_) -ieq '.nupkg')
{
Write-Log "pushing $_ to $env:NUGET_URL"
Start-NativeExecution -sb {dotnet nuget push $_ --api-key $NuGetKey --source "$env:NUGET_URL/api/v2/package"} -IgnoreExitcode
}
}
if(!$pushedAllArtifacts)
{
throw "Some artifacts did not exist!"
}
}
catch
{
Write-Host -Foreground Red $_
Write-Host -Foreground Red $_.ScriptStackTrace
throw $_
}
}
# Bootstrap script for Linux and macOS
function Invoke-Bootstrap-Stage
{
$createPackages = Test-DailyBuild
Write-Log -Message "Executing ci.psm1 Bootstrap Stage"
# Make sure we have all the tags
Sync-PSTags -AddRemoteIfMissing
Start-PSBootstrap -Package:$createPackages
}
# Build and test script for Linux and macOS:
function Invoke-LinuxTests
{
$releaseTag = Get-ReleaseTag
Write-Log -Message "Executing ci.psm1 build and test on a Linux based operating system."
$originalProgressPreference = $ProgressPreference
$ProgressPreference = 'SilentlyContinue'
try {
# We use CrossGen build to run tests only if it's the daily build.
Start-PSBuild -CrossGen -PSModuleRestore -CI -ReleaseTag $releaseTag -Configuration 'Release'
}
finally
{
$ProgressPreference = $originalProgressPreference
}
$output = Split-Path -Parent (Get-PSOutput -Options (Get-PSOptions))
$testResultsNoSudo = "$pwd/TestResultsNoSudo.xml"
$testResultsSudo = "$pwd/TestResultsSudo.xml"
$excludeTag = @('RequireSudoOnUnix')
$noSudoPesterParam = @{
'BinDir' = $output
'PassThru' = $true
'Terse' = $true
'Tag' = @()
'ExcludeTag' = $excludeTag
'OutputFile' = $testResultsNoSudo
}
# create packages if it is a full build
$isFullBuild = Test-DailyBuild
$createPackages = $isFullBuild
if ($isFullBuild) {
$noSudoPesterParam['Tag'] = @('CI','Feature','Scenario')
} else {
$noSudoPesterParam['Tag'] = @('CI')
$noSudoPesterParam['ThrowOnFailure'] = $true
}
if ($hasRunFailingTestTag) {
$noSudoPesterParam['IncludeFailingTest'] = $true
}
# Get the experimental feature names and the tests associated with them
$ExperimentalFeatureTests = Get-ExperimentalFeatureTests
# Running tests which do not require sudo.
$pesterPassThruNoSudoObject = Start-PSPester @noSudoPesterParam -Title 'Pester No Sudo'
# Running tests that do not require sudo, with specified experimental features enabled
$noSudoResultsWithExpFeatures = @()
foreach ($entry in $ExperimentalFeatureTests.GetEnumerator()) {
$featureName = $entry.Key
$testFiles = $entry.Value
$expFeatureTestResultFile = "$pwd\TestResultsNoSudo.$featureName.xml"
$noSudoPesterParam['OutputFile'] = $expFeatureTestResultFile
$noSudoPesterParam['ExperimentalFeatureName'] = $featureName
if ($testFiles.Count -eq 0) {
# If an empty array is specified for the feature name, we run all tests with the feature enabled.
# This allows us to prevent regressions to a critical engine experimental feature.
$noSudoPesterParam.Remove('Path')
}
else
{
# If a non-empty string or array is specified for the feature name, we only run those test files.
$noSudoPesterParam['Path'] = $testFiles
}
$passThruResult = Start-PSPester @noSudoPesterParam -Title "Pester Experimental No Sudo - $featureName"
$noSudoResultsWithExpFeatures += $passThruResult
}
# Running tests, which require sudo.
$sudoPesterParam = $noSudoPesterParam.Clone()
$sudoPesterParam.Remove('Path')
$sudoPesterParam['Tag'] = @('RequireSudoOnUnix')
$sudoPesterParam['ExcludeTag'] = @()
$sudoPesterParam['Sudo'] = $true
$sudoPesterParam['OutputFile'] = $testResultsSudo
$pesterPassThruSudoObject = Start-PSPester @sudoPesterParam -Title 'Pester Sudo'
# Running tests that require sudo, with specified experimental features enabled
$sudoResultsWithExpFeatures = @()
foreach ($entry in $ExperimentalFeatureTests.GetEnumerator()) {
$featureName = $entry.Key
$testFiles = $entry.Value
$expFeatureTestResultFile = "$pwd\TestResultsSudo.$featureName.xml"
$sudoPesterParam['OutputFile'] = $expFeatureTestResultFile
$sudoPesterParam['ExperimentalFeatureName'] = $featureName
if ($testFiles.Count -eq 0)
{
# If an empty array is specified for the feature name, we run all tests with the feature enabled.
# This allows us to prevent regressions to a critical engine experimental feature.
$sudoPesterParam.Remove('Path')
}
else
{
# If a non-empty string or array is specified for the feature name, we only run those test files.
$sudoPesterParam['Path'] = $testFiles
}
$passThruResult = Start-PSPester @sudoPesterParam -Title "Pester Experimental Sudo - $featureName"
$sudoResultsWithExpFeatures += $passThruResult
}
# Determine whether the build passed
try {
$allTestResultsWithNoExpFeature = @($pesterPassThruNoSudoObject, $pesterPassThruSudoObject)
$allTestResultsWithExpFeatures = $noSudoResultsWithExpFeatures + $sudoResultsWithExpFeatures
# This throws if there was an error:
$allTestResultsWithNoExpFeature | ForEach-Object { Test-PSPesterResults -ResultObject $_ }
$allTestResultsWithExpFeatures | ForEach-Object { Test-PSPesterResults -ResultObject $_ -CanHaveNoResult }
$result = "PASS"
} catch {
# The build failed, set the result:
$resultError = $_
$result = "FAIL"
}
try {
$xUnitTestResultsFile = "$pwd/xUnitTestResults.xml"
Start-PSxUnit -xUnitTestResultsFile $xUnitTestResultsFile
# If there are failures, Test-XUnitTestResults throws
Test-XUnitTestResults -TestResultsFile $xUnitTestResultsFile
} catch {
$result = "FAIL"
if (!$resultError)
{
$resultError = $_
}
}
if ($createPackages)
{
$packageParams = @{}
$packageParams += @{ReleaseTag=$releaseTag}
# Only build packages for PowerShell/PowerShell repository
# branches, not pull requests
$packages = @(Start-PSPackage @packageParams -SkipReleaseChecks)
foreach($package in $packages)
{
if (Test-Path $package)
{
Write-Log "Package found: $package"
}
else
{
Write-Error -Message "Package NOT found: $package"
}
# Publish the packages to the nuget feed if:
# 1 - It's a Daily build (already checked, for not a PR)
# 2 - We have the info to publish (NUGET_KEY and NUGET_URL)
# 3 - it's a nupkg file
if($isFullBuild -and $NugetKey -and $env:NUGET_URL -and [system.io.path]::GetExtension($package) -ieq '.nupkg')
{
Write-Log "pushing $package to $env:NUGET_URL"
Start-NativeExecution -sb {dotnet nuget push $package --api-key $NugetKey --source "$env:NUGET_URL/api/v2/package"} -IgnoreExitcode
}
if($isFullBuild)
{
if ($package -isnot [System.IO.FileInfo])
{
$packageObj = Get-Item $package
Write-Error -Message "The PACKAGE is not a FileInfo object"
}
else
{
$packageObj = $package
}
Write-Log -message "Artifacts directory: ${env:BUILD_ARTIFACTSTAGINGDIRECTORY}"
Copy-Item $packageObj.FullName -Destination "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}" -Force
}
}
if ($IsLinux)
{
# Create and package Raspbian .tgz
Start-PSBuild -PSModuleRestore -Clean -Runtime linux-arm -Configuration 'Release'
$armPackage = Start-PSPackage @packageParams -Type tar-arm -SkipReleaseChecks
Copy-Item $armPackage -Destination "${env:BUILD_ARTIFACTSTAGINGDIRECTORY}" -Force
}
if ($isFullBuild)
{
New-TestPackage -Destination "${env:SYSTEM_ARTIFACTSDIRECTORY}"
}
}
# If the tests did not pass, throw the reason why
if ( $result -eq "FAIL" )
{
Write-Warning "Tests failed. See the issue below."
Throw $resultError
}
else
{
Write-Verbose "Tests did not fail! Nice job!"
}
}