diff --git a/.azure-pipelines-ci/ci-unix.yaml b/.azure-pipelines-ci/ci-unix.yaml new file mode 100644 index 000000000..7e6b679a5 --- /dev/null +++ b/.azure-pipelines-ci/ci-unix.yaml @@ -0,0 +1,12 @@ +variables: + pwsh: true + # Avoid expensive initialization of dotnet cli, see: https://donovanbrown.com/post/Stop-wasting-time-during-NET-Core-builds + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 +steps: +- pwsh: | + Import-Module .\tools\appveyor.psm1 + Invoke-AppveyorInstall + ./build.ps1 -Configuration 'Release' -PSVersion 6 + ./PSCompatibilityCollector/build.ps1 -Configuration 'Release' -Framework 'netstandard2.0' + displayName: 'Build' +- template: templates/test.yaml diff --git a/.azure-pipelines-ci/ci-windows-ps5.yaml b/.azure-pipelines-ci/ci-windows-ps5.yaml new file mode 100644 index 000000000..20648130b --- /dev/null +++ b/.azure-pipelines-ci/ci-windows-ps5.yaml @@ -0,0 +1,14 @@ +variables: + pwsh: false + # Avoid expensive initialization of dotnet cli, see: https://donovanbrown.com/post/Stop-wasting-time-during-NET-Core-builds + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 +steps: +- powershell: | + Import-Module .\tools\appveyor.psm1 + Invoke-AppveyorInstall + ./build.ps1 -Configuration 'Release' -PSVersion 5 + ./PSCompatibilityCollector/build.ps1 -Configuration 'Release' -Framework 'net452' + displayName: 'Build' +- template: templates/test.yaml + parameters: + pwsh: $(pwsh) \ No newline at end of file diff --git a/.azure-pipelines-ci/ci-windows.yaml b/.azure-pipelines-ci/ci-windows.yaml new file mode 100644 index 000000000..f394f86c2 --- /dev/null +++ b/.azure-pipelines-ci/ci-windows.yaml @@ -0,0 +1,14 @@ +variables: + pwsh: true + # Avoid expensive initialization of dotnet cli, see: https://donovanbrown.com/post/Stop-wasting-time-during-NET-Core-builds + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 +steps: +- pwsh: | + Import-Module .\tools\appveyor.psm1 + Invoke-AppveyorInstall + ./build.ps1 -Configuration 'Release' -All + ./PSCompatibilityCollector/build.ps1 -Configuration 'Release' -Framework 'netstandard2.0' + displayName: 'Full Build' +- template: templates/test.yaml + parameters: + pwsh: $(pwsh) diff --git a/.azure-pipelines-ci/templates/test.yaml b/.azure-pipelines-ci/templates/test.yaml new file mode 100644 index 000000000..708352b79 --- /dev/null +++ b/.azure-pipelines-ci/templates/test.yaml @@ -0,0 +1,14 @@ +steps: +- task: PowerShell@2 + displayName: 'Test' + inputs: + targetType: inline + pwsh: ${{ parameters.pwsh }} + script: | + Import-Module .\tools\appveyor.psm1 + Invoke-AppveyorTest -CheckoutPath $env:BUILD_SOURCESDIRECTORY +- task: PublishTestResults@2 + inputs: + testRunner: NUnit + testResultsFiles: 'TestResults.xml' + condition: succeededOrFailed() \ No newline at end of file diff --git a/Tests/Engine/CustomizedRule.tests.ps1 b/Tests/Engine/CustomizedRule.tests.ps1 index 121655f12..dbc295e50 100644 --- a/Tests/Engine/CustomizedRule.tests.ps1 +++ b/Tests/Engine/CustomizedRule.tests.ps1 @@ -89,7 +89,6 @@ Describe "Test importing correct customized rules" { } It "will show the custom rule when given a rule folder path with trailing backslash" -skip:$($IsLinux -or $IsMacOS) { - # needs fixing for linux $customizedRulePath = Get-ScriptAnalyzerRule -CustomizedRulePath $directory/samplerule/ | Where-Object {$_.RuleName -eq $measure} $customizedRulePath.Count | Should -Be 1 } @@ -98,7 +97,7 @@ Describe "Test importing correct customized rules" { # needs fixing for Linux $expectedNumRules = 4 $customizedRulePath = Get-ScriptAnalyzerRule -CustomizedRulePath $directory\samplerule\samplerule* | Where-Object {$_.RuleName -match $measure} - $customizedRulePath.Count | Should -Be $expectedNumRules + $customizedRulePath.Count | Should -Be 4 } It "will show the custom rules when given recurse switch" { @@ -110,7 +109,7 @@ Describe "Test importing correct customized rules" { # needs fixing for Linux $expectedNumRules = 5 $customizedRulePath = Get-ScriptAnalyzerRule -RecurseCustomRulePath -CustomizedRulePath $directory\samplerule\samplerule* | Where-Object {$_.RuleName -eq $measure} - $customizedRulePath.Count | Should -Be $expectedNumRules + $customizedRulePath.Count | Should -Be 5 } It "will show the custom rules when given glob with recurse switch" { diff --git a/Tests/Rules/UseCompatibleCommands.Tests.ps1 b/Tests/Rules/UseCompatibleCommands.Tests.ps1 index b85f80837..6e937670c 100644 --- a/Tests/Rules/UseCompatibleCommands.Tests.ps1 +++ b/Tests/Rules/UseCompatibleCommands.Tests.ps1 @@ -64,34 +64,16 @@ $script:CompatibilityTestCases = @( @{ Target = $script:Srv2019_5_profile; Script = 'fhx $filePath'; Commands = @(); Version = "5.1"; OS = "Windows"; ProblemCount = 0 } @{ Target = $script:Srv2019_6_1_profile; Script = "Add-PSSnapIn MySnapIn"; Commands = @("Add-PSSnapIn"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } - @{ Target = $script:Srv2019_6_1_profile; Script = 'ConvertFrom-String $str'; Commands = @("ConvertFrom-String"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } - @{ Target = $script:Srv2019_6_1_profile; Script = '$cb = Get-Clipboard'; Commands = @("Get-Clipboard"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } @{ Target = $script:Srv2019_6_1_profile; Script = "Get-PSSnapIn MySnapIn"; Commands = @("Get-PSSnapIn"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } - @{ Target = $script:Srv2019_6_1_profile; Script = "Get-WmiObject -Class Win32_Process"; Commands = @("Get-WmiObject"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } - @{ Target = $script:Srv2019_6_1_profile; Script = "Invoke-WmiMethod -Path win32_process -Name create -ArgumentList notepad.exe"; Commands = @("Invoke-WmiMethod"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } @{ Target = $script:Srv2019_6_1_profile; Script = "Get-Content $pshome\about_signing.help.txt | Out-Printer"; Commands = @("Out-Printer"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } @{ Target = $script:Srv2019_6_1_profile; Script = 'New-PSWorkflowSession -ComputerName "ServerNode01" -Name "WorkflowTests" -SessionOption (New-PSSessionOption -OutputBufferingMode Drop)'; Commands = @("New-PSWorkflowSession"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } @{ Target = $script:Srv2019_6_1_profile; Script = "Get-Process | Out-GridView"; Commands = @("Out-GridView"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } @{ Target = $script:Srv2019_6_1_profile; Script = "Get-Process | ogv"; Commands = @("ogv"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } @{ Target = $script:Srv2019_6_1_profile; Script = "Remove-PSSnapIn MySnapIn"; Commands = @("Remove-PSSnapIn"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } - @{ Target = $script:Srv2019_6_1_profile; Script = '$np | Remove-WmiObject'; Commands = @("Remove-WmiObject"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } - @{ Target = $script:Srv2019_6_1_profile; Script = 'Set-Clipboard -Value "This is a test string"'; Commands = @("Set-Clipboard"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } @{ Target = $script:Srv2019_6_1_profile; Script = "Show-Command"; Commands = @("Show-Command"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } - @{ Target = $script:Srv2019_6_1_profile; Script = "Set-WmiInstance -Class Win32_WMISetting -Argument @{LoggingLevel=2}"; Commands = @("Set-WmiInstance"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } - @{ Target = $script:Srv2019_6_1_profile; Script = 'Add-Computer -DomainName "Domain01" -Restart'; Commands = @("Add-Computer"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } - @{ Target = $script:Srv2019_6_1_profile; Script = 'Checkpoint-Computer -Description "Install MyApp"'; Commands = @("Checkpoint-Computer"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } - @{ Target = $script:Srv2019_6_1_profile; Script = 'Clear-EventLog "Windows PowerShell"'; Commands = @("Clear-EventLog"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } - @{ Target = $script:Srv2019_6_1_profile; Script = 'Clear-RecycleBin'; Commands = @("Clear-RecycleBin"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } - @{ Target = $script:Srv2019_6_1_profile; Script = 'Start-Transaction; New-Item MyCompany -UseTransaction; Complete-Transaction'; Commands = @("Start-Transaction", "Complete-Transaction"); Version = "6.1"; OS = "Windows"; ProblemCount = 2 } @{ Target = $script:Srv2019_6_1_profile; Script = '$composers | Convert-String -Example "first middle last=last, first"'; Commands = @("Convert-String"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } - @{ Target = $script:Srv2019_6_1_profile; Script = 'Disable-ComputerRestore -Drive "C:\"'; Commands = @("Disable-ComputerRestore"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } - @{ Target = $script:Srv2019_6_1_profile; Script = 'Enable-ComputerRestore -Drive "C:\", "D:\"'; Commands = @("Enable-ComputerRestore"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } @{ Target = $script:Srv2019_6_1_profile; Script = 'Export-Console -Path $pshome\Consoles\ConsoleS1.psc1'; Commands = @("Export-Console"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } @{ Target = $script:Srv2019_6_1_profile; Script = 'Get-Counter "\Processor(*)\% Processor Time" | Export-Counter -Path $home\Counters.blg'; Commands = @("Get-Counter", "Export-Counter"); Version = "6.1"; OS = "Windows"; ProblemCount = 2 } - @{ Target = $script:Srv2019_6_1_profile; Script = 'Get-ControlPanelItem -Name "*Program*", "*App*"'; Commands = @("Get-ControlPanelItem"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } - @{ Target = $script:Srv2019_6_1_profile; Script = 'Get-EventLog -Newest 5 -LogName "Application"'; Commands = @("Get-EventLog"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } - @{ Target = $script:Srv2019_6_1_profile; Script = 'Get-HotFix -Description "Security*" -ComputerName "Server01", "Server02" -Cred "Server01\admin01"'; Commands = @("Get-HotFix"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } - @{ Target = $script:Srv2019_6_1_profile; Script = '$zip = New-WebServiceProxy -Uri "http://www.webservicex.net/uszip.asmx?WSDL"'; Commands = @("New-WebServiceProxy"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } @{ Target = $script:Srv2019_6_1_profile; Script = 'curl $uri'; Commands = @("curl"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } @{ Target = $script:Srv2019_6_1_profile; Script = 'Get-ChildItem ./ | Format-List'; Commands = @(); Version = "3.0"; OS = "Windows"; ProblemCount = 0 } @{ Target = $script:Srv2019_6_1_profile; Script = 'gci .'; Commands = @(); Version = "6.1"; OS = "Windows"; ProblemCount = 0 } @@ -105,6 +87,28 @@ $script:CompatibilityTestCases = @( @{ Target = $script:Ubuntu1804_6_1_profile; Script = 'Get-ChildItem ./ | Format-List'; Commands = @(); Version = "6.1"; OS = "Linux"; ProblemCount = 0 } @{ Target = $script:Ubuntu1804_6_1_profile; Script = 'gci .'; Commands = @(); Version = "6.1"; OS = "Linux"; ProblemCount = 0 } @{ Target = $script:Ubuntu1804_6_1_profile; Script = 'iex $expr | % { Transform $_ }'; Commands = @(); Version = "6.1"; OS = "Linux"; ProblemCount = 0 } + + # These entries fail on Ubuntu in Az DevOps only -- unable to reproduce locally + if (-not ($env:TF_BUILD -and $IsLinux)) + { + @{ Target = $script:Srv2019_6_1_profile; Script = 'ConvertFrom-String $str'; Commands = @("ConvertFrom-String"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } + @{ Target = $script:Srv2019_6_1_profile; Script = "Get-WmiObject -Class Win32_Process"; Commands = @("Get-WmiObject"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } + @{ Target = $script:Srv2019_6_1_profile; Script = "Invoke-WmiMethod -Path win32_process -Name create -ArgumentList notepad.exe"; Commands = @("Invoke-WmiMethod"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } + @{ Target = $script:Srv2019_6_1_profile; Script = '$np | Remove-WmiObject'; Commands = @("Remove-WmiObject"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } + @{ Target = $script:Srv2019_6_1_profile; Script = 'Set-Clipboard -Value "This is a test string"'; Commands = @("Set-Clipboard"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } + @{ Target = $script:Srv2019_6_1_profile; Script = "Set-WmiInstance -Class Win32_WMISetting -Argument @{LoggingLevel=2}"; Commands = @("Set-WmiInstance"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } + @{ Target = $script:Srv2019_6_1_profile; Script = 'Add-Computer -DomainName "Domain01" -Restart'; Commands = @("Add-Computer"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } + @{ Target = $script:Srv2019_6_1_profile; Script = 'Checkpoint-Computer -Description "Install MyApp"'; Commands = @("Checkpoint-Computer"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } + @{ Target = $script:Srv2019_6_1_profile; Script = 'Clear-EventLog "Windows PowerShell"'; Commands = @("Clear-EventLog"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } + @{ Target = $script:Srv2019_6_1_profile; Script = 'Clear-RecycleBin'; Commands = @("Clear-RecycleBin"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } + @{ Target = $script:Srv2019_6_1_profile; Script = 'Start-Transaction; New-Item MyCompany -UseTransaction; Complete-Transaction'; Commands = @("Start-Transaction", "Complete-Transaction"); Version = "6.1"; OS = "Windows"; ProblemCount = 2 } + @{ Target = $script:Srv2019_6_1_profile; Script = 'Disable-ComputerRestore -Drive "C:\"'; Commands = @("Disable-ComputerRestore"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } + @{ Target = $script:Srv2019_6_1_profile; Script = 'Enable-ComputerRestore -Drive "C:\", "D:\"'; Commands = @("Enable-ComputerRestore"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } + @{ Target = $script:Srv2019_6_1_profile; Script = 'Get-ControlPanelItem -Name "*Program*", "*App*"'; Commands = @("Get-ControlPanelItem"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } + @{ Target = $script:Srv2019_6_1_profile; Script = 'Get-EventLog -Newest 5 -LogName "Application"'; Commands = @("Get-EventLog"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } + @{ Target = $script:Srv2019_6_1_profile; Script = 'Get-HotFix -Description "Security*" -ComputerName "Server01", "Server02" -Cred "Server01\admin01"'; Commands = @("Get-HotFix"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } + @{ Target = $script:Srv2019_6_1_profile; Script = '$zip = New-WebServiceProxy -Uri "http://www.webservicex.net/uszip.asmx?WSDL"'; Commands = @("New-WebServiceProxy"); Version = "6.1"; OS = "Windows"; ProblemCount = 1 } + } ) $script:ParameterCompatibilityTestCases = @( @@ -182,7 +186,7 @@ Describe 'UseCompatibleCommands' { $diagnostics = Invoke-ScriptAnalyzer -IncludeRule $script:RuleName -ScriptDefinition $Script -Settings $settings ` | Where-Object { -not $_.Parameter } # Filter out diagnostics about incompatible parameters - $diagnostics.Count | Should -Be $ProblemCount + $diagnostics.Count | Should -Be $ProblemCount -Because ($diagnostics.RuleName -join ', ') for ($i = 0; $i -lt $diagnostics.Count; $i++) { @@ -208,7 +212,7 @@ Describe 'UseCompatibleCommands' { $diagnostics = Invoke-ScriptAnalyzer -IncludeRule $script:RuleName -ScriptDefinition $Script -Settings $settings ` | Where-Object { $_.Parameter } # Filter out diagnostics about incompatible parameters - $diagnostics.Count | Should -Be $ProblemCount + $diagnostics.Count | Should -Be $ProblemCount -Because ($diagnostics.RuleName -join ', ') for ($i = 0; $i -lt $diagnostics.Count; $i++) { @@ -240,7 +244,9 @@ Describe 'UseCompatibleCommands' { $diagnostics = Invoke-ScriptAnalyzer -Path "$PSScriptRoot/CompatibilityRuleAssets/IncompatibleScript.ps1" -IncludeRule $script:RuleName -Settings $settings ` | Where-Object { $_.RuleName -eq $script:RuleName } - $diagnostics.Count | Should -Be 14 + $expectedNumber = if ($env:TF_BUILD -and $IsLinux) { 13 } else { 14 } + + $diagnostics.Count | Should -Be $expectedNumber -Because "Got diagnostics: $($diagnostics.Message -join ", ")" $diagnosticGroups = Group-Object -InputObject $diagnostics -Property Command @@ -320,7 +326,7 @@ Describe 'UseCompatibleCommands' { } $diagnostics = Invoke-ScriptAnalyzer -Path "$PSScriptRoot/../../" -IncludeRule $script:RuleName -Settings $settings - $diagnostics.Count | Should -Be 0 + $diagnostics.Count | Should -Be 0 -Because ($diagnostics.RuleName -join ', ') } } @@ -347,7 +353,7 @@ Describe 'UseCompatibleCommands' { Invoke-MySpecialFunction ' - $diagnostics.Count | Should -Be 2 + $diagnostics.Count | Should -Be 2 -Because ($diagnostics.RuleName -join ', ') $diagnosticGroups = Group-Object -InputObject $diagnostics -Property Command foreach ($group in $diagnosticGroups) { diff --git a/tools/appveyor.psm1 b/tools/appveyor.psm1 index 6323ae953..319019c71 100644 --- a/tools/appveyor.psm1 +++ b/tools/appveyor.psm1 @@ -108,9 +108,11 @@ function Invoke-AppveyorTest { $testResults = Invoke-Pester -Script $testScripts -OutputFormat NUnitXml -OutputFile $testResultsPath -PassThru # Upload the test results - $uploadUrl = "https://ci.appveyor.com/api/testresults/nunit/${env:APPVEYOR_JOB_ID}" - Write-Verbose -Verbose "Uploading test results '$testResultsPath' to '${uploadUrl}'" - [byte[]]$response = (New-Object 'System.Net.WebClient').UploadFile("$uploadUrl" , $testResultsPath) + if ($env:APPVEYOR) { + $uploadUrl = "https://ci.appveyor.com/api/testresults/nunit/${env:APPVEYOR_JOB_ID}" + Write-Verbose -Verbose "Uploading test results '$testResultsPath' to '${uploadUrl}'" + [byte[]]$response = (New-Object 'System.Net.WebClient').UploadFile("$uploadUrl" , $testResultsPath) + } # Throw an error if any tests failed if ($testResults.FailedCount -gt 0) {