Add VSTS CI for Windows (#7536)

- Add VSTS CI for Windows
    - Disable `Access-denied test for Get-Item C:\windows\appcompat\Programs\Install -ErrorAction Stop`, because the path does not always exist
        - https://github.com/PowerShell/PowerShell/issues/7553
    - Disable `Should give .sys file if the fullpath is specified with hidden and force parameter`, because pagefile.sys doesn't always exist and other files don't meet test's requirement.
        - https://github.com/PowerShell/PowerShell/issues/7554
    - Disable some `Test-Connection` tests for same reasons they failed on VSTS Linux
        - https://github.com/PowerShell/PowerShell/issues/7555
    - Disable `Test-FileCatalog should pass when catalog is in the same folder as files being tested`, because the CmdLet does not work in that scenario
         - Also, give details needed to investigate when the test fails
         - https://github.com/PowerShell/PowerShell/issues/7556
    - Update `appveyor.psm1` to work with VSTS
    - Update `HelpersRemoting.psm1` `New-RemoteSession` to work for CimSession (discovered an issue during the investigation)
    - Update `Test wildcard with drive relative directory path` to work when there are multiple drives
         - Disable on non-windows machines since the test is assuming drive letters
    - Update `New-CimSession` Tests to requireAdmin
         - Also, make sure session name is a string
    - Add functions to save and restore psoptions
    - update `.gitatttributes` so files clone like they do on appveyor
This commit is contained in:
Travis Plunk 2018-08-17 22:06:51 -07:00 committed by GitHub
parent 9fa97adeba
commit 40532d9a2e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 245 additions and 36 deletions

2
.gitattributes vendored
View file

@ -2,3 +2,5 @@ CHANGELOG.md merge=union
* text=auto
*.png binary
*.rtf binary
testablescript.ps1 text eol=lf
TestFileCatalog.txt text eol=lf

65
.vsts-ci/windows.yml Normal file
View file

@ -0,0 +1,65 @@
name: PR-$(System.PullRequest.PullRequestNumber)-$(Date:yyyyMMdd)$(Rev:.rr)
queue:
name: Hosted VS2017
parallel: 2 # Limit to two agents at a time
matrix:
UnelevatedPesterTests:
Purpose: UnelevatedPesterTests
ElevatedPesterTests_xUnit_Packaging:
Purpose: ElevatedPesterTests_xUnit_Packaging
variables:
GIT_CONFIG_PARAMETERS: "'core.autocrlf=false'"
DOTNET_CLI_TELEMETRY_OPTOUT: 1
POWERSHELL_TELEMETRY_OPTOUT: 1
# Avoid expensive initialization of dotnet cli, see: http://donovanbrown.com/post/Stop-wasting-time-during-NET-Core-builds
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
resources:
- repo: self
clean: true
steps:
- powershell: Write-Host "##vso[build.updatebuildnumber]$env:BUILD_SOURCEBRANCHNAME-$env:BUILD_SOURCEVERSION-$((get-date).ToString("yyyyMMddhhss"))"
displayName: Set Build Name for Non-PR
condition: ne(variables['Build.Reason'], 'PullRequest')
- powershell: |
git submodule update --init
displayName: SubModule Init
condition: succeededOrFailed()
- powershell: |
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
Import-Module .\tools\Appveyor.psm1
Invoke-AppveyorInstall
displayName: Bootstrap
condition: succeededOrFailed()
- powershell: |
Import-Module .\tools\Appveyor.psm1
Invoke-AppveyorBuild
Save-PSOptions
displayName: Build
condition: succeeded()
- powershell: |
Import-Module .\tools\Appveyor.psm1
Restore-PSOptions
Invoke-AppveyorTest -Purpose '$(Purpose)'
displayName: Test
condition: succeeded()
- powershell: |
Import-Module .\tools\Appveyor.psm1
Restore-PSOptions
Invoke-AppveyorAfterTest
displayName: AfterTest
condition: succeededOrFailed()
- powershell: |
Import-Module .\tools\Appveyor.psm1
Restore-PSOptions
Invoke-AppveyorFinish
displayName: Finish
condition: eq(variables['Purpose'], 'ElevatedPesterTests_xUnit_Packaging')

View file

@ -116,8 +116,7 @@ function Get-EnvironmentInformation
if ($Environment.IsWindows)
{
$environment += @{'IsAdmin' = (New-Object Security.Principal.WindowsPrincipal ([Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)}
# Can't use $env:HOME - not available on older systems (e.g. in AppVeyor)
$environment += @{'nugetPackagesRoot' = "${env:HOMEDRIVE}${env:HOMEPATH}\.nuget\packages"}
$environment += @{'nugetPackagesRoot' = "${env:USERPROFILE}\.nuget\packages"}
}
else
{
@ -876,14 +875,15 @@ function New-PSOptions {
$RootInfo['IsValid'] = $true
}
return @{ RootInfo = [PSCustomObject]$RootInfo
Top = $Top
Configuration = $Configuration
Framework = $Framework
Runtime = $Runtime
Output = $Output
CrossGen = $CrossGen.IsPresent
PSModuleRestore = $PSModuleRestore.IsPresent }
return New-PSOptionsObject `
-RootInfo ([PSCustomObject]$RootInfo) `
-Top $Top `
-Runtime $Runtime `
-Crossgen $Crossgen.IsPresent `
-Configuration $Configuration `
-PSModuleRestore $PSModuleRestore.IsPresent `
-Framework $Framework `
-Output $Output
}
# Get the Options of the last build
@ -2996,6 +2996,102 @@ function Restore-PSOptions {
Set-PSOptions -Options $options
}
# Save PSOptions to be restored by Restore-PSOptions
function Save-PSOptions {
param(
[ValidateScript({$parent = Split-Path $_;if($parent){Test-Path $parent}else{return $true}})]
[ValidateNotNullOrEmpty()]
[string]
$PSOptionsPath = (Join-Path -Path $PSScriptRoot -ChildPath 'psoptions.json'),
[ValidateNotNullOrEmpty()]
[object]
$Options = (Get-PSOptions -DefaultToNew)
)
$Options | ConvertTo-Json -Depth 3 | Out-File -Encoding utf8 -FilePath $PSOptionsPath
}
# Restore PSOptions
# Optionally remove the PSOptions file
function Restore-PSOptions {
param(
[ValidateScript({Test-Path $_})]
[string]
$PSOptionsPath = (Join-Path -Path $PSScriptRoot -ChildPath 'psoptions.json'),
[switch]
$Remove
)
$options = Get-Content -Path $PSOptionsPath | ConvertFrom-Json
if($Remove)
{
# Remove PSOptions.
# The file is only used to set the PSOptions.
Remove-Item -Path $psOptionsPath -Force
}
$newOptions = New-PSOptionsObject `
-RootInfo $options.RootInfo `
-Top $options.Top `
-Runtime $options.Runtime `
-Crossgen $options.Crossgen `
-Configuration $options.Configuration `
-PSModuleRestore $options.PSModuleRestore `
-Framework $options.Framework `
-Output $options.Output
Set-PSOptions -Options $newOptions
}
function New-PSOptionsObject
{
param(
[PSCustomObject]
$RootInfo,
[Parameter(Mandatory)]
[String]
$Top,
[Parameter(Mandatory)]
[String]
$Runtime,
[Parameter(Mandatory)]
[Bool]
$CrossGen,
[Parameter(Mandatory)]
[String]
$Configuration,
[Parameter(Mandatory)]
[Bool]
$PSModuleRestore,
[Parameter(Mandatory)]
[String]
$Framework,
[Parameter(Mandatory)]
[String]
$Output
)
return @{
RootInfo = $RootInfo
Top = $Top
Configuration = $Configuration
Framework = $Framework
Runtime = $Runtime
Output = $Output
CrossGen = $CrossGen
PSModuleRestore = $PSModuleRestore
}
}
$script:RESX_TEMPLATE = @'
<?xml version="1.0" encoding="utf-8"?>
<root>

View file

@ -5,7 +5,7 @@ try {
$PSDefaultParameterValues['it:pending'] = $true
}
Describe "New-CimSession" -Tag @("CI") {
Describe "New-CimSession" -Tag @("CI","RequireAdminOnWindows") {
BeforeAll {
$sessions = @()
}
@ -16,7 +16,7 @@ try {
}
It "A cim session can be created" {
$sessionName = [guid]::NewGuid()
$sessionName = [guid]::NewGuid().Guid
$session = New-CimSession -ComputerName . -Name $sessionName
$sessions += $session
$session.Name | Should -BeExactly $sessionName
@ -24,7 +24,7 @@ try {
}
It "A Cim session can be retrieved" {
$sessionName = [guid]::NewGuid()
$sessionName = [guid]::NewGuid().Guid
$session = New-CimSession -ComputerName . -Name $sessionName
$sessions += $session
(Get-CimSession -Name $sessionName).InstanceId | Should -Be $session.InstanceId
@ -33,7 +33,7 @@ try {
}
It "A cim session can be removed" {
$sessionName = [guid]::NewGuid()
$sessionName = [guid]::NewGuid().Guid
$session = New-CimSession -ComputerName . -Name $sessionName
$sessions += $session
$session.Name | Should -BeExactly $sessionName

View file

@ -16,13 +16,21 @@ Describe "Tests Get-Command with relative paths and wildcards" -Tag "CI" {
$commandInfo = Get-Command Get-Date -ShowCommandInfo
}
It "Test wildcard with drive relative directory path" {
# this test doesn't test anything on non-windows platforms
It "Test wildcard with drive relative directory path" -Skip:(!$IsWindows) {
$pathName = Join-Path $TestDrive "WildCardCommandA*"
$driveOffset = $pathName.IndexOf(":")
$pathName = $pathName.Substring($driveOffset + 1)
$result = Get-Command -Name $pathName
$result | Should -Not -BeNullOrEmpty
$result.Name | Should -Be WildCardCommandA.exe
$driveName = $pathName.Substring(0,$driveOffset + 1)
Push-Location -Path $driveName
try {
$pathName = $pathName.Substring($driveOffset + 1)
$result = Get-Command -Name $pathName
$result | Should -Not -BeNullOrEmpty
$result.Name | Should -Be WildCardCommandA.exe
}
catch {
Pop-Location
}
}
It "Test wildcard with relative directory path" {

View file

@ -252,7 +252,8 @@ Describe "Basic FileSystem Provider Tests" -Tags "CI" {
It "Access-denied test for <cmdline>" -Skip:(-not $IsWindows) -TestCases @(
# NOTE: ensure the fileNameBase parameter is unique for each test case; it is used to generate a unique error and done file name.
@{cmdline = "Get-Item $protectedPath2 -ErrorAction Stop"; expectedError = "ItemExistsUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetItemCommand"}
# The following test does not consistently work on windows
# @{cmdline = "Get-Item $protectedPath2 -ErrorAction Stop"; expectedError = "ItemExistsUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetItemCommand"}
@{cmdline = "Get-ChildItem $protectedPath -ErrorAction Stop"; expectedError = "DirUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand"}
@{cmdline = "New-Item -Type File -Path $newItemPath -ErrorAction Stop"; expectedError = "NewItemUnauthorizedAccessError,Microsoft.PowerShell.Commands.NewItemCommand"}
@{cmdline = "Rename-Item -Path $protectedPath -NewName bar -ErrorAction Stop"; expectedError = "RenameItemIOError,Microsoft.PowerShell.Commands.RenameItemCommand"},

View file

@ -161,7 +161,8 @@ Describe "Get-ChildItem" -Tags "CI" {
(Get-ChildItem -Path $searchRoot -Directory -Recurse).Count | Should -Be 1
}
It "Should give .sys file if the fullpath is specified with hidden and force parameter" -Skip:(!$IsWindows) {
# VSTS machines don't have a page file
It "Should give .sys file if the fullpath is specified with hidden and force parameter" -Pending {
# Don't remove!!! It is special test for hidden and opened file with exclusive lock.
$file = Get-ChildItem -path "$env:SystemDrive\\pagefile.sys" -Hidden
$file | Should not be $null

View file

@ -79,7 +79,7 @@ Describe "Test-Connection" -tags "CI" {
}
# In VSTS, address is 0.0.0.0
It "Force IPv4 with implicit PingOptions" -Skip:(Test-IsVstsLinux) {
It "Force IPv4 with implicit PingOptions" -Skip:((Test-IsVstsLinux) -or (Test-IsVstsWindows)) {
$result = Test-Connection $realName -Count 1 -IPv4
$result.Replies[0].Address | Should -BeExactly $realAddress
@ -90,7 +90,7 @@ Describe "Test-Connection" -tags "CI" {
}
# In VSTS, address is 0.0.0.0
It "Force IPv4 with explicit PingOptions" -Skip:(Test-IsVstsLinux) {
It "Force IPv4 with explicit PingOptions" -Skip:((Test-IsVstsLinux) -or (Test-IsVstsWindows)) {
$result1 = Test-Connection $realName -Count 1 -IPv4 -MaxHops 10 -DontFragment
$result2 = Test-Connection $realName -Count 1 -IPv4 -MaxHops 1 -DontFragment
@ -196,8 +196,9 @@ Describe "Test-Connection" -tags "CI" {
}
# TODO: We skip the MTUSizeDetect tests on Unix because we expect 'TtlExpired' but get 'TimeOut' internally from .Net Core
# Skipping on VSTS in Windows due to `TimedOut`
Context "MTUSizeDetect" {
It "MTUSizeDetect works" -Pending:(!$isWindows) {
It "MTUSizeDetect works" -Pending:(!$isWindows -or (Test-IsVstsWindows)) {
$result = Test-Connection $realName -MTUSizeDetect
$result | Should -BeOfType "System.Net.NetworkInformation.PingReply"
@ -206,7 +207,7 @@ Describe "Test-Connection" -tags "CI" {
$result.MTUSize | Should -BeGreaterThan 0
}
It "Quiet works" -Pending:(!$isWindows) {
It "Quiet works" -Pending:(!$isWindows -or (Test-IsVstsWindows)) {
$result = Test-Connection $realName -MTUSizeDetect -Quiet
$result | Should -BeOfType "Int32"
@ -216,7 +217,7 @@ Describe "Test-Connection" -tags "CI" {
Context "TraceRoute" {
# Hangs in VSTS Linux
It "TraceRoute works" -skip:(Test-IsVstsLinux) {
It "TraceRoute works" -skip:((Test-IsVstsLinux) -or (Test-IsVstsWindows)) {
$result = Test-Connection $realName -TraceRoute
$replies = $result.Replies
# Check target host reply.
@ -243,7 +244,7 @@ Describe "Test-Connection" -tags "CI" {
}
# Hangs in VSTS Linux
It "Quiet works" -skip:(Test-IsVstsLinux) {
It "Quiet works" -skip:((Test-IsVstsLinux) -or (Test-IsVstsWindows)) {
$result = Test-Connection $realName -TraceRoute -Quiet
$result | Should -BeTrue

View file

@ -226,9 +226,10 @@ Describe "Test suite for NewFileCatalogAndTestFileCatalogCmdlets" -Tags "CI" {
CompareHashTables $result.CatalogItems $expectedPathsAndHashes
}
It "NewFileCatalogFolderWhenCatalogFileIsCreatedInsideSameFolder" {
# This is failing saying the exact thing that it says is supposed to work does not
It "Test-FileCatalog should pass when catalog is in the same folder as files being tested" -Pending {
$catalogPath = "$env:TEMP\UserConfigProv\NewFileCatalogFolderWhenCatalogFileIsCreatedInsideSameFolder.cat"
$catalogPath = "$env:TEMP\UserConfigProv\catalog.cat"
try
{
copy-item "$testDataPath\UserConfigProv" $env:temp -Recurse -ErrorAction SilentlyContinue
@ -236,6 +237,13 @@ Describe "Test suite for NewFileCatalogAndTestFileCatalogCmdlets" -Tags "CI" {
# When -Path is not specified, it should use current directory
$null = New-FileCatalog -CatalogFilePath $catalogPath -CatalogVersion 1.0
$result = Test-FileCatalog -CatalogFilePath $catalogPath
if($result -ne 'Valid')
{
# We will fail, Write why.
$detailResult = Test-FileCatalog -CatalogFilePath $catalogPath -Detailed
$detailResult | ConvertTo-Json | Write-Verbose -Verbose
}
}
finally
{

View file

@ -26,6 +26,7 @@ FunctionsToExport = @(
'Test-IsElevated'
'Test-IsRoot'
'Test-IsVstsLinux'
'Test-IsVstsWindows'
'Test-TesthookIsSet'
'Wait-FileToBePresent'
'Wait-UntilTrue'

View file

@ -260,3 +260,9 @@ function Test-IsVstsLinux
{
return ($env:TF_BUILD -and $IsLinux)
}
# Tests if we are running is a VSTS Linux Build
function Test-IsVstsWindows
{
return ($env:TF_BUILD -and $IsWindows)
}

View file

@ -36,6 +36,7 @@ function CreateParameters
[string] $ComputerName,
[string[]] $Name,
[string] $ConfigurationName,
[switch] $CimSession,
[System.Management.Automation.Remoting.PSSessionOption] $SessionOption,
[System.Management.Automation.Runspaces.PSSession[]] $Session)
@ -56,7 +57,14 @@ function CreateParameters
}
if ($Name) {
$parameters["Name"] = $Name
if($CimSession.IsPresent)
{
$parameters["Name"] = [String] $Name
}
else
{
$parameters["Name"] = $Name
}
}
if ($ConfigurationName) {
@ -88,7 +96,7 @@ function New-RemoteSession
[switch] $CimSession,
[System.Management.Automation.Remoting.PSSessionOption] $SessionOption)
$parameters = CreateParameters -Name $Name -ConfigurationName $ConfigurationName -SessionOption $SessionOption
$parameters = CreateParameters -Name $Name -ConfigurationName $ConfigurationName -SessionOption $SessionOption -CimSession:$CimSession.IsPresent
if ($CimSession) {
$session = New-CimSession @parameters

View file

@ -124,6 +124,14 @@ Function Set-BuildVariable
{
Set-AppveyorBuildVariable @PSBoundParameters
}
elseif($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 AppVeyor
Set-Item env:/$name -Value $Value
}
else
{
Set-Item env:/$name -Value $Value
@ -221,7 +229,7 @@ function Invoke-AppVeyorInstall
Update-AppveyorBuild -message $buildName
}
if ($env:APPVEYOR)
if ($env:APPVEYOR -or $env:TF_BUILD)
{
#
# Generate new credential for appveyor (only) remoting tests.
@ -360,7 +368,7 @@ function Invoke-AppVeyorTest
Tag = @()
ExcludeTag = $ExcludeTag + 'RequireAdminOnWindows'
}
Start-PSPester @arguments
Start-PSPester @arguments -Title 'Pester Unelevated'
Write-Host -Foreground Green 'Upload CoreCLR Non-Admin test results'
Update-AppVeyorTestResults -resultsFile $testResultsNonAdminFile
# Fail the build, if tests failed
@ -382,7 +390,7 @@ function Invoke-AppVeyorTest
# 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
Start-PSPester @arguments -Title "Pester Experimental Unelevated - $featureName"
Write-Host -ForegroundColor Green "Upload CoreCLR Non-Admin test results for experimental feature '$featureName'"
Update-AppVeyorTestResults -resultsFile $expFeatureTestResultFile
@ -399,7 +407,7 @@ function Invoke-AppVeyorTest
Tag = @('RequireAdminOnWindows')
ExcludeTag = $ExcludeTag
}
Start-PSPester @arguments
Start-PSPester @arguments -Title 'Pester Elevated'
Write-Host -Foreground Green 'Upload CoreCLR Admin test results'
Update-AppVeyorTestResults -resultsFile $testResultsAdminFile
@ -433,7 +441,7 @@ function Invoke-AppVeyorTest
# 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
Start-PSPester @arguments -Title "Pester Experimental Elevated - $featureName"
Write-Host -ForegroundColor Green "Upload CoreCLR Admin test results for experimental feature '$featureName'"
Update-AppVeyorTestResults -resultsFile $expFeatureTestResultFile
@ -594,6 +602,10 @@ function Invoke-AppveyorFinish
{
Push-AppveyorArtifact $_
}
elseif ($env:TF_BUILD) {
# In VSTS
Write-Host "##vso[artifact.upload containerfolder=artifacts;artifactname=artifacts;]$_"
}
}
else
{