From cab2708b9e5f48a54e26edb7be4bd659afacddcc Mon Sep 17 00:00:00 2001 From: James Truher Date: Wed, 3 Oct 2018 16:48:02 -0700 Subject: [PATCH 01/16] consolidate build of script analyzer into module Require any 2.1 sdk for building, this way we can build with the same sdk as PowerShell core --- build.psm1 | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++++ global.json | 2 +- 2 files changed, 258 insertions(+), 1 deletion(-) create mode 100644 build.psm1 diff --git a/build.psm1 b/build.psm1 new file mode 100644 index 000000000..ed84a5e80 --- /dev/null +++ b/build.psm1 @@ -0,0 +1,257 @@ +# BUILDCORECLR + +$projectRoot = $PSScriptRoot +$destinationDir = Join-Path -Path $projectRoot -ChildPath (Join-Path -Path "out" -ChildPath "PSScriptAnalyzer") +function Publish-File +{ + param ([string[]]$itemsToCopy, [string]$destination) + if (-not (Test-Path $destination)) + { + $null = New-Item -ItemType Directory $destination -Force + } + foreach ($file in $itemsToCopy) + { + Copy-Item -Path $file -Destination (Join-Path $destination (Split-Path $file -Leaf)) -Force + } +} + +function Uninstall-ScriptAnalyzer +{ + +} + +# attempt to get the users module directory +function Get-UserModulePath +{ + if ( $IsCoreCLR -and ! $IsWindows ) + { + $platformType = "System.Management.Automation.Platform" -as [Type] + if ( $platformType ) { + ${platformType}::SelectProductNameForDirectory("USER_MODULES") + } + else { + throw "Could not determine users module path" + } + } + else { + "${HOME}/Documents/WindowsPowerShell/Modules" + } + +} + +# install script analyzer, by default into the users module path +function Install-ScriptAnalyzer +{ + [CmdletBinding(SupportsShouldProcess)] + param ( $ModulePath = $(Join-Path -Path (Get-UserModulePath) -ChildPath PSScriptAnalyzer) ) + + #Write-Progress "Installing to $modulePath" + Copy-Item -Recurse -Path "$destinationDir" -Destination "$ModulePath\." -Force +} + +# if script analyzer is installed, remove it +function Uninstall-ScriptAnalyzer +{ + [CmdletBinding(SupportsShouldProcess)] + param ( $ModulePath = $(Join-Path -Path (Get-UserModulePath) -ChildPath PSScriptAnalyzer) ) + $ + if (Test-Path $ModulePath -and (Get-Item $ModulePath).PSIsContainer ) + { + Remove-Item -Force -Recurse $ModulePath + } +} + +# Build documentation using platyPS +function Build-Doc +{ + $docsPath = Join-Path $projectRoot docs + $markdownDocsPath = Join-Path $docsPath markdown + $outputDocsPath = Join-Path $destinationDir en-US + $requiredVersionOfplatyPS = 0.9 + $modInfo = new-object Microsoft.PowerShell.Commands.ModuleSpecification -ArgumentList @{ ModuleName = "platyps"; ModuleVersion = $requiredVersionOfplatyPS} + if ( $null -eq (Get-Module -ListAvailable -FullyQualifiedName $modInfo)) + { + throw "Cannot find required minimum version $requiredVersionOfplatyPS of platyPS. Install via 'Install-Module platyPS'" + } + if (-not (Test-Path $markdownDocsPath)) + { + throw "Cannot find markdown documentation folder." + } + Import-Module platyPS + if ( ! (Test-Path $outputDocsPath)) { + $null = New-Item -Type Directory -Path $outputDocsPath -Force + } + $null = New-ExternalHelp -Path $markdownDocsPath -OutputPath $outputDocsPath -Force +} + +# Clean up the build location +function Remove-Build +{ + [CmdletBinding(SupportsShouldProcess=$true)] + param () + $ + if ( $PSCmdlet.ShouldProcess("${destinationDir}")) { + if ( test-path -dir ${destinatationDir} ) { + Remove-Item -Force -Recurse ${destinationDir} + } + } +} + +# build script analyzer (and optionally build everything with -All) +function Build-ScriptAnalyzer +{ + [CmdletBinding(DefaultParameterSetName="BuildOne")] + param ( + [Parameter(ParameterSetName="BuildAll")] + [switch]$All, + + [Parameter(ParameterSetName="BuildOne")] + [ValidateSet("full", "core")] + [string]$Framework = "core", + + [Parameter(ParameterSetName="BuildOne")] + [ValidateSet("PSv3","PSv4","PSv5")] + [string]$AnalyzerVersion = "PSv5", + + [Parameter(ParameterSetName="BuildOne")] + [ValidateSet("Debug", "Release")] + [string]$Configuration = "Debug", + + [Parameter(ParameterSetName="BuildDoc")] + [switch]$Documentation + ) + + if ( $All ) + { + # Build all the versions of the analyzer + Build-ScriptAnalyzer -Framework full -Configuration $Configuration -AnalyzerVersion "PSv3" + Build-ScriptAnalyzer -Framework full -Configuration $Configuration -AnalyzerVersion "PSv4" + Build-ScriptAnalyzer -Framework full -Configuration $Configuration -AnalyzerVersion "PSv5" + Build-ScriptAnalyzer -Framework core -Configuration $Configuration -AnalyzerVersion "PSv5" + Build-ScriptAnalyzer -Documentation + return + } + + if ( $Documentation ) + { + Build-Doc + return + } + + Push-Location -Path $projectRoot + + if ( $framework -eq "core" ) { + $frameworkName = "netstandard2.0" + } + else { + $frameworkName = "net451" + } + + # build the appropriate assembly + if ($AnalyzerVersion -match "PSv3|PSv4" -and $Framework -eq "core") + { + throw ("ScriptAnalyzer Version '{0}' is not applicable to {1} framework" -f $AnalyzerVersion,$Framework) + } + + #Write-Progress "Building ScriptAnalyzer" + if (-not (Test-Path "$projectRoot/global.json")) + { + throw "Not in solution root" + } + + $itemsToCopyCommon = @( + "$projectRoot\Engine\PSScriptAnalyzer.psd1", "$projectRoot\Engine\PSScriptAnalyzer.psm1", + "$projectRoot\Engine\ScriptAnalyzer.format.ps1xml", "$projectRoot\Engine\ScriptAnalyzer.types.ps1xml" + ) + + $settingsFiles = Get-Childitem "$projectRoot\Engine\Settings" | ForEach-Object -MemberName FullName + + $destinationDir = "$projectRoot\out\PSScriptAnalyzer" + # this is normalizing case as well as selecting the proper location + if ( $Framework -eq "core" ) { + $destinationDirBinaries = "$destinationDir\coreclr" + } + elseif ($AnalyzerVersion -eq 'PSv3') { + $destinationDirBinaries = "$destinationDir\PSv3" + } + elseif ($AnalyzerVersion -eq 'PSv4') { + $destinationDirBinaries = "$destinationDir\PSv4" + } + else { + $destinationDirBinaries = $destinationDir + } + + # build the analyzer + #Write-Progress "Building for framework $Framework, configuration $Configuration" + # The Rules project has a dependency on the Engine therefore just building the Rules project is enough + try { + Push-Location $projectRoot/Rules + Write-Progress "Building ScriptAnalyzer '$framework' version '${AnalyzerVersion}' configuration '${Configuration}'" + $buildOutput = dotnet build Rules.csproj --framework $frameworkName --configuration "${AnalyzerVersion}${Configuration}" + if ( $LASTEXITCODE -ne 0 ) { throw "$buildOutput" } + } + catch { + Write-Error "Failure to build $framework ${AnalyzerVersion}${Configuration}" + return + } + finally { + Pop-Location + } + + #Write-Progress "Copying files to $destinationDir" + Publish-File $itemsToCopyCommon $destinationDir + + $itemsToCopyBinaries = @( + "$projectRoot\Engine\bin\${AnalyzerVersion}${Configuration}\${frameworkName}\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll", + "$projectRoot\Rules\bin\${AnalyzerVersion}${Configuration}\${frameworkName}\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll" + ) + Publish-File $itemsToCopyBinaries $destinationDirBinaries + + Publish-File $settingsFiles (Join-Path -Path $destinationDir -ChildPath Settings) + + # copy newtonsoft dll if net451 framework + if ($Framework -eq "full") { + Copy-Item -path "$projectRoot\Rules\bin\${AnalyzerVersion}${Configuration}\${frameworkName}\Newtonsoft.Json.dll" -Destination $destinationDirBinaries + } + + Pop-Location +} + +# Run our tests +function Test-ScriptAnalyzer +{ + [CmdletBinding()] + $testModulePath = Join-Path "${projectRoot}" -ChildPath out + $testResultsFile = Join-Path ${projectRoot} -childPath TestResults.xml + $testScripts = "${projectRoot}\Tests\Engine,${projectRoot}\Tests\Rules,${projectRoot}\Tests\Documentation" + try { + $savedModulePath = $env:PSModulePath + $env:PSModulePath = "${testModulePath}{0}${env:PSModulePath}" -f [System.IO.Path]::PathSeparator + $scriptBlock = [scriptblock]::Create("Invoke-Pester -Path $testScripts -OutputFormat NUnitXml -OutputFile $testResultsFile -Show Describe") + Write-Verbose -verbose "$scriptBlock" + $powershell = (Get-Process -id $PID).MainModule.FileName + & ${powershell} -Command $scriptBlock + } + finally { + $env:PSModulePath = $savedModulePath + } +} + +# a simple function to make it easier to retrieve the test results +function Get-TestResults +{ + param ( $logfile = (Join-Path -Path ${projectRoot} -ChildPath TestResults.xml) ) + $logPath = (Resolve-Path $logfile).Path + $results = [xml](Get-Content $logPath) + $results.SelectNodes(".//test-case") +} + +# a simple function to make it easier to retrieve the failures +# it's not a filter of the results of Get-TestResults because this is faster +function Get-TestFailures +{ + param ( $logfile = (Join-Path -Path ${projectRoot} -ChildPath TestResults.xml) ) + $logPath = (Resolve-Path $logfile).Path + $results = [xml](Get-Content $logPath) + $results.SelectNodes(".//test-case[@result='Failure']") +} diff --git a/global.json b/global.json index 7298a99c2..dd12f3441 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "2.1.101" + "version": "2.1.400" } } From 8977733c6d2c02406994584e7b3719d04574f441 Mon Sep 17 00:00:00 2001 From: James Truher Date: Fri, 5 Oct 2018 11:39:45 -0700 Subject: [PATCH 02/16] Have git ignore vim swap files and the test results file --- .gitignore | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 329ec9bd5..cbdb1ba3d 100644 --- a/.gitignore +++ b/.gitignore @@ -205,4 +205,10 @@ FakesAssemblies/ *.opt ##Our project binplace location -PSScriptAnalyzer/ \ No newline at end of file +PSScriptAnalyzer/ + +# Vim swap files +*.swp + +# Test result file +TestResults.xml From 920a8ab0c8fa77260f63b11917066b9a50f0119a Mon Sep 17 00:00:00 2001 From: James Truher Date: Fri, 5 Oct 2018 11:40:45 -0700 Subject: [PATCH 03/16] Only special case linux for the customized rule tests --- Tests/Engine/CustomizedRule.tests.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Engine/CustomizedRule.tests.ps1 b/Tests/Engine/CustomizedRule.tests.ps1 index 753a82d05..543abc768 100644 --- a/Tests/Engine/CustomizedRule.tests.ps1 +++ b/Tests/Engine/CustomizedRule.tests.ps1 @@ -97,7 +97,7 @@ Describe "Test importing correct customized rules" { It "will show the custom rules when given a glob" { # needs fixing for Linux $expectedNumRules = 4 - if ($IsLinux -or $IsMacOS) + if ($IsLinux) { $expectedNumRules = 3 } @@ -113,7 +113,7 @@ Describe "Test importing correct customized rules" { It "will show the custom rules when given glob with recurse switch" { # needs fixing for Linux $expectedNumRules = 5 - if ($IsLinux -or $IsMacOS) + if ($IsLinux) { $expectedNumRules = 4 } From 7a3f1d253cae4ae406ade99a6699a05bf255cb7b Mon Sep 17 00:00:00 2001 From: James Truher Date: Fri, 5 Oct 2018 14:31:45 -0700 Subject: [PATCH 04/16] Update to build scripts. To build for core, simply type ./build, to build all flavors and documentation type ./build -all. You can now run tests as well via ./build -Test. --- build.ps1 | 213 +++++++++----------------------------- build.psm1 | 264 +++++++++++++++++++++++++---------------------- buildCoreClr.ps1 | 97 ----------------- 3 files changed, 192 insertions(+), 382 deletions(-) delete mode 100644 buildCoreClr.ps1 diff --git a/build.ps1 b/build.ps1 index 89dcbcf11..01ee2c890 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,183 +1,68 @@ -# This function might be a partially out of date and only the -BuildDoc switch is guaranteed to work since it is used and needed for the build process. -[CmdletBinding()] +[CmdletBinding(DefaultParameterSetName="BuildOne")] param( + [Parameter(ParameterSetName="BuildAll")] + [switch]$All, - [Parameter(ParameterSetName='Build')] - [ValidateSet('PSV3 Debug','PSV3 Release','Debug','Release')] - [string] $Configuration = 'Debug', + [Parameter(ParameterSetName="BuildOne")] + [ValidateSet("full", "core")] + [string]$Framework = "core", - [Parameter(ParameterSetName='Build')] - [switch] $BuildDocs = $false, + [Parameter(ParameterSetName="BuildOne")] + [ValidateSet("PSv3","PSv4","PSv5")] + [string]$AnalyzerVersion = "PSv5", - [Parameter(ParameterSetName='Build')] - [switch] $CleanOutput = $false, + [Parameter(ParameterSetName="BuildOne")] + [ValidateSet("Debug", "Release")] + [string]$Configuration = "Debug", - [Parameter(ParameterSetName='Build')] - [switch] $Install = $false, + [Parameter(ParameterSetName="BuildDoc")] + [switch]$Documentation, - [Parameter(ParameterSetName='Build')] - [switch] $Uninstall = $false, + [Parameter(ParameterSetName='BuildAll')] + [Parameter(ParameterSetName='BuildOne')] + [switch]$Clobber, - [Parameter(ParameterSetName='Test')] - [switch] $Test = $false, + [Parameter(Mandatory=$true,ParameterSetName='Clean')] + [switch] $Clean, - [Parameter(ParameterSetName='Test')] - [switch] $Engine = $false, + [Parameter(Mandatory=$true,ParameterSetName='Test')] + [switch] $Test, [Parameter(ParameterSetName='Test')] - [switch] $Rules = $false, - - [Parameter(ParameterSetName='Test')] - [switch] $RunInDifferentProcess = $false + [switch] $InProcess ) -# Some cmdlets like copy-item do not respond to the $verbosepreference variable -# hence we set it explicitly -$verbosity = $false -if ($VerbosePreference.Equals([System.Management.Automation.ActionPreference]'Continue')) -{ - $verbosity = $true -} - -Function CreateIfNotExists([string] $folderPath) -{ - if (-not (Test-Path $folderPath)) - { - New-Item -Path $folderPath -ItemType Directory -Verbose:$verbosity - } -} - -$projectRoot = Resolve-path (Split-Path $MyInvocation.InvocationName) -$solutionPath = Join-Path $projectRoot 'PSScriptAnalyzer.sln' -$outPath = Join-Path $projectRoot 'out' -$destinationPath = Join-Path $outPath PSScriptAnalyzer - -if (-not (Test-Path $solutionPath)) -{ - $errMsg = "{0} not the right directory" -f $solutionPath - throw $errMsg -} - -if ($CleanOutput) -{ - Remove-Item -Recurse $outPath\* -Force -Verbose:$verbosity -} - -if ($BuildDocs) -{ - $docsPath = Join-Path $projectRoot 'docs' - $markdownDocsPath = Join-Path $docsPath 'markdown' - $outputDocsPath = Join-Path $destinationPath en-US - - CreateIfNotExists($outputDocsPath) - - # Build documentation using platyPS - $requiredVersionOfplatyPS = 0.9 - if ($null -eq (Get-Module platyPS -ListAvailable -Verbose:$verbosity | Where-Object { $_.Version -ge $requiredVersionOfplatyPS })) - { - "Cannot find required minimum version $requiredVersionOfplatyPS of platyPS. Please install it from https://www.powershellgallery.com/packages/platyPS/ using e.g. the following command: Install-Module platyPS" - } - if ($null -eq (Get-Module platyPS -Verbose:$verbosity)) - { - Import-Module platyPS -Verbose:$verbosity - } - if (-not (Test-Path $markdownDocsPath -Verbose:$verbosity)) - { - throw "Cannot find markdown documentation folder." - } - New-ExternalHelp -Path $markdownDocsPath -OutputPath $outputDocsPath -Force -Verbose:$verbosity -} - -# Appveyor errors out due to $profile being null. Hence... -$moduleRootPath = "$HOME/Documents/WindowsPowerShell/Modules" -if ($null -ne $profile) -{ - $moduleRootPath = Join-Path (Split-Path $profile) 'Modules' -} -$modulePSSAPath = Join-Path $moduleRootPath 'PSScriptAnalyzer' -if ($Install) -{ - if (-not (Test-Path $moduleRootPath)) - { - New-Item -Path $moduleRootPath -ItemType Directory -Force -Verbose:$verbosity - } - if (-not (Test-Path -Path $destinationPath)) - { - throw "Please build the module first." - } - Copy-Item -Path $destinationPath -Destination $modulePSSAPath -Recurse -Verbose:$verbosity -} - -if ($Test) -{ - Import-Module -Name Pester -MinimumVersion 4.3.1 -ErrorAction Stop - Function GetTestRunnerScriptContent($testPath) - { - $x = @" - cd $testPath - Invoke-Pester -"@ - return $x - } - - Function CreateTestRunnerScript($testPath) - { - $tmptmpFilePath = [System.IO.Path]::GetTempFileName() - $tmpFilePath = $tmptmpFilePath + '.ps1' - Move-Item $tmptmpFilePath $tmpFilePath -Verbose:$verbosity - $content = GetTestRunnerScriptContent $testPath - Set-Content -Path $tmpFilePath -Value $content -Verbose:$verbosity - return $tmpFilePath - } - - Function GetTestPath($TestType) - { - if ($TestType -eq "engine") - { - $testPath = Join-Path $projectRoot "Tests/Engine" +END { + Import-Module -Force (Join-Path $PSScriptRoot build.psm1) + if ( $Clean -or $Clobber ) { + Remove-Build + if ( $PSCmdlet.ParameterSetName -eq "Clean" ) { + return } - else - { - $testPath = Join-Path $projectRoot "Tests/Rules" - } - return $testPath } - Function RunTest($TestType, [Boolean] $DifferentProcess) - { - $testPath = GetTestPath($TestType) - if ($DifferentProcess) - { - $testScriptFilePath = CreateTestRunnerScript $testPath - Start-Process powershell -ArgumentList "-NoExit","-File $testScriptFilePath" -Verb runas - # clean up the test file + $setName = $PSCmdlet.ParameterSetName + switch ( $setName ) { + "BuildAll" { + Build-ScriptAnalyzer -All } - else - { - try - { - Push-Location . - ([scriptblock]::Create((GetTestRunnerScriptContent $testPath))).Invoke() - } - finally - { - Pop-Location - + "BuildDoc" { + Build-ScriptAnalyzer -Documentation + } + "BuildOne" { + $buildArgs = @{ + Framework = $Framework + AnalyzerVersion = $AnalyzerVersion + Configuration = $Configuration } + Build-ScriptAnalyzer @buildArgs + } + "Test" { + Test-ScriptAnalyzer -InProcess:$InProcess + return + } + default { + throw "Unexpected parameter set '$setName'" } } - - if ($Engine -or (-not ($Engine -or $Rules))) - { - RunTest 'engine' $RunInDifferentProcess - } - if ($Rules -or (-not ($Engine -or $Rules))) - { - RunTest 'rules' $RunInDifferentProcess - } -} - -if ($Uninstall) -{ - Remove-Item -Path $modulePSSAPath -Force -Verbose:$verbosity -Recurse -} +} \ No newline at end of file diff --git a/build.psm1 b/build.psm1 index ed84a5e80..e28d46fa2 100644 --- a/build.psm1 +++ b/build.psm1 @@ -1,7 +1,7 @@ -# BUILDCORECLR - +# Build module for PowerShell ScriptAnalyzer $projectRoot = $PSScriptRoot $destinationDir = Join-Path -Path $projectRoot -ChildPath (Join-Path -Path "out" -ChildPath "PSScriptAnalyzer") + function Publish-File { param ([string[]]$itemsToCopy, [string]$destination) @@ -15,11 +15,6 @@ function Publish-File } } -function Uninstall-ScriptAnalyzer -{ - -} - # attempt to get the users module directory function Get-UserModulePath { @@ -36,7 +31,18 @@ function Get-UserModulePath else { "${HOME}/Documents/WindowsPowerShell/Modules" } +} + +function Uninstall-ScriptAnalyzer +{ + [CmdletBinding(SupportsShouldProcess)] + param ( $ModulePath = $(Join-Path -Path (Get-UserModulePath) -ChildPath PSScriptAnalyzer) ) + END { + if ( $PSCmdlet.ShouldProcess("$modulePath") ) { + Remove-Item -Recurse -Path "$ModulePath" -Force + } + } } # install script analyzer, by default into the users module path @@ -44,9 +50,11 @@ function Install-ScriptAnalyzer { [CmdletBinding(SupportsShouldProcess)] param ( $ModulePath = $(Join-Path -Path (Get-UserModulePath) -ChildPath PSScriptAnalyzer) ) - - #Write-Progress "Installing to $modulePath" - Copy-Item -Recurse -Path "$destinationDir" -Destination "$ModulePath\." -Force + END { + if ( $PSCmdlet.ShouldProcess("$modulePath") ) { + Copy-Item -Recurse -Path "$destinationDir" -Destination "$ModulePath\." -Force + } + } } # if script analyzer is installed, remove it @@ -54,15 +62,31 @@ function Uninstall-ScriptAnalyzer { [CmdletBinding(SupportsShouldProcess)] param ( $ModulePath = $(Join-Path -Path (Get-UserModulePath) -ChildPath PSScriptAnalyzer) ) - $ - if (Test-Path $ModulePath -and (Get-Item $ModulePath).PSIsContainer ) - { - Remove-Item -Force -Recurse $ModulePath + END { + if (Test-Path $ModulePath -and (Get-Item $ModulePath).PSIsContainer ) + { + Remove-Item -Force -Recurse $ModulePath + } + } +} + +# Clean up the build location +function Remove-Build +{ + [CmdletBinding(SupportsShouldProcess=$true)] + param () + END { + if ( $PSCmdlet.ShouldProcess("${destinationDir}")) { + if ( Test-Path ${destinationDir} ) { + Remove-Item -Force -Recurse ${destinationDir} + } + } } } + # Build documentation using platyPS -function Build-Doc +function Build-Documentation { $docsPath = Join-Path $projectRoot docs $markdownDocsPath = Join-Path $docsPath markdown @@ -84,19 +108,6 @@ function Build-Doc $null = New-ExternalHelp -Path $markdownDocsPath -OutputPath $outputDocsPath -Force } -# Clean up the build location -function Remove-Build -{ - [CmdletBinding(SupportsShouldProcess=$true)] - param () - $ - if ( $PSCmdlet.ShouldProcess("${destinationDir}")) { - if ( test-path -dir ${destinatationDir} ) { - Remove-Item -Force -Recurse ${destinationDir} - } - } -} - # build script analyzer (and optionally build everything with -All) function Build-ScriptAnalyzer { @@ -121,119 +132,130 @@ function Build-ScriptAnalyzer [switch]$Documentation ) - if ( $All ) - { - # Build all the versions of the analyzer - Build-ScriptAnalyzer -Framework full -Configuration $Configuration -AnalyzerVersion "PSv3" - Build-ScriptAnalyzer -Framework full -Configuration $Configuration -AnalyzerVersion "PSv4" - Build-ScriptAnalyzer -Framework full -Configuration $Configuration -AnalyzerVersion "PSv5" - Build-ScriptAnalyzer -Framework core -Configuration $Configuration -AnalyzerVersion "PSv5" - Build-ScriptAnalyzer -Documentation - return - } + END { + if ( $All ) + { + # Build all the versions of the analyzer + Build-ScriptAnalyzer -Framework full -Configuration $Configuration -AnalyzerVersion "PSv3" + Build-ScriptAnalyzer -Framework full -Configuration $Configuration -AnalyzerVersion "PSv4" + Build-ScriptAnalyzer -Framework full -Configuration $Configuration -AnalyzerVersion "PSv5" + Build-ScriptAnalyzer -Framework core -Configuration $Configuration -AnalyzerVersion "PSv5" + Build-ScriptAnalyzer -Documentation + return + } - if ( $Documentation ) - { - Build-Doc - return - } + if ( $Documentation ) + { + Build-Documentation + return + } - Push-Location -Path $projectRoot + Push-Location -Path $projectRoot - if ( $framework -eq "core" ) { - $frameworkName = "netstandard2.0" - } - else { - $frameworkName = "net451" - } + if ( $framework -eq "core" ) { + $frameworkName = "netstandard2.0" + } + else { + $frameworkName = "net451" + } - # build the appropriate assembly - if ($AnalyzerVersion -match "PSv3|PSv4" -and $Framework -eq "core") - { - throw ("ScriptAnalyzer Version '{0}' is not applicable to {1} framework" -f $AnalyzerVersion,$Framework) - } + # build the appropriate assembly + if ($AnalyzerVersion -match "PSv3|PSv4" -and $Framework -eq "core") + { + throw ("ScriptAnalyzer Version '{0}' is not applicable to {1} framework" -f $AnalyzerVersion,$Framework) + } - #Write-Progress "Building ScriptAnalyzer" - if (-not (Test-Path "$projectRoot/global.json")) - { - throw "Not in solution root" - } + #Write-Progress "Building ScriptAnalyzer" + if (-not (Test-Path "$projectRoot/global.json")) + { + throw "Not in solution root" + } - $itemsToCopyCommon = @( - "$projectRoot\Engine\PSScriptAnalyzer.psd1", "$projectRoot\Engine\PSScriptAnalyzer.psm1", - "$projectRoot\Engine\ScriptAnalyzer.format.ps1xml", "$projectRoot\Engine\ScriptAnalyzer.types.ps1xml" - ) + $itemsToCopyCommon = @( + "$projectRoot\Engine\PSScriptAnalyzer.psd1", "$projectRoot\Engine\PSScriptAnalyzer.psm1", + "$projectRoot\Engine\ScriptAnalyzer.format.ps1xml", "$projectRoot\Engine\ScriptAnalyzer.types.ps1xml" + ) - $settingsFiles = Get-Childitem "$projectRoot\Engine\Settings" | ForEach-Object -MemberName FullName + $settingsFiles = Get-Childitem "$projectRoot\Engine\Settings" | ForEach-Object -MemberName FullName - $destinationDir = "$projectRoot\out\PSScriptAnalyzer" - # this is normalizing case as well as selecting the proper location - if ( $Framework -eq "core" ) { - $destinationDirBinaries = "$destinationDir\coreclr" - } - elseif ($AnalyzerVersion -eq 'PSv3') { - $destinationDirBinaries = "$destinationDir\PSv3" - } - elseif ($AnalyzerVersion -eq 'PSv4') { - $destinationDirBinaries = "$destinationDir\PSv4" - } - else { - $destinationDirBinaries = $destinationDir - } + $destinationDir = "$projectRoot\out\PSScriptAnalyzer" + # this is normalizing case as well as selecting the proper location + if ( $Framework -eq "core" ) { + $destinationDirBinaries = "$destinationDir\coreclr" + } + elseif ($AnalyzerVersion -eq 'PSv3') { + $destinationDirBinaries = "$destinationDir\PSv3" + } + elseif ($AnalyzerVersion -eq 'PSv4') { + $destinationDirBinaries = "$destinationDir\PSv4" + } + else { + $destinationDirBinaries = $destinationDir + } - # build the analyzer - #Write-Progress "Building for framework $Framework, configuration $Configuration" - # The Rules project has a dependency on the Engine therefore just building the Rules project is enough - try { - Push-Location $projectRoot/Rules - Write-Progress "Building ScriptAnalyzer '$framework' version '${AnalyzerVersion}' configuration '${Configuration}'" - $buildOutput = dotnet build Rules.csproj --framework $frameworkName --configuration "${AnalyzerVersion}${Configuration}" - if ( $LASTEXITCODE -ne 0 ) { throw "$buildOutput" } - } - catch { - Write-Error "Failure to build $framework ${AnalyzerVersion}${Configuration}" - return - } - finally { - Pop-Location - } + # build the analyzer + #Write-Progress "Building for framework $Framework, configuration $Configuration" + # The Rules project has a dependency on the Engine therefore just building the Rules project is enough + try { + Push-Location $projectRoot/Rules + Write-Progress "Building ScriptAnalyzer '$framework' version '${AnalyzerVersion}' configuration '${Configuration}'" + $buildOutput = dotnet build Rules.csproj --framework $frameworkName --configuration "${AnalyzerVersion}${Configuration}" + if ( $LASTEXITCODE -ne 0 ) { throw "$buildOutput" } + } + catch { + Write-Error "Failure to build $framework ${AnalyzerVersion}${Configuration}" + return + } + finally { + Pop-Location + } - #Write-Progress "Copying files to $destinationDir" - Publish-File $itemsToCopyCommon $destinationDir + #Write-Progress "Copying files to $destinationDir" + Publish-File $itemsToCopyCommon $destinationDir - $itemsToCopyBinaries = @( - "$projectRoot\Engine\bin\${AnalyzerVersion}${Configuration}\${frameworkName}\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll", - "$projectRoot\Rules\bin\${AnalyzerVersion}${Configuration}\${frameworkName}\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll" - ) - Publish-File $itemsToCopyBinaries $destinationDirBinaries + $itemsToCopyBinaries = @( + "$projectRoot\Engine\bin\${AnalyzerVersion}${Configuration}\${frameworkName}\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll", + "$projectRoot\Rules\bin\${AnalyzerVersion}${Configuration}\${frameworkName}\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll" + ) + Publish-File $itemsToCopyBinaries $destinationDirBinaries - Publish-File $settingsFiles (Join-Path -Path $destinationDir -ChildPath Settings) + Publish-File $settingsFiles (Join-Path -Path $destinationDir -ChildPath Settings) - # copy newtonsoft dll if net451 framework - if ($Framework -eq "full") { - Copy-Item -path "$projectRoot\Rules\bin\${AnalyzerVersion}${Configuration}\${frameworkName}\Newtonsoft.Json.dll" -Destination $destinationDirBinaries - } + # copy newtonsoft dll if net451 framework + if ($Framework -eq "full") { + Copy-Item -path "$projectRoot\Rules\bin\${AnalyzerVersion}${Configuration}\${frameworkName}\Newtonsoft.Json.dll" -Destination $destinationDirBinaries + } - Pop-Location + Pop-Location + } } +# TEST HELPERS # Run our tests function Test-ScriptAnalyzer { [CmdletBinding()] - $testModulePath = Join-Path "${projectRoot}" -ChildPath out - $testResultsFile = Join-Path ${projectRoot} -childPath TestResults.xml - $testScripts = "${projectRoot}\Tests\Engine,${projectRoot}\Tests\Rules,${projectRoot}\Tests\Documentation" - try { - $savedModulePath = $env:PSModulePath - $env:PSModulePath = "${testModulePath}{0}${env:PSModulePath}" -f [System.IO.Path]::PathSeparator - $scriptBlock = [scriptblock]::Create("Invoke-Pester -Path $testScripts -OutputFormat NUnitXml -OutputFile $testResultsFile -Show Describe") - Write-Verbose -verbose "$scriptBlock" - $powershell = (Get-Process -id $PID).MainModule.FileName - & ${powershell} -Command $scriptBlock - } - finally { - $env:PSModulePath = $savedModulePath + param ( [Parameter()][switch]$InProcess ) + + END { + $testModulePath = Join-Path "${projectRoot}" -ChildPath out + $testResultsFile = Join-Path ${projectRoot} -childPath TestResults.xml + $testScripts = "${projectRoot}\Tests\Engine,${projectRoot}\Tests\Rules,${projectRoot}\Tests\Documentation" + try { + $savedModulePath = $env:PSModulePath + $env:PSModulePath = "${testModulePath}{0}${env:PSModulePath}" -f [System.IO.Path]::PathSeparator + $scriptBlock = [scriptblock]::Create("Invoke-Pester -Path $testScripts -OutputFormat NUnitXml -OutputFile $testResultsFile -Show Describe") + if ( $InProcess ) { + & $scriptBlock + } + else { + $powershell = (Get-Process -id $PID).MainModule.FileName + & ${powershell} -Command $scriptBlock + } + } + finally { + $env:PSModulePath = $savedModulePath + } } } diff --git a/buildCoreClr.ps1 b/buildCoreClr.ps1 deleted file mode 100644 index 4a72331ef..000000000 --- a/buildCoreClr.ps1 +++ /dev/null @@ -1,97 +0,0 @@ -param( - [switch]$Build, - [switch]$Uninstall, - [switch]$Install, - - [ValidateSet("net451", "netstandard2.0")] - [string]$Framework = "netstandard2.0", - - [ValidateSet("Debug", "Release", "PSv3Debug", "PSv3Release", "PSv4Release")] - [string]$Configuration = "Debug" -) - -if ($Configuration -match "PSv" -and $Framework -eq "netstandard2.0") -{ - throw ("{0} configuration is not applicable to {1} framework" -f $Configuration,$Framework) -} - -Write-Progress "Building ScriptAnalyzer" -$solutionDir = Split-Path $MyInvocation.InvocationName -if (-not (Test-Path "$solutionDir/global.json")) -{ - throw "Not in solution root" -} - -$itemsToCopyBinaries = @("$solutionDir\Engine\bin\$Configuration\$Framework\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll", - "$solutionDir\Rules\bin\$Configuration\$Framework\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll") - -$itemsToCopyCommon = @("$solutionDir\Engine\PSScriptAnalyzer.psd1", - "$solutionDir\Engine\PSScriptAnalyzer.psm1", - "$solutionDir\Engine\ScriptAnalyzer.format.ps1xml", - "$solutionDir\Engine\ScriptAnalyzer.types.ps1xml") - -$destinationDir = "$solutionDir\out\PSScriptAnalyzer" -$destinationDirBinaries = $destinationDir -if ($Framework -eq "netstandard2.0") -{ - $destinationDirBinaries = "$destinationDir\coreclr" -} -elseif ($Configuration -match 'PSv3') { - $destinationDirBinaries = "$destinationDir\PSv3" -} -elseif ($Configuration -match 'PSv4') { - $destinationDirBinaries = "$destinationDir\PSv4" -} - -if ($build) -{ - Write-Progress "Building for framework $Framework, configuration $Configuration" - # The Rules project has a dependency on the Engine therefore just building the Rules project is enough - Push-Location Rules\ - dotnet build Rules.csproj --framework $Framework --configuration $Configuration - Pop-Location - - Function CopyToDestinationDir($itemsToCopy, $destination) - { - if (-not (Test-Path $destination)) - { - $null = New-Item -ItemType Directory $destination -Force - } - foreach ($file in $itemsToCopy) - { - Copy-Item -Path $file -Destination (Join-Path $destination (Split-Path $file -Leaf)) -Force - } - } - - - Write-Progress "Copying files to $destinationDir" - CopyToDestinationDir $itemsToCopyCommon $destinationDir - CopyToDestinationDir $itemsToCopyBinaries $destinationDirBinaries - - # Copy Settings File - Copy-Item -Path "$solutionDir\Engine\Settings" -Destination $destinationDir -Force -Recurse - - # copy newtonsoft dll if net451 framework - if ($Framework -eq "net451") - { - copy-item -path "$solutionDir\Rules\bin\$Configuration\$Framework\Newtonsoft.Json.dll" -Destination $destinationDirBinaries - } -} - -$modulePath = "$HOME\Documents\WindowsPowerShell\Modules"; -$pssaModulePath = Join-Path $modulePath PSScriptAnalyzer - - -if ($uninstall) -{ - if ((Test-Path $pssaModulePath)) - { - Remove-Item -Recurse $pssaModulePath - } -} - -if ($install) -{ - Write-Progress "Installing to $modulePath" - Copy-Item -Recurse -Path "$destinationDir" -Destination "$modulePath\." -Force -} From 90e795712c95aebf5c59e1fd74a8a5315723acb0 Mon Sep 17 00:00:00 2001 From: James Truher Date: Fri, 5 Oct 2018 14:32:05 -0700 Subject: [PATCH 05/16] Modify readme to match new build instructions --- README.md | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 590afbb2b..2a0b8496d 100644 --- a/README.md +++ b/README.md @@ -123,25 +123,33 @@ Note: the PSScriptAnalyzer Chocolatey package is provided and supported by the c * Building You can either build using the `Visual Studio` solution `PSScriptAnalyzer.sln` or build using `PowerShell` specifically for your platform as follows: - * Windows PowerShell version 5.0 and greater + * The default build is for PowerShell Core ```powershell - .\buildCoreClr.ps1 -Framework net451 -Configuration Release -Build + .\build.ps1 + ``` + * Windows PowerShell version 5.0 + ```powershell + .\build.ps1 -Framework full -AnalyzerVersion PSV5 -Configuration Release ``` * Windows PowerShell version 4.0 ```powershell - .\buildCoreClr.ps1 -Framework net451 -Configuration PSV4Release -Build + .\build.ps1 -Framework full -AnalyzerVersion PSV4 -Configuration Release ``` * Windows PowerShell version 3.0 ```powershell - .\buildCoreClr.ps1 -Framework net451 -Configuration PSV3Release -Build + .\build.ps1 -Framework full -AnalyzerVersion PSV3 -Configuration Release ``` * PowerShell Core ```powershell - .\buildCoreClr.ps1 -Framework netstandard2.0 -Configuration Release -Build + .\buildCoreClr.ps1 -Framework core -Configuration Release -Build + ``` +* Build documentation + ```powershell + .\build.ps1 -Documentation ``` -* Build documenatation +* Build all versions (PowerShell v3, v4, v5, and Core) and documentation ```powershell - .\build.ps1 -BuildDocs + .\build.ps1 -All ``` * Import the module ```powershell @@ -157,12 +165,25 @@ For adding/removing resource strings in the `*.resx` files, it is recommended to #### Tests Pester-based ScriptAnalyzer Tests are located in `path/to/PSScriptAnalyzer/Tests` folder. -* Ensure [Pester 4.3.1](https://www.powershellgallery.com/packages/Pester/4.3.1) is installed -* Copy `path/to/PSScriptAnalyzer/out/PSScriptAnalyzer` to a folder in `PSModulePath` +* Ensure [Pester 4.3.1](https://www.powershellgallery.com/packages/Pester/4.3.1) or higher is installed +* Ensure that the documentation has been built (`./build.ps1 -Documentation`) * In the root folder of your local repository, run: ``` PowerShell -$testScripts = ".\Tests\Engine",".\Tests\Rules",".\Tests\Documentation" -Invoke-Pester -Script $testScripts +./build -Test +``` + +To retrieve the results of the run, you can use the tools which are part of the build module (`build.psm1`) + +```powershell +Import-Module ./build.psm1 +Get-TestResults +``` + +To retrieve only the errors, you can use the following: + +```powershell +Import-Module ./build.psm1 +Get-TestFailures ``` [Back to ToC](#table-of-contents) From 3064367728754c17ab70424a9c36f3923e097b2c Mon Sep 17 00:00:00 2001 From: James Truher Date: Tue, 16 Oct 2018 14:55:51 -0700 Subject: [PATCH 06/16] Add ubuntu16 docker file to build scripts --- tools/docker/ubuntu16/Dockerfile | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tools/docker/ubuntu16/Dockerfile diff --git a/tools/docker/ubuntu16/Dockerfile b/tools/docker/ubuntu16/Dockerfile new file mode 100644 index 000000000..f5c196721 --- /dev/null +++ b/tools/docker/ubuntu16/Dockerfile @@ -0,0 +1,12 @@ +FROM mcr.microsoft.com/powershell:ubuntu-16.04 + +ENV __InContainer 1 + +RUN apt update -qq && apt install -q -y wget git apt-transport-https +RUN wget -q https://packages.microsoft.com/config/ubuntu/16.04/packages-microsoft-prod.deb && dpkg -i packages-microsoft-prod.deb + +RUN apt update -qq && \ + cd / && \ + git clone https://github.com/JamesWTruher/PSScriptAnalyzer + +RUN pwsh -c 'save-module -name platyps,pester -path $PSHOME/Modules' From f46abf3a27cc48efb89f8672e06a3498b9c2cda9 Mon Sep 17 00:00:00 2001 From: James Truher Date: Tue, 16 Oct 2018 16:47:13 -0700 Subject: [PATCH 07/16] change to use psversion rather than analyzerversion because it's really about the version of PS, not the analyzer --- README.md | 6 +++--- build.ps1 | 11 ++++++----- build.psm1 | 38 ++++++++++++++++++++++---------------- 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 2a0b8496d..dc0fe356c 100644 --- a/README.md +++ b/README.md @@ -129,15 +129,15 @@ Note: the PSScriptAnalyzer Chocolatey package is provided and supported by the c ``` * Windows PowerShell version 5.0 ```powershell - .\build.ps1 -Framework full -AnalyzerVersion PSV5 -Configuration Release + .\build.ps1 -Framework full -PSVersion 5 -Configuration Release ``` * Windows PowerShell version 4.0 ```powershell - .\build.ps1 -Framework full -AnalyzerVersion PSV4 -Configuration Release + .\build.ps1 -Framework full -PSVersion 4 -Configuration Release ``` * Windows PowerShell version 3.0 ```powershell - .\build.ps1 -Framework full -AnalyzerVersion PSV3 -Configuration Release + .\build.ps1 -Framework full -PSVersion 3 -Configuration Release ``` * PowerShell Core ```powershell diff --git a/build.ps1 b/build.ps1 index 01ee2c890..6163626ce 100644 --- a/build.ps1 +++ b/build.ps1 @@ -8,10 +8,11 @@ param( [string]$Framework = "core", [Parameter(ParameterSetName="BuildOne")] - [ValidateSet("PSv3","PSv4","PSv5")] - [string]$AnalyzerVersion = "PSv5", + [ValidateSet("3","4","5")] + [string]$PSVersion = "5", [Parameter(ParameterSetName="BuildOne")] + [Parameter(ParameterSetName="BuildAll")] [ValidateSet("Debug", "Release")] [string]$Configuration = "Debug", @@ -44,7 +45,7 @@ END { $setName = $PSCmdlet.ParameterSetName switch ( $setName ) { "BuildAll" { - Build-ScriptAnalyzer -All + Build-ScriptAnalyzer -All -Configuration $Configuration } "BuildDoc" { Build-ScriptAnalyzer -Documentation @@ -52,7 +53,7 @@ END { "BuildOne" { $buildArgs = @{ Framework = $Framework - AnalyzerVersion = $AnalyzerVersion + PSVersion = $PSVersion Configuration = $Configuration } Build-ScriptAnalyzer @buildArgs @@ -65,4 +66,4 @@ END { throw "Unexpected parameter set '$setName'" } } -} \ No newline at end of file +} diff --git a/build.psm1 b/build.psm1 index e28d46fa2..d510b2596 100644 --- a/build.psm1 +++ b/build.psm1 @@ -121,10 +121,11 @@ function Build-ScriptAnalyzer [string]$Framework = "core", [Parameter(ParameterSetName="BuildOne")] - [ValidateSet("PSv3","PSv4","PSv5")] - [string]$AnalyzerVersion = "PSv5", + [ValidateSet("3","4","5")] + [string]$PSVersion = "5", [Parameter(ParameterSetName="BuildOne")] + [Parameter(ParameterSetName="BuildAll")] [ValidateSet("Debug", "Release")] [string]$Configuration = "Debug", @@ -132,14 +133,19 @@ function Build-ScriptAnalyzer [switch]$Documentation ) + BEGIN { + if ( $PSVersion -match "[34]" -and $Framework -eq "core" ) { + throw "Script Analyzer for PowerShell 3/4 cannot be built for framework 'core'" + } + } END { if ( $All ) { # Build all the versions of the analyzer - Build-ScriptAnalyzer -Framework full -Configuration $Configuration -AnalyzerVersion "PSv3" - Build-ScriptAnalyzer -Framework full -Configuration $Configuration -AnalyzerVersion "PSv4" - Build-ScriptAnalyzer -Framework full -Configuration $Configuration -AnalyzerVersion "PSv5" - Build-ScriptAnalyzer -Framework core -Configuration $Configuration -AnalyzerVersion "PSv5" + Build-ScriptAnalyzer -Framework full -Configuration $Configuration -PSVersion "3" + Build-ScriptAnalyzer -Framework full -Configuration $Configuration -PSVersion "4" + Build-ScriptAnalyzer -Framework full -Configuration $Configuration -PSVersion "5" + Build-ScriptAnalyzer -Framework core -Configuration $Configuration -PSVersion "5" Build-ScriptAnalyzer -Documentation return } @@ -160,9 +166,9 @@ function Build-ScriptAnalyzer } # build the appropriate assembly - if ($AnalyzerVersion -match "PSv3|PSv4" -and $Framework -eq "core") + if ($PSVersion -match "[34]" -and $Framework -eq "core") { - throw ("ScriptAnalyzer Version '{0}' is not applicable to {1} framework" -f $AnalyzerVersion,$Framework) + throw ("ScriptAnalyzer for PS version '{0}' is not applicable to {1} framework" -f $PSVersion,$Framework) } #Write-Progress "Building ScriptAnalyzer" @@ -183,10 +189,10 @@ function Build-ScriptAnalyzer if ( $Framework -eq "core" ) { $destinationDirBinaries = "$destinationDir\coreclr" } - elseif ($AnalyzerVersion -eq 'PSv3') { + elseif ($PSVersion -eq '3') { $destinationDirBinaries = "$destinationDir\PSv3" } - elseif ($AnalyzerVersion -eq 'PSv4') { + elseif ($PSVersion -eq '4') { $destinationDirBinaries = "$destinationDir\PSv4" } else { @@ -198,12 +204,12 @@ function Build-ScriptAnalyzer # The Rules project has a dependency on the Engine therefore just building the Rules project is enough try { Push-Location $projectRoot/Rules - Write-Progress "Building ScriptAnalyzer '$framework' version '${AnalyzerVersion}' configuration '${Configuration}'" - $buildOutput = dotnet build Rules.csproj --framework $frameworkName --configuration "${AnalyzerVersion}${Configuration}" + Write-Progress "Building ScriptAnalyzer '$framework' version '${PSVersion}' configuration '${Configuration}'" + $buildOutput = dotnet build Rules.csproj --framework $frameworkName --configuration "${PSVersion}${Configuration}" if ( $LASTEXITCODE -ne 0 ) { throw "$buildOutput" } } catch { - Write-Error "Failure to build $framework ${AnalyzerVersion}${Configuration}" + Write-Error "Failure to build $framework ${PSVersion}${Configuration}" return } finally { @@ -214,8 +220,8 @@ function Build-ScriptAnalyzer Publish-File $itemsToCopyCommon $destinationDir $itemsToCopyBinaries = @( - "$projectRoot\Engine\bin\${AnalyzerVersion}${Configuration}\${frameworkName}\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll", - "$projectRoot\Rules\bin\${AnalyzerVersion}${Configuration}\${frameworkName}\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll" + "$projectRoot\Engine\bin\${PSVersion}${Configuration}\${frameworkName}\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll", + "$projectRoot\Rules\bin\${PSVersion}${Configuration}\${frameworkName}\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll" ) Publish-File $itemsToCopyBinaries $destinationDirBinaries @@ -223,7 +229,7 @@ function Build-ScriptAnalyzer # copy newtonsoft dll if net451 framework if ($Framework -eq "full") { - Copy-Item -path "$projectRoot\Rules\bin\${AnalyzerVersion}${Configuration}\${frameworkName}\Newtonsoft.Json.dll" -Destination $destinationDirBinaries + Copy-Item -path "$projectRoot\Rules\bin\${PSVersion}${Configuration}\${frameworkName}\Newtonsoft.Json.dll" -Destination $destinationDirBinaries } Pop-Location From 1b8386a5d5563bca6baa0cf5a2a8db6b7321619f Mon Sep 17 00:00:00 2001 From: James Truher Date: Wed, 17 Oct 2018 15:02:34 -0700 Subject: [PATCH 08/16] Add copyright banners to script and module --- build.ps1 | 3 +++ build.psm1 | 3 +++ 2 files changed, 6 insertions(+) diff --git a/build.ps1 b/build.ps1 index 6163626ce..7830b5a23 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,3 +1,6 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + [CmdletBinding(DefaultParameterSetName="BuildOne")] param( [Parameter(ParameterSetName="BuildAll")] diff --git a/build.psm1 b/build.psm1 index d510b2596..547350ffc 100644 --- a/build.psm1 +++ b/build.psm1 @@ -1,3 +1,6 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + # Build module for PowerShell ScriptAnalyzer $projectRoot = $PSScriptRoot $destinationDir = Join-Path -Path $projectRoot -ChildPath (Join-Path -Path "out" -ChildPath "PSScriptAnalyzer") From 2978f78e8775deab2c6a081cf36605a2f5ca2e60 Mon Sep 17 00:00:00 2001 From: James Truher Date: Wed, 17 Oct 2018 16:14:29 -0700 Subject: [PATCH 09/16] Fix repo to point to the official repo --- tools/docker/ubuntu16/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/docker/ubuntu16/Dockerfile b/tools/docker/ubuntu16/Dockerfile index f5c196721..7bb23eb74 100644 --- a/tools/docker/ubuntu16/Dockerfile +++ b/tools/docker/ubuntu16/Dockerfile @@ -7,6 +7,6 @@ RUN wget -q https://packages.microsoft.com/config/ubuntu/16.04/packages-microsof RUN apt update -qq && \ cd / && \ - git clone https://github.com/JamesWTruher/PSScriptAnalyzer + git clone https://github.com/PowerShell/PSScriptAnalyzer RUN pwsh -c 'save-module -name platyps,pester -path $PSHOME/Modules' From 5c019785ce47081fd710da978a68d8d85f7fb85a Mon Sep 17 00:00:00 2001 From: James Truher Date: Thu, 18 Oct 2018 11:50:18 -0700 Subject: [PATCH 10/16] Update appveyor scripts to use new build script --- appveyor.yml | 43 +++++++++++++++++++++---------------------- build.psm1 | 6 +++--- tools/appveyor.psm1 | 42 ++++++++---------------------------------- 3 files changed, 32 insertions(+), 59 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 850d5b413..986a0e22d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,17 +1,16 @@ environment: + PSVersion: 5 + BuildConfiguration: Release matrix: - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 PowerShellEdition: PowerShellCore - BuildConfiguration: Release - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 PowerShellEdition: WindowsPowerShell - BuildConfiguration: Release - APPVEYOR_BUILD_WORKER_IMAGE: WMF 4 PowerShellEdition: WindowsPowerShell - BuildConfiguration: PSv4Release + PSVersion: 4 - APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu PowerShellEdition: PowerShellCore - BuildConfiguration: Release # cache Nuget packages and dotnet CLI cache cache: @@ -33,29 +32,29 @@ install: build_script: - ps: | - if ($env:PowerShellEdition -eq 'WindowsPowerShell') { - if ($env:BuildConfiguration -eq 'PSv4Release') { - # On WMF$: Also build for v3 to check it builds at least since we do not have a WMF3 image - Invoke-AppveyorBuild -CheckoutPath $env:APPVEYOR_BUILD_FOLDER -BuildConfiguration PSv3Release -BuildType 'FullCLR' - } - Invoke-AppveyorBuild -CheckoutPath $env:APPVEYOR_BUILD_FOLDER -BuildConfiguration $env:BuildConfiguration -BuildType 'FullCLR' - } + Set-Location $env:APPVEYOR_BUILD_FOLDER + ./build.ps1 -Documentation + if ( $env:PSVersion -eq "4" ) { # On WMF4: Also build for v3 to check it builds at least since we do not have a WMF3 image + ./build.ps1 -Configuration "$env:BuildConfiguration" -PSVersion 3 -Framework full + } + ./build.ps1 -Configuration "$env:BuildConfiguration" -PSVersion "$env:PSVersion" -Framework full - pwsh: | - if ($env:PowerShellEdition -eq 'PowerShellCore') { - Import-Module .\tools\appveyor.psm1 # Appveyor does not persist pwsh sessions like it does for ps - Invoke-AppveyorBuild -CheckoutPath $env:APPVEYOR_BUILD_FOLDER -BuildConfiguration $env:BuildConfiguration -BuildType 'NetStandard' - } + if ($env:PowerShellEdition -eq 'PowerShellCore') { + Set-Location $env:APPVEYOR_BUILD_FOLDER + ./build.ps1 -Documentation + ./build.ps1 -Configuration "$env:BuildConfiguration" -PSVersion 5 -Framework core + } test_script: - ps: | - if ($env:PowerShellEdition -eq 'WindowsPowerShell') { - Invoke-AppveyorTest -CheckoutPath $env:APPVEYOR_BUILD_FOLDER - } + if ($env:PowerShellEdition -eq 'WindowsPowerShell') { + Invoke-AppveyorTest -CheckoutPath $env:APPVEYOR_BUILD_FOLDER + } - pwsh: | - if ($env:PowerShellEdition -eq 'PowerShellCore') { - Import-Module .\tools\appveyor.psm1 # Appveyor does not persist pwsh sessions like it does for ps - Invoke-AppveyorTest -CheckoutPath $env:APPVEYOR_BUILD_FOLDER - } + if ($env:PowerShellEdition -eq 'PowerShellCore') { + Import-Module .\tools\appveyor.psm1 # Appveyor does not persist pwsh sessions like it does for ps + Invoke-AppveyorTest -CheckoutPath $env:APPVEYOR_BUILD_FOLDER + } # Upload the project along with test results as a zip archive on_finish: diff --git a/build.psm1 b/build.psm1 index 547350ffc..61b63bee5 100644 --- a/build.psm1 +++ b/build.psm1 @@ -87,7 +87,6 @@ function Remove-Build } } - # Build documentation using platyPS function Build-Documentation { @@ -95,8 +94,9 @@ function Build-Documentation $markdownDocsPath = Join-Path $docsPath markdown $outputDocsPath = Join-Path $destinationDir en-US $requiredVersionOfplatyPS = 0.9 - $modInfo = new-object Microsoft.PowerShell.Commands.ModuleSpecification -ArgumentList @{ ModuleName = "platyps"; ModuleVersion = $requiredVersionOfplatyPS} - if ( $null -eq (Get-Module -ListAvailable -FullyQualifiedName $modInfo)) + #$modInfo = new-object Microsoft.PowerShell.Commands.ModuleSpecification -ArgumentList @{ ModuleName = "platyps"; ModuleVersion = $requiredVersionOfplatyPS} + #if ( $null -eq (Get-Module -ListAvailable -FullyQualifiedName $modInfo)) + if ( $null -eq (Get-Module -ListAvailable platyPS)) { throw "Cannot find required minimum version $requiredVersionOfplatyPS of platyPS. Install via 'Install-Module platyPS'" } diff --git a/tools/appveyor.psm1 b/tools/appveyor.psm1 index 130488f8d..a65c95b19 100644 --- a/tools/appveyor.psm1 +++ b/tools/appveyor.psm1 @@ -5,31 +5,36 @@ $ErrorActionPreference = 'Stop' # Implements the AppVeyor 'install' step and installs the required versions of Pester, platyPS and the .Net Core SDK if needed. function Invoke-AppVeyorInstall { - $requiredPesterVersion = '4.3.1' + $requiredPesterVersion = '4.4.1' $pester = Get-Module Pester -ListAvailable | Where-Object { $_.Version -eq $requiredPesterVersion } if ($null -eq $pester) { if ($null -eq (Get-Module -ListAvailable PowershellGet)) { # WMF 4 image build + Write-Verbose -Verbose "Installing Pester via nuget" nuget install Pester -Version $requiredPesterVersion -source https://www.powershellgallery.com/api/v2 -outputDirectory "$env:ProgramFiles\WindowsPowerShell\Modules\." -ExcludeVersion } else { # Visual Studio 2017 build (has already Pester v3, therefore a different installation mechanism is needed to make it also use the new version 4) + Write-Verbose -Verbose "Installing Pester via Install-Module" Install-Module -Name Pester -Force -SkipPublisherCheck -Scope CurrentUser } } if ($null -eq (Get-Module -ListAvailable PowershellGet)) { # WMF 4 image build + Write-Verbose -Verbose "Installing platyPS via nuget" nuget install platyPS -Version 0.9.0 -source https://www.powershellgallery.com/api/v2 -outputDirectory "$Env:ProgramFiles\WindowsPowerShell\Modules\." -ExcludeVersion } else { + Write-Verbose -Verbose "Installing platyPS via Install-Module" Install-Module -Name platyPS -Force -Scope CurrentUser -RequiredVersion '0.9.0' } # the legacy WMF4 image only has the old preview SDKs of dotnet $globalDotJson = Get-Content (Join-Path $PSScriptRoot '..\global.json') -Raw | ConvertFrom-Json $dotNetCoreSDKVersion = $globalDotJson.sdk.version - if (-not ((dotnet --version).StartsWith($dotNetCoreSDKVersion))) { + # don't try to run this script on linux - we have to do the negative check because IsLinux will be defined in core, but not windows + if (-not ((dotnet --version).StartsWith($dotNetCoreSDKVersion)) -and ! $IsLinux ) { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 # https://github.com/dotnet/announcements/issues/77 Invoke-WebRequest 'https://dot.net/v1/dotnet-install.ps1' -OutFile dotnet-install.ps1 .\dotnet-install.ps1 -Version $dotNetCoreSDKVersion @@ -37,37 +42,6 @@ function Invoke-AppVeyorInstall { } } -# Implements the AppVeyor 'build_script' step -function Invoke-AppVeyorBuild { - Param( - [Parameter(Mandatory)] - [ValidateSet('FullCLR', 'NetStandard')] - $BuildType, - - [Parameter(Mandatory)] - [ValidateSet('Release', 'PSv3Release', 'PSv4Release')] - $BuildConfiguration, - - [Parameter(Mandatory)] - [ValidateScript( {Test-Path $_})] - $CheckoutPath - ) - - $PSVersionTable - Write-Verbose "Pester version: $((Get-Command Invoke-Pester).Version)" -Verbose - Write-Verbose ".NET SDK version: $(dotnet --version)" -Verbose - Push-Location $CheckoutPath - [Environment]::SetEnvironmentVariable("DOTNET_SKIP_FIRST_TIME_EXPERIENCE", 1) # avoid unneccessary initialization in CI - if ($BuildType -eq 'FullCLR') { - .\buildCoreClr.ps1 -Framework net451 -Configuration $BuildConfiguration -Build - } - elseif ($BuildType -eq 'NetStandard') { - .\buildCoreClr.ps1 -Framework netstandard2.0 -Configuration Release -Build - } - .\build.ps1 -BuildDocs - Pop-Location -} - # Implements AppVeyor 'test_script' step function Invoke-AppveyorTest { Param( @@ -97,4 +71,4 @@ function Invoke-AppveyorFinish { # You can add other artifacts here (Get-ChildItem $zipFile) ) | ForEach-Object { Push-AppveyorArtifact $_.FullName } -} \ No newline at end of file +} From 9ef4a9d47c402ff54708fa6823921a6ea7f24e33 Mon Sep 17 00:00:00 2001 From: James Truher Date: Thu, 18 Oct 2018 14:48:20 -0700 Subject: [PATCH 11/16] Forcing installation of platyPS if not found when building documentation --- appveyor.yml | 2 +- build.psm1 | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 986a0e22d..fdfd0a73a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -58,4 +58,4 @@ test_script: # Upload the project along with test results as a zip archive on_finish: - - ps: Import-Module .\tools\appveyor.psm1; Invoke-AppveyorFinish + - ps: Import-Module "${env:BuildConfiguration}\tools\appveyor.psm1"; Invoke-AppveyorFinish diff --git a/build.psm1 b/build.psm1 index 61b63bee5..5aadc1601 100644 --- a/build.psm1 +++ b/build.psm1 @@ -98,7 +98,9 @@ function Build-Documentation #if ( $null -eq (Get-Module -ListAvailable -FullyQualifiedName $modInfo)) if ( $null -eq (Get-Module -ListAvailable platyPS)) { - throw "Cannot find required minimum version $requiredVersionOfplatyPS of platyPS. Install via 'Install-Module platyPS'" + Write-Verbose -verbose "platyPS not found, installing" + Install-Module -Force -Name platyPS -Scope CurrentUser + # throw "Cannot find required minimum version $requiredVersionOfplatyPS of platyPS. Install via 'Install-Module platyPS'" } if (-not (Test-Path $markdownDocsPath)) { From e9c817557b3981f8756c5c711fe53ea4d807ed97 Mon Sep 17 00:00:00 2001 From: James Truher Date: Thu, 18 Oct 2018 16:00:09 -0700 Subject: [PATCH 12/16] Be sure to skip uses of TypeDefinitionAst on both PSV3 and PSV4 --- Engine/Generic/RuleSuppression.cs | 2 +- Engine/Helper.cs | 24 +++++++++++----------- Engine/VariableAnalysis.cs | 2 +- Engine/VariableAnalysisBase.cs | 16 +++++++-------- Rules/DscExamplesPresent.cs | 2 +- Rules/DscTestsPresent.cs | 2 +- Rules/ReturnCorrectTypesForDSCFunctions.cs | 6 +++--- Rules/UseOutputTypeCorrectly.cs | 4 ++-- Rules/UseStandardDSCFunctionsInResource.cs | 2 +- 9 files changed, 30 insertions(+), 30 deletions(-) diff --git a/Engine/Generic/RuleSuppression.cs b/Engine/Generic/RuleSuppression.cs index bdf023096..ac59d43b4 100644 --- a/Engine/Generic/RuleSuppression.cs +++ b/Engine/Generic/RuleSuppression.cs @@ -360,7 +360,7 @@ public static List GetSuppressions(IEnumerable at targetAsts = scopeAst.FindAll(item => item is FunctionDefinitionAst && reg.IsMatch((item as FunctionDefinitionAst).Name), true); goto default; - #if !PSV3 + #if !(PSV3||PSV4) case "class": targetAsts = scopeAst.FindAll(item => item is TypeDefinitionAst && reg.IsMatch((item as TypeDefinitionAst).Name), true); diff --git a/Engine/Helper.cs b/Engine/Helper.cs index 3d1f4a4ad..b093d9c0f 100644 --- a/Engine/Helper.cs +++ b/Engine/Helper.cs @@ -509,7 +509,7 @@ public bool IsDscResourceClassBased(ScriptBlockAst ast) return false; } - #if !PSV3 + #if !(PSV3||PSV4) List dscResourceFunctionNames = new List(new string[] { "Test", "Get", "Set" }); @@ -1018,7 +1018,7 @@ internal VariableAnalysis InitializeVariableAnalysisHelper(Ast ast, VariableAnal /// /// -#if PSV3 +#if (PSV3||PSV4) public string GetTypeFromReturnStatementAst(Ast funcAst, ReturnStatementAst ret) @@ -1089,7 +1089,7 @@ public string GetTypeFromReturnStatementAst(Ast funcAst, ReturnStatementAst ret, /// /// -#if PSV3 +#if (PSV3||PSV4) public string GetTypeFromMemberExpressionAst(MemberExpressionAst memberAst, Ast scopeAst) @@ -1106,7 +1106,7 @@ public string GetTypeFromMemberExpressionAst(MemberExpressionAst memberAst, Ast VariableAnalysisDetails details = null; -#if !PSV3 +#if !(PSV3||PSV4) TypeDefinitionAst psClass = null; @@ -1149,7 +1149,7 @@ public string GetTypeFromMemberExpressionAst(MemberExpressionAst memberAst, Ast /// /// -#if PSV3 +#if (PSV3||PSV4) internal string GetTypeFromMemberExpressionAstHelper(MemberExpressionAst memberAst, VariableAnalysisDetails analysisDetails) @@ -1162,7 +1162,7 @@ internal string GetTypeFromMemberExpressionAstHelper(MemberExpressionAst memberA //Try to get the type without using psClass first Type result = AssignmentTarget.GetTypeFromMemberExpressionAst(memberAst); -#if !PSV3 +#if !(PSV3||PSV4) //If we can't get the type, then it may be that the type of the object being invoked on is a powershell class if (result == null && psClass != null && analysisDetails != null) @@ -1270,7 +1270,7 @@ public Dictionary> GetRuleSuppression(Ast ast) ruleSuppressionList.AddRange(GetSuppressionsFunction(funcAst)); } -#if !PSV3 +#if !(PSV3||PSV4) // Get rule suppression from classes IEnumerable typeAsts = ast.FindAll(item => item is TypeDefinitionAst, true).Cast(); @@ -1322,7 +1322,7 @@ internal List GetSuppressionsFunction(FunctionDefinitionAst fun return result; } -#if !PSV3 +#if !(PSV3||PSV4) /// /// Returns a list of rule suppression from the class /// @@ -2039,7 +2039,7 @@ private object VisitStatementHelper(StatementAst statementAst) return null; } -#if PSV3 +#if (PSV3||PSV4) statementAst.Visit(this); @@ -2755,7 +2755,7 @@ public class FindPipelineOutput : ICustomAstVisitor { List> outputTypes; -#if !PSV3 +#if !(PSV3||PSV4) IEnumerable classes; @@ -2797,7 +2797,7 @@ static FindPipelineOutput() /// /// -#if PSV3 +#if (PSV3||PSV4) public FindPipelineOutput(FunctionDefinitionAst ast) @@ -2828,7 +2828,7 @@ public FindPipelineOutput(FunctionDefinitionAst ast, IEnumerable /// -#if PSV3 +#if (PSV3||PSV4) public static List> OutputTypes(FunctionDefinitionAst funcAst) { diff --git a/Engine/VariableAnalysis.cs b/Engine/VariableAnalysis.cs index 3434a8877..fd66ea2c4 100644 --- a/Engine/VariableAnalysis.cs +++ b/Engine/VariableAnalysis.cs @@ -205,7 +205,7 @@ public void AnalyzeImpl(Ast ast, VariableAnalysis outerAnalysis) parent = parent.Parent; } - #if !PSV3 + #if !(PSV3||PSV4) List classes = parent.FindAll(item => item is TypeDefinitionAst && (item as TypeDefinitionAst).IsClass, true) diff --git a/Engine/VariableAnalysisBase.cs b/Engine/VariableAnalysisBase.cs index 8e366a952..b55119d7a 100644 --- a/Engine/VariableAnalysisBase.cs +++ b/Engine/VariableAnalysisBase.cs @@ -165,7 +165,7 @@ internal void InitializeVariables(Ast ast) _variables.Add("true", new VariableAnalysisDetails { Name = "true", RealName = "true", Type = typeof(bool) }); _variables.Add("false", new VariableAnalysisDetails { Name = "false", RealName = "true", Type = typeof(bool) }); - #if !PSV3 + #if !(PSV3||PSV4) if (ast is FunctionMemberAst) { @@ -808,7 +808,7 @@ internal static void InitializeSSA(Dictionary V /// /// /// - #if PSV3 + #if (PSV3||PSV4) internal static Tuple, Dictionary> SparseSimpleConstants( Dictionary Variables, Block Entry) @@ -989,7 +989,7 @@ internal static Tuple, Dictionary /// - #if PSV3 + #if (PSV3||PSV4) internal static Type GetTypeFromMemberExpressionAst(MemberExpressionAst memAst, VariableAnalysisDetails analysis) @@ -1460,7 +1460,7 @@ internal static Type GetTypeFromMemberExpressionAst(MemberExpressionAst memberAs // isStatic is true result = GetTypeFromInvokeMemberAst(type, imeAst, methodName, true); } - #if !PSV3 + #if !(PSV3||PSV4) else { // Check for classes @@ -1498,7 +1498,7 @@ internal static Type GetTypeFromMemberExpressionAst(MemberExpressionAst memberAs { result = GetPropertyOrFieldTypeFromMemberExpressionAst(expressionType, fieldName); } - #if !PSV3 + #if !(PSV3||PSV4) else { // check for class type @@ -1531,7 +1531,7 @@ internal static Type GetTypeFromMemberExpressionAst(MemberExpressionAst memberAs if (memberAst.Expression is VariableExpressionAst && String.Equals((memberAst.Expression as VariableExpressionAst).VariablePath.UserPath, "this", StringComparison.OrdinalIgnoreCase)) { - #if !PSV3 + #if !(PSV3||PSV4) // Check that we are in a class TypeDefinitionAst psClass = FindClassAncestor(memberAst); @@ -1598,7 +1598,7 @@ internal static Type GetPropertyOrFieldTypeFromMemberExpressionAst(Type type, st return result; } -#if !PSV3 +#if !(PSV3||PSV4) /// /// Checks whether a class with the name name exists in the script that contains ast /// diff --git a/Rules/DscExamplesPresent.cs b/Rules/DscExamplesPresent.cs index 331991d02..6d0a01a3b 100644 --- a/Rules/DscExamplesPresent.cs +++ b/Rules/DscExamplesPresent.cs @@ -65,7 +65,7 @@ public IEnumerable AnalyzeDSCResource(Ast ast, string fileName } } - #if !PSV3 + #if !(PSV3||PSV4) /// /// AnalyzeDSCClass: Analyzes given DSC class diff --git a/Rules/DscTestsPresent.cs b/Rules/DscTestsPresent.cs index 21dbf10da..5c09ede8a 100644 --- a/Rules/DscTestsPresent.cs +++ b/Rules/DscTestsPresent.cs @@ -65,7 +65,7 @@ public IEnumerable AnalyzeDSCResource(Ast ast, string fileName } } - #if !PSV3 + #if !(PSV3||PSV4) /// /// AnalyzeDSCClass: Analyzes given DSC class diff --git a/Rules/ReturnCorrectTypesForDSCFunctions.cs b/Rules/ReturnCorrectTypesForDSCFunctions.cs index 693b7429f..08eb59df0 100644 --- a/Rules/ReturnCorrectTypesForDSCFunctions.cs +++ b/Rules/ReturnCorrectTypesForDSCFunctions.cs @@ -35,7 +35,7 @@ public IEnumerable AnalyzeDSCResource(Ast ast, string fileName IEnumerable functionDefinitionAsts = Helper.Instance.DscResourceFunctions(ast); - #if !PSV3 + #if !(PSV3||PSV4) IEnumerable classes = ast.FindAll(item => item is TypeDefinitionAst @@ -46,7 +46,7 @@ item is TypeDefinitionAst foreach (FunctionDefinitionAst func in functionDefinitionAsts) { - #if PSV3 + #if PSV3 || PSV4 List> outputTypes = FindPipelineOutput.OutputTypes(func); @@ -93,7 +93,7 @@ item is TypeDefinitionAst } } - #if !PSV3 + #if !(PSV3||PSV4) /// /// AnalyzeDSCClass: Analyzes given DSC Resource diff --git a/Rules/UseOutputTypeCorrectly.cs b/Rules/UseOutputTypeCorrectly.cs index 5d3708ac9..099cd9f25 100644 --- a/Rules/UseOutputTypeCorrectly.cs +++ b/Rules/UseOutputTypeCorrectly.cs @@ -22,7 +22,7 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules #endif public class UseOutputTypeCorrectly : SkipTypeDefinition, IScriptRule { - #if !PSV3 + #if !(PSV3||PSV4) private IEnumerable _classes; @@ -41,7 +41,7 @@ public IEnumerable AnalyzeScript(Ast ast, string fileName) DiagnosticRecords.Clear(); this.fileName = fileName; - #if !PSV3 + #if !(PSV3||PSV4) _classes = ast.FindAll(item => item is TypeDefinitionAst && ((item as TypeDefinitionAst).IsClass), true).Cast(); diff --git a/Rules/UseStandardDSCFunctionsInResource.cs b/Rules/UseStandardDSCFunctionsInResource.cs index 548414b06..b93147bf7 100644 --- a/Rules/UseStandardDSCFunctionsInResource.cs +++ b/Rules/UseStandardDSCFunctionsInResource.cs @@ -64,7 +64,7 @@ public IEnumerable AnalyzeDSCClass(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage); - #if PSV3 + #if (PSV3||PSV4) return null; From 118e0b27f1c7998e56bf75e6fb5b44fdad2a3a3e Mon Sep 17 00:00:00 2001 From: James Truher Date: Thu, 18 Oct 2018 16:24:06 -0700 Subject: [PATCH 13/16] Modified logic to not build full on non-Windows Add additional verbose statements for debugging --- appveyor.yml | 14 ++++++++------ tools/appveyor.psm1 | 2 ++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index fdfd0a73a..49ed21b69 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -32,12 +32,14 @@ install: build_script: - ps: | - Set-Location $env:APPVEYOR_BUILD_FOLDER - ./build.ps1 -Documentation - if ( $env:PSVersion -eq "4" ) { # On WMF4: Also build for v3 to check it builds at least since we do not have a WMF3 image - ./build.ps1 -Configuration "$env:BuildConfiguration" -PSVersion 3 -Framework full + if ( $env:PowerShellEdition -eq 'WindowsPowerShell' ) { + Set-Location $env:APPVEYOR_BUILD_FOLDER + ./build.ps1 -Documentation + if ( $env:PSVersion -eq "4" ) { # On WMF4: Also build for v3 to check it builds at least since we do not have a WMF3 image + ./build.ps1 -Configuration "$env:BuildConfiguration" -PSVersion 3 -Framework full + } + ./build.ps1 -Configuration "$env:BuildConfiguration" -PSVersion "$env:PSVersion" -Framework full } - ./build.ps1 -Configuration "$env:BuildConfiguration" -PSVersion "$env:PSVersion" -Framework full - pwsh: | if ($env:PowerShellEdition -eq 'PowerShellCore') { Set-Location $env:APPVEYOR_BUILD_FOLDER @@ -58,4 +60,4 @@ test_script: # Upload the project along with test results as a zip archive on_finish: - - ps: Import-Module "${env:BuildConfiguration}\tools\appveyor.psm1"; Invoke-AppveyorFinish + - ps: Import-Module "${env:APPVEYOR_BUILD_FOLDER}\tools\appveyor.psm1"; Invoke-AppveyorFinish diff --git a/tools/appveyor.psm1 b/tools/appveyor.psm1 index a65c95b19..cc8e15f81 100644 --- a/tools/appveyor.psm1 +++ b/tools/appveyor.psm1 @@ -50,6 +50,8 @@ function Invoke-AppveyorTest { $CheckoutPath ) + Write-Verbose -Verbose ("Running tests on PowerShell version " + $PSVersionTable.PSVersion) + $modulePath = $env:PSModulePath.Split([System.IO.Path]::PathSeparator) | Where-Object { Test-Path $_} | Select-Object -First 1 Copy-Item "${CheckoutPath}\out\PSScriptAnalyzer" "$modulePath\" -Recurse -Force $testResultsFile = ".\TestResults.xml" From 9a20e2288cf62f76d5c7f6196278c701a83125f0 Mon Sep 17 00:00:00 2001 From: James Truher Date: Fri, 19 Oct 2018 14:06:41 -0700 Subject: [PATCH 14/16] fix issue with incorrect build configuration When simplifying to use only psversion, add back the 'PSV' prolog to configuration --- build.ps1 | 6 +++--- build.psm1 | 27 ++++++++++++++------------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/build.ps1 b/build.ps1 index 7830b5a23..e0e0712cd 100644 --- a/build.ps1 +++ b/build.ps1 @@ -48,10 +48,10 @@ END { $setName = $PSCmdlet.ParameterSetName switch ( $setName ) { "BuildAll" { - Build-ScriptAnalyzer -All -Configuration $Configuration + Start-ScriptAnalyzerBuild -All -Configuration $Configuration } "BuildDoc" { - Build-ScriptAnalyzer -Documentation + Start-ScriptAnalyzerBuild -Documentation } "BuildOne" { $buildArgs = @{ @@ -59,7 +59,7 @@ END { PSVersion = $PSVersion Configuration = $Configuration } - Build-ScriptAnalyzer @buildArgs + Start-ScriptAnalyzerBuild @buildArgs } "Test" { Test-ScriptAnalyzer -InProcess:$InProcess diff --git a/build.psm1 b/build.psm1 index 5aadc1601..5473a0da7 100644 --- a/build.psm1 +++ b/build.psm1 @@ -88,7 +88,7 @@ function Remove-Build } # Build documentation using platyPS -function Build-Documentation +function Start-DocumentationBuild { $docsPath = Join-Path $projectRoot docs $markdownDocsPath = Join-Path $docsPath markdown @@ -114,7 +114,7 @@ function Build-Documentation } # build script analyzer (and optionally build everything with -All) -function Build-ScriptAnalyzer +function Start-ScriptAnalyzerBuild { [CmdletBinding(DefaultParameterSetName="BuildOne")] param ( @@ -147,17 +147,17 @@ function Build-ScriptAnalyzer if ( $All ) { # Build all the versions of the analyzer - Build-ScriptAnalyzer -Framework full -Configuration $Configuration -PSVersion "3" - Build-ScriptAnalyzer -Framework full -Configuration $Configuration -PSVersion "4" - Build-ScriptAnalyzer -Framework full -Configuration $Configuration -PSVersion "5" - Build-ScriptAnalyzer -Framework core -Configuration $Configuration -PSVersion "5" - Build-ScriptAnalyzer -Documentation + Start-ScriptAnalyzerBuild -Framework full -Configuration $Configuration -PSVersion "3" + Start-ScriptAnalyzerBuild -Framework full -Configuration $Configuration -PSVersion "4" + Start-ScriptAnalyzerBuild -Framework full -Configuration $Configuration -PSVersion "5" + Start-ScriptAnalyzerBuild -Framework core -Configuration $Configuration -PSVersion "5" + Start-ScriptAnalyzerBuild -Documentation return } if ( $Documentation ) { - Build-Documentation + Start-DocumentationBuild return } @@ -207,14 +207,15 @@ function Build-ScriptAnalyzer # build the analyzer #Write-Progress "Building for framework $Framework, configuration $Configuration" # The Rules project has a dependency on the Engine therefore just building the Rules project is enough + $config = "PSV${PSVersion}${Configuration}" try { Push-Location $projectRoot/Rules Write-Progress "Building ScriptAnalyzer '$framework' version '${PSVersion}' configuration '${Configuration}'" - $buildOutput = dotnet build Rules.csproj --framework $frameworkName --configuration "${PSVersion}${Configuration}" + $buildOutput = dotnet build Rules.csproj --framework $frameworkName --configuration "${config}" if ( $LASTEXITCODE -ne 0 ) { throw "$buildOutput" } } catch { - Write-Error "Failure to build $framework ${PSVersion}${Configuration}" + Write-Error "Failure to build $framework ${config}" return } finally { @@ -225,8 +226,8 @@ function Build-ScriptAnalyzer Publish-File $itemsToCopyCommon $destinationDir $itemsToCopyBinaries = @( - "$projectRoot\Engine\bin\${PSVersion}${Configuration}\${frameworkName}\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll", - "$projectRoot\Rules\bin\${PSVersion}${Configuration}\${frameworkName}\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll" + "$projectRoot\Engine\bin\${config}\${frameworkName}\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll", + "$projectRoot\Rules\bin\${config}\${frameworkName}\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll" ) Publish-File $itemsToCopyBinaries $destinationDirBinaries @@ -234,7 +235,7 @@ function Build-ScriptAnalyzer # copy newtonsoft dll if net451 framework if ($Framework -eq "full") { - Copy-Item -path "$projectRoot\Rules\bin\${PSVersion}${Configuration}\${frameworkName}\Newtonsoft.Json.dll" -Destination $destinationDirBinaries + Copy-Item -path "$projectRoot\Rules\bin\${config}\${frameworkName}\Newtonsoft.Json.dll" -Destination $destinationDirBinaries } Pop-Location From b3018ea9410bdfd6391d18fb6c71f7fd031f90cc Mon Sep 17 00:00:00 2001 From: James Truher Date: Fri, 19 Oct 2018 14:07:24 -0700 Subject: [PATCH 15/16] reduce build matrix to accellerate CI testing --- appveyor.yml | 54 ++++++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 49ed21b69..c9d6f9509 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,15 +2,15 @@ environment: PSVersion: 5 BuildConfiguration: Release matrix: - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - PowerShellEdition: PowerShellCore - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - PowerShellEdition: WindowsPowerShell +# - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 +# PowerShellEdition: PowerShellCore +# - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 +# PowerShellEdition: WindowsPowerShell - APPVEYOR_BUILD_WORKER_IMAGE: WMF 4 PowerShellEdition: WindowsPowerShell PSVersion: 4 - - APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu - PowerShellEdition: PowerShellCore +# - APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu +# PowerShellEdition: PowerShellCore # cache Nuget packages and dotnet CLI cache cache: @@ -19,16 +19,16 @@ cache: install: - ps: if ($env:PowerShellEdition -eq 'WindowsPowerShell') { Import-Module .\tools\appveyor.psm1; Invoke-AppveyorInstall } - pwsh: if ($env:PowerShellEdition -eq 'PowerShellCore') { Import-Module .\tools\appveyor.psm1; Invoke-AppveyorInstall } - - ps: | - # Windows image still has version 6.0.0 of pwsh but 6.0.2 is required due to System.Management.Automation package https://github.com/appveyor/ci/issues/2230 - if ($env:PowerShellEdition -eq 'PowerShellCore' -and $PSVersionTable.PSVersion -lt [version]'6.0.2' -and $IsWindows) { - $msiPath = "$env:TEMP\PowerShell-6.0.2-win-x64.msi" - (New-Object Net.WebClient).DownloadFile('https://github.com/PowerShell/PowerShell/releases/download/v6.0.2/PowerShell-6.0.2-win-x64.msi', $msiPath) - Write-Verbose 'Installing pwsh 6.0.2' -Verbose - Start-Process 'msiexec.exe' -Wait -ArgumentList "/i $msiPath /quiet" - Remove-Item $msiPath - $env:Path = "$env:ProgramFiles\PowerShell\6.0.2;$env:Path" - } +# - ps: | +# # Windows image still has version 6.0.0 of pwsh but 6.0.2 is required due to System.Management.Automation package https://github.com/appveyor/ci/issues/2230 +# if ($env:PowerShellEdition -eq 'PowerShellCore' -and $PSVersionTable.PSVersion -lt [version]'6.0.2' -and $IsWindows) { +# $msiPath = "$env:TEMP\PowerShell-6.0.2-win-x64.msi" +# (New-Object Net.WebClient).DownloadFile('https://github.com/PowerShell/PowerShell/releases/download/v6.0.2/PowerShell-6.0.2-win-x64.msi', $msiPath) +# Write-Verbose 'Installing pwsh 6.0.2' -Verbose +# Start-Process 'msiexec.exe' -Wait -ArgumentList "/i $msiPath /quiet" +# Remove-Item $msiPath +# $env:Path = "$env:ProgramFiles\PowerShell\6.0.2;$env:Path" +# } build_script: - ps: | @@ -40,23 +40,23 @@ build_script: } ./build.ps1 -Configuration "$env:BuildConfiguration" -PSVersion "$env:PSVersion" -Framework full } - - pwsh: | - if ($env:PowerShellEdition -eq 'PowerShellCore') { - Set-Location $env:APPVEYOR_BUILD_FOLDER - ./build.ps1 -Documentation - ./build.ps1 -Configuration "$env:BuildConfiguration" -PSVersion 5 -Framework core - } +# - pwsh: | +# if ($env:PowerShellEdition -eq 'PowerShellCore') { +# Set-Location $env:APPVEYOR_BUILD_FOLDER +# ./build.ps1 -Documentation +# ./build.ps1 -Configuration "$env:BuildConfiguration" -PSVersion 5 -Framework core +# } test_script: - ps: | if ($env:PowerShellEdition -eq 'WindowsPowerShell') { Invoke-AppveyorTest -CheckoutPath $env:APPVEYOR_BUILD_FOLDER } - - pwsh: | - if ($env:PowerShellEdition -eq 'PowerShellCore') { - Import-Module .\tools\appveyor.psm1 # Appveyor does not persist pwsh sessions like it does for ps - Invoke-AppveyorTest -CheckoutPath $env:APPVEYOR_BUILD_FOLDER - } +# - pwsh: | +# if ($env:PowerShellEdition -eq 'PowerShellCore') { +# Import-Module .\tools\appveyor.psm1 # Appveyor does not persist pwsh sessions like it does for ps +# Invoke-AppveyorTest -CheckoutPath $env:APPVEYOR_BUILD_FOLDER +# } # Upload the project along with test results as a zip archive on_finish: From cb95da1d0ba09deedad0e6d146ac695c0e09511e Mon Sep 17 00:00:00 2001 From: James Truher Date: Fri, 19 Oct 2018 14:19:54 -0700 Subject: [PATCH 16/16] Revert "reduce build matrix to accellerate CI testing" This reverts commit b3018ea9410bdfd6391d18fb6c71f7fd031f90cc. --- appveyor.yml | 54 ++++++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index c9d6f9509..49ed21b69 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,15 +2,15 @@ environment: PSVersion: 5 BuildConfiguration: Release matrix: -# - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 -# PowerShellEdition: PowerShellCore -# - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 -# PowerShellEdition: WindowsPowerShell + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + PowerShellEdition: PowerShellCore + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + PowerShellEdition: WindowsPowerShell - APPVEYOR_BUILD_WORKER_IMAGE: WMF 4 PowerShellEdition: WindowsPowerShell PSVersion: 4 -# - APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu -# PowerShellEdition: PowerShellCore + - APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu + PowerShellEdition: PowerShellCore # cache Nuget packages and dotnet CLI cache cache: @@ -19,16 +19,16 @@ cache: install: - ps: if ($env:PowerShellEdition -eq 'WindowsPowerShell') { Import-Module .\tools\appveyor.psm1; Invoke-AppveyorInstall } - pwsh: if ($env:PowerShellEdition -eq 'PowerShellCore') { Import-Module .\tools\appveyor.psm1; Invoke-AppveyorInstall } -# - ps: | -# # Windows image still has version 6.0.0 of pwsh but 6.0.2 is required due to System.Management.Automation package https://github.com/appveyor/ci/issues/2230 -# if ($env:PowerShellEdition -eq 'PowerShellCore' -and $PSVersionTable.PSVersion -lt [version]'6.0.2' -and $IsWindows) { -# $msiPath = "$env:TEMP\PowerShell-6.0.2-win-x64.msi" -# (New-Object Net.WebClient).DownloadFile('https://github.com/PowerShell/PowerShell/releases/download/v6.0.2/PowerShell-6.0.2-win-x64.msi', $msiPath) -# Write-Verbose 'Installing pwsh 6.0.2' -Verbose -# Start-Process 'msiexec.exe' -Wait -ArgumentList "/i $msiPath /quiet" -# Remove-Item $msiPath -# $env:Path = "$env:ProgramFiles\PowerShell\6.0.2;$env:Path" -# } + - ps: | + # Windows image still has version 6.0.0 of pwsh but 6.0.2 is required due to System.Management.Automation package https://github.com/appveyor/ci/issues/2230 + if ($env:PowerShellEdition -eq 'PowerShellCore' -and $PSVersionTable.PSVersion -lt [version]'6.0.2' -and $IsWindows) { + $msiPath = "$env:TEMP\PowerShell-6.0.2-win-x64.msi" + (New-Object Net.WebClient).DownloadFile('https://github.com/PowerShell/PowerShell/releases/download/v6.0.2/PowerShell-6.0.2-win-x64.msi', $msiPath) + Write-Verbose 'Installing pwsh 6.0.2' -Verbose + Start-Process 'msiexec.exe' -Wait -ArgumentList "/i $msiPath /quiet" + Remove-Item $msiPath + $env:Path = "$env:ProgramFiles\PowerShell\6.0.2;$env:Path" + } build_script: - ps: | @@ -40,23 +40,23 @@ build_script: } ./build.ps1 -Configuration "$env:BuildConfiguration" -PSVersion "$env:PSVersion" -Framework full } -# - pwsh: | -# if ($env:PowerShellEdition -eq 'PowerShellCore') { -# Set-Location $env:APPVEYOR_BUILD_FOLDER -# ./build.ps1 -Documentation -# ./build.ps1 -Configuration "$env:BuildConfiguration" -PSVersion 5 -Framework core -# } + - pwsh: | + if ($env:PowerShellEdition -eq 'PowerShellCore') { + Set-Location $env:APPVEYOR_BUILD_FOLDER + ./build.ps1 -Documentation + ./build.ps1 -Configuration "$env:BuildConfiguration" -PSVersion 5 -Framework core + } test_script: - ps: | if ($env:PowerShellEdition -eq 'WindowsPowerShell') { Invoke-AppveyorTest -CheckoutPath $env:APPVEYOR_BUILD_FOLDER } -# - pwsh: | -# if ($env:PowerShellEdition -eq 'PowerShellCore') { -# Import-Module .\tools\appveyor.psm1 # Appveyor does not persist pwsh sessions like it does for ps -# Invoke-AppveyorTest -CheckoutPath $env:APPVEYOR_BUILD_FOLDER -# } + - pwsh: | + if ($env:PowerShellEdition -eq 'PowerShellCore') { + Import-Module .\tools\appveyor.psm1 # Appveyor does not persist pwsh sessions like it does for ps + Invoke-AppveyorTest -CheckoutPath $env:APPVEYOR_BUILD_FOLDER + } # Upload the project along with test results as a zip archive on_finish: