diff --git a/.vsts-ci/linux.yml b/.vsts-ci/linux.yml index 9faa155f74d..f5623ccb2a1 100644 --- a/.vsts-ci/linux.yml +++ b/.vsts-ci/linux.yml @@ -47,11 +47,15 @@ variables: __SuppressAnsiEscapeSequences: 1 resources: -- repo: self - clean: true + repositories: + - repository: Docker + type: github + endpoint: PowerShell + name: PowerShell/PowerShell-Docker + ref: master stages: -- stage: BuildLinux +- stage: BuildLinuxStage displayName: Build for Linux jobs: - template: templates/ci-build.yml @@ -60,33 +64,34 @@ stages: jobName: linux_build displayName: linux Build -- stage: TestLinux - displayName: Test for Linux +- stage: TestUbuntu + displayName: Test for Ubuntu + dependsOn: [BuildLinuxStage] jobs: - template: templates/nix-test.yml parameters: - name: Linux + name: Ubuntu pool: ubuntu-20.04 purpose: UnelevatedPesterTests tagSet: CI - template: templates/nix-test.yml parameters: - name: Linux + name: Ubuntu pool: ubuntu-20.04 purpose: ElevatedPesterTests tagSet: CI - template: templates/nix-test.yml parameters: - name: Linux + name: Ubuntu pool: ubuntu-20.04 purpose: UnelevatedPesterTests tagSet: Others - template: templates/nix-test.yml parameters: - name: Linux + name: Ubuntu pool: ubuntu-20.04 purpose: ElevatedPesterTests tagSet: Others @@ -95,24 +100,72 @@ stages: parameters: pool: ubuntu-20.04 +- stage: TestContainer + displayName: Test in a container + dependsOn: [BuildLinuxStage] + jobs: + - job: getContainerJob + displayName: Choose a container + pool: + vmImage: ubuntu-20.04 + steps: + - checkout: self + clean: true + + - checkout: Docker + clean: true + + - pwsh: | + $matrix = ./PowerShell-Docker/build.ps1 -GenerateMatrixJson -FullJson -Channel preview | ConvertFrom-Json + # Filter out containers that won't run on AzDevOps Linux host as an agent + # Windows, nano server, alpine, and any ARM image + $linuxImages = $matrix.preview | + Where-Object {$_.osversion -notmatch 'windows|nano|alpine|arm'} | + Select-Object JobName, Taglist | + Sort-Object -property JobName + # Force mariner for now, later we will add automated rotation by the month. + $marinerImage = $linuxImages | where-object {$_.JobName -like 'mariner*'} + Import-Module ./PowerShell/tools/ci.psm1 + $tag = $marinerImage.Taglist -split ';' | select-object -first 1 + $containerName = "mcr.microsoft.com/powershell/test-deps:$tag" + Set-BuildVariable -Name containerName -Value $containerName -IsOutput + Set-BuildVariable -Name containerBuildName -Value $marinerImage.JobName -IsOutput + name: getContainerTask + displayName: Get Container + continueOnError: true + + - template: templates/test/nix-container-test.yml + parameters: + name: container + pool: ubuntu-20.04 + purpose: UnelevatedPesterTests + tagSet: CI + + - template: templates/test/nix-container-test.yml + parameters: + name: container + pool: ubuntu-20.04 + purpose: ElevatedPesterTests + tagSet: CI + + - template: templates/test/nix-container-test.yml + parameters: + name: container + pool: ubuntu-20.04 + purpose: UnelevatedPesterTests + tagSet: Others + + - template: templates/test/nix-container-test.yml + parameters: + name: container + pool: ubuntu-20.04 + purpose: ElevatedPesterTests + tagSet: Others + - stage: PackageLinux displayName: Package Linux - dependsOn: ["BuildLinux"] + dependsOn: ["BuildLinuxStage"] jobs: - template: linux/templates/packaging.yml parameters: pool: ubuntu-20.04 - -- stage: CodeCovTestPackage - displayName: CodeCoverage and Test Packages - dependsOn: [] # by specifying an empty array, this stage doesn't depend on the stage before it - jobs: - - job: CodeCovTestPackage - displayName: CodeCoverage and Test Packages - pool: - vmImage: ubuntu-20.04 - steps: - - pwsh: | - Import-Module .\tools\ci.psm1 - New-CodeCoverageAndTestPackage - displayName: CodeCoverage and Test Package diff --git a/.vsts-ci/misc-analysis.yml b/.vsts-ci/misc-analysis.yml index e1f2d8ebfc6..b7d451ea199 100644 --- a/.vsts-ci/misc-analysis.yml +++ b/.vsts-ci/misc-analysis.yml @@ -5,14 +5,12 @@ trigger: branches: include: - master - - release* - feature* pr: branches: include: - master - - release* - feature* resources: diff --git a/.vsts-ci/templates/nix-test.yml b/.vsts-ci/templates/nix-test.yml index f2f04d9dd5c..ab3985dacd6 100644 --- a/.vsts-ci/templates/nix-test.yml +++ b/.vsts-ci/templates/nix-test.yml @@ -1,71 +1,19 @@ parameters: pool: 'macOS-latest' - parentJobs: [] purpose: '' tagSet: 'CI' name: 'mac' jobs: - job: ${{ parameters.name }}_test_${{ parameters.purpose }}_${{ parameters.tagSet }} - dependsOn: - ${{ parameters.parentJobs }} + pool: vmImage: ${{ parameters.pool }} displayName: ${{ parameters.name }} Test - ${{ parameters.purpose }} - ${{ parameters.tagSet }} steps: - - pwsh: | - Get-ChildItem -Path env: - displayName: Capture Environment - condition: succeededOrFailed() - - - task: DownloadBuildArtifacts@0 - displayName: 'Download build artifacts' - inputs: - downloadType: specific - itemPattern: | - build/**/* - downloadPath: '$(System.ArtifactsDirectory)' - - - pwsh: | - Get-ChildItem "$(System.ArtifactsDirectory)\*" -Recurse - displayName: 'Capture Artifacts Directory' - continueOnError: true - - - pwsh: | - Import-Module .\tools\ci.psm1 - Invoke-CIInstall -SkipUser - displayName: Bootstrap - - - task: ExtractFiles@1 - displayName: 'Extract Build ZIP' - inputs: - archiveFilePatterns: '$(System.ArtifactsDirectory)/build/build.zip' - destinationFolder: '$(System.ArtifactsDirectory)/bins' - - - bash: | - find "$(System.ArtifactsDirectory)/bins" -type d -exec chmod +rwx {} \; - find "$(System.ArtifactsDirectory)/bins" -type f -exec chmod +rw {} \; - displayName: 'Fix permissions' - continueOnError: true - - - pwsh: | - Get-ChildItem "$(System.ArtifactsDirectory)\bins\*" -Recurse -ErrorAction SilentlyContinue - displayName: 'Capture Extracted Build ZIP' - continueOnError: true - - - pwsh: | - Import-Module .\tools\ci.psm1 - Restore-PSOptions -PSOptionsPath '$(System.ArtifactsDirectory)\build\psoptions.json' - $options = (Get-PSOptions) - $rootPath = '$(System.ArtifactsDirectory)\bins' - $originalRootPath = Split-Path -path $options.Output - $path = Join-Path -path $rootPath -ChildPath (split-path -leaf -path $originalRootPath) - $pwshPath = Join-Path -path $path -ChildPath 'pwsh' - chmod a+x $pwshPath - $options.Output = $pwshPath - Set-PSOptions $options - Invoke-CITest -Purpose '${{ parameters.purpose }}' -TagSet '${{ parameters.tagSet }}' - displayName: Test - condition: succeeded() + - template: ./test/nix-test-steps.yml + parameters: + purpose: ${{ parameters.purpose }} + tagSet: ${{ parameters.tagSet }} diff --git a/.vsts-ci/templates/test/nix-container-test.yml b/.vsts-ci/templates/test/nix-container-test.yml new file mode 100644 index 00000000000..87827ac2508 --- /dev/null +++ b/.vsts-ci/templates/test/nix-container-test.yml @@ -0,0 +1,28 @@ +parameters: + pool: 'macOS-latest' + purpose: '' + tagSet: 'CI' + name: 'mac' + +jobs: +- job: ${{ parameters.name }}_test_${{ parameters.purpose }}_${{ parameters.tagSet }} + + dependsOn: + - getContainerJob + + variables: + getContainerJob: $[ dependencies.getContainerJob.outputs['getContainerTask.containerName'] ] + __INCONTAINER: 1 + + container: $[ variables.getContainerJob ] + + pool: + vmImage: ${{ parameters.pool }} + + displayName: ${{ parameters.name }} Test - ${{ parameters.purpose }} - ${{ parameters.tagSet }} + + steps: + - template: ./nix-test-steps.yml + parameters: + purpose: ${{ parameters.purpose }} + tagSet: ${{ parameters.tagSet }} diff --git a/.vsts-ci/templates/test/nix-test-steps.yml b/.vsts-ci/templates/test/nix-test-steps.yml new file mode 100644 index 00000000000..c0329888006 --- /dev/null +++ b/.vsts-ci/templates/test/nix-test-steps.yml @@ -0,0 +1,59 @@ +parameters: + purpose: '' + tagSet: 'CI' + +steps: + - pwsh: | + Get-ChildItem -Path env: + displayName: Capture Environment + condition: succeededOrFailed() + + - task: DownloadBuildArtifacts@0 + displayName: 'Download build artifacts' + inputs: + downloadType: specific + itemPattern: | + build/**/* + downloadPath: '$(System.ArtifactsDirectory)' + + - pwsh: | + Get-ChildItem "$(System.ArtifactsDirectory)\*" -Recurse + displayName: 'Capture Artifacts Directory' + continueOnError: true + + - pwsh: | + Import-Module .\tools\ci.psm1 + Invoke-CIInstall -SkipUser + displayName: Bootstrap + + - task: ExtractFiles@1 + displayName: 'Extract Build ZIP' + inputs: + archiveFilePatterns: '$(System.ArtifactsDirectory)/build/build.zip' + destinationFolder: '$(System.ArtifactsDirectory)/bins' + + - bash: | + find "$(System.ArtifactsDirectory)/bins" -type d -exec chmod +rwx {} \; + find "$(System.ArtifactsDirectory)/bins" -type f -exec chmod +rw {} \; + displayName: 'Fix permissions' + continueOnError: true + + - pwsh: | + Get-ChildItem "$(System.ArtifactsDirectory)\bins\*" -Recurse -ErrorAction SilentlyContinue + displayName: 'Capture Extracted Build ZIP' + continueOnError: true + + - pwsh: | + Import-Module .\tools\ci.psm1 + Restore-PSOptions -PSOptionsPath '$(System.ArtifactsDirectory)\build\psoptions.json' + $options = (Get-PSOptions) + $rootPath = '$(System.ArtifactsDirectory)\bins' + $originalRootPath = Split-Path -path $options.Output + $path = Join-Path -path $rootPath -ChildPath (split-path -leaf -path $originalRootPath) + $pwshPath = Join-Path -path $path -ChildPath 'pwsh' + chmod a+x $pwshPath + $options.Output = $pwshPath + Set-PSOptions $options + Invoke-CITest -Purpose '${{ parameters.purpose }}' -TagSet '${{ parameters.tagSet }}' + displayName: Test + condition: succeeded() diff --git a/test/powershell/Modules/Microsoft.PowerShell.Management/Test-Connection.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Management/Test-Connection.Tests.ps1 index dbe91e86574..b8c9d14a1be 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Management/Test-Connection.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Management/Test-Connection.Tests.ps1 @@ -97,15 +97,8 @@ Describe "Test-Connection" -tags "CI", "RequireSudoOnUnix" { { Test-Connection "fakeHost" -Count 1 -ErrorAction Stop } | Should -Throw -ErrorId "TestConnectionException,Microsoft.PowerShell.Commands.TestConnectionCommand" # Error code = 11001 - Host not found. - $platform = Get-PlatformInfo - if ($platform.Platform -match "raspbian" -or ( $platform.Platform -match 'ubuntu' -and $platform.Version -eq '20.04')) { - $code = 11 - } elseif (!$IsWindows) { - $code = -131073 - } else { - $code = 11001 - } - $error[0].Exception.InnerException.ErrorCode | Should -Be $code + # Error code = -131073 - Invalid address + $error[0].Exception.InnerException.ErrorCode | Should -BeIn 11, -131073, 11001 } It "Force IPv4 with implicit PingOptions" { diff --git a/test/powershell/engine/Remoting/PSSession.Tests.ps1 b/test/powershell/engine/Remoting/PSSession.Tests.ps1 index 25c7ab9c582..cbf7313eed0 100644 --- a/test/powershell/engine/Remoting/PSSession.Tests.ps1 +++ b/test/powershell/engine/Remoting/PSSession.Tests.ps1 @@ -79,14 +79,8 @@ Describe "SkipCACheck and SkipCNCheck PSSession options are required for New-PSS It "" -TestCases $testCases { param ($scriptBlock, $expectedErrorCode) - $platformInfo = Get-PlatformInfo - if ( - ($platformInfo.Platform -match "alpine|raspbian") -or - ($platformInfo.Platform -eq "debian" -and ($platformInfo.Version -eq '10' -or $platformInfo.Version -eq '')) -or # debian 11 has empty Version ID - ($platformInfo.Platform -eq 'centos' -and $platformInfo.Version -eq '8') -or - ($platformInfo.Platform -eq 'ubuntu' -and $platformInfo.Version -eq '20.04') - ) { - Set-ItResult -Skipped -Because "MI library not available for Alpine, Raspberry Pi, Debian 10 and 11, and CentOS 8" + if ( -not (Get-WsManSupport)) { + Set-ItResult -Skipped -Because "MI library not available for this platform" return } diff --git a/test/powershell/engine/Remoting/RemoteSession.Basic.Tests.ps1 b/test/powershell/engine/Remoting/RemoteSession.Basic.Tests.ps1 index d56ed1999ac..84e25a276ec 100644 --- a/test/powershell/engine/Remoting/RemoteSession.Basic.Tests.ps1 +++ b/test/powershell/engine/Remoting/RemoteSession.Basic.Tests.ps1 @@ -10,15 +10,8 @@ function GetRandomString() Describe "New-PSSession basic test" -Tag @("CI") { It "New-PSSession should not crash powershell" { - $platformInfo = Get-PlatformInfo - if ( - ($platformInfo.Platform -match "alpine|raspbian") -or - ($platformInfo.Platform -eq "debian" -and ($platformInfo.Version -eq '10' -or $platformInfo.Version -eq '')) -or # debian 11 has empty Version ID - ($platformInfo.Platform -eq 'centos' -and $platformInfo.Version -eq '8') -or - ($platformInfo.Platform -eq 'ubuntu' -and $platformInfo.Version -eq '20.04') -or - ($IsMacOS) - ) { - Set-ItResult -Skipped -Because "MI library not available for Alpine, Raspberry Pi, Debian 10 and 11, CentOS 8, and not compatible with macOS" + if ( -not (Get-WsManSupport)) { + Set-ItResult -Skipped -Because "MI library not available for this platform" return } @@ -29,15 +22,8 @@ Describe "New-PSSession basic test" -Tag @("CI") { Describe "Basic Auth over HTTP not allowed on Unix" -Tag @("CI") { It "New-PSSession should throw when specifying Basic Auth over HTTP on Unix" -Skip:($IsWindows) { - $platformInfo = Get-PlatformInfo - if ( - ($platformInfo.Platform -match "alpine|raspbian") -or - ($platformInfo.Platform -eq "debian" -and ($platformInfo.Version -eq '10' -or $platformInfo.Version -eq '')) -or # debian 11 has empty Version ID - ($platformInfo.Platform -eq 'centos' -and $platformInfo.Version -eq '8') -or - ($platformInfo.Platform -eq 'ubuntu' -and $platformInfo.Version -eq '20.04') -or - ($IsMacOS) - ) { - Set-ItResult -Skipped -Because "MI library not available for Alpine, Raspberry Pi, Debian 10 and 11, CentOS 8, and not compatible with macOS" + if ( -not (Get-WsManSupport)) { + Set-ItResult -Skipped -Because "MI library not available for this platform" return } @@ -53,15 +39,8 @@ Describe "Basic Auth over HTTP not allowed on Unix" -Tag @("CI") { # Skip this test for macOS because the latest OS release is incompatible with our shipped libmi for WinRM/OMI. It "New-PSSession should NOT throw a ConnectFailed exception when specifying Basic Auth over HTTPS on Unix" -Skip:($IsWindows) { - $platformInfo = Get-PlatformInfo - if ( - ($platformInfo.Platform -match "alpine|raspbian") -or - ($platformInfo.Platform -eq "debian" -and ($platformInfo.Version -eq '10' -or $platformInfo.Version -eq '')) -or # debian 11 has empty Version ID - ($platformInfo.Platform -eq 'centos' -and $platformInfo.Version -eq '8') -or - ($platformInfo.Platform -eq 'ubuntu' -and $platformInfo.Version -eq '20.04') -or - ($IsMacOS) - ) { - Set-ItResult -Skipped -Because "MI library not available for Alpine, Raspberry Pi, Debian 10 and 11, CentOS 8, and not compatible with macOS" + if ( -not (Get-WsManSupport)) { + Set-ItResult -Skipped -Because "MI library not available for this platform" return } diff --git a/test/tools/Modules/HelpersCommon/HelpersCommon.psd1 b/test/tools/Modules/HelpersCommon/HelpersCommon.psd1 index 3d501983806..43d2ada88cc 100644 --- a/test/tools/Modules/HelpersCommon/HelpersCommon.psd1 +++ b/test/tools/Modules/HelpersCommon/HelpersCommon.psd1 @@ -35,6 +35,7 @@ FunctionsToExport = @( 'Wait-FileToBePresent' 'Wait-UntilTrue' 'Get-PlatformInfo' + 'Get-WSManSupport' ) CmdletsToExport= @() diff --git a/test/tools/Modules/HelpersCommon/HelpersCommon.psm1 b/test/tools/Modules/HelpersCommon/HelpersCommon.psm1 index c971e786765..dbd77186d2f 100644 --- a/test/tools/Modules/HelpersCommon/HelpersCommon.psm1 +++ b/test/tools/Modules/HelpersCommon/HelpersCommon.psm1 @@ -385,3 +385,19 @@ function Get-PlatformInfo { return "unknown" } } + +# return true if WsMan is supported on the current platform +function Get-WsManSupport { + $platformInfo = Get-PlatformInfo + if ( + ($platformInfo.Platform -match "alpine|raspbian") -or + ($platformInfo.Platform -eq "debian" -and $platformInfo.Version -ne '9') -or + ($platformInfo.Platform -eq 'centos' -and $platformInfo.Version -eq '8') -or + ($platformInfo.Platform -eq 'ubuntu' -and $platformInfo.Version -eq '20.04') -or + ($platformInfo.Platform -eq 'mariner') -or + ($IsMacOS) + ) { + return $false + } + return $true +} diff --git a/tools/ci.psm1 b/tools/ci.psm1 index f4ed3c78945..c06137a438d 100644 --- a/tools/ci.psm1 +++ b/tools/ci.psm1 @@ -16,7 +16,8 @@ if(Test-Path $dotNetPath) } # import build into the global scope so it can be used by packaging -Import-Module (Join-Path $repoRoot 'build.psm1') -Verbose -Scope Global +# argumentList $true says ignore tha we may not be able to build +Import-Module (Join-Path $repoRoot 'build.psm1') -Verbose -Scope Global -ArgumentList $true Import-Module (Join-Path $repoRoot 'tools\packaging') -Verbose -Scope Global # import the windows specific functcion only in Windows PowerShell or on Windows @@ -48,21 +49,26 @@ Function Set-BuildVariable [Parameter(Mandatory=$true)] [string] - $Value + $Value, + + [switch] + $IsOutput ) - if($env:TF_BUILD) - { + $IsOutputString = if ($IsOutput) { 'true' } else { 'false' } + $command = "vso[task.setvariable variable=$Name;isOutput=$IsOutputString]$Value" + + # always log command to make local debugging easier + Write-Verbose -Message "sending command: $command" -Verbose + + if ($env:TF_BUILD) { # In VSTS - Write-Host "##vso[task.setvariable variable=$Name;]$Value" + Write-Host "##$command" # 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 } + + # Setting in the current session for the same behavior as the CI and to make it show up in the same task + Set-Item env:/$name -Value $Value } # Emulates running all of CI but locally