Integrating PSScriptAnalyzer in an Appveyor Continuous Integration pipeline

Many of us who are writing PowerShell code are using the free (and awesome) Appveyor service for Continuous Integration (especially for personal projects). And most of us use this to run Pester tests. Automated testing is great, it allows to set a certain standard of code quality without slowing down code delivery. But, this is just checking that the code behaves as we intended to.

What about code consistency, style, readability and following best practices ?

This is where a static code analysis tool like PSScriptAnalyzer comes in. Even though PSScriptAnalyzer is a perfect fit in a PowerShell “build” process, searching the web for “integrating PSScriptAnalyzer and Appveyor” doesn’t yield very helpful results. So here is the solution I came up with :

version: 1.0.{build}

os: WMF 5

# Skip on updates to the readme
skip_commits:
  message: /readme*/
  
install:
  - ps: Install-PackageProvider -Name NuGet -Force
  - ps: Install-Module PsScriptAnalyzer -Force
  
build: false

test_script:
  - ps: |
      Add-AppveyorTest -Name "PsScriptAnalyzer" -Outcome Running
      $Results = Invoke-ScriptAnalyzer -Path $pwd -Recurse -Severity Error -ErrorAction SilentlyContinue
      If ($Results) {
        $ResultString = $Results | Out-String
        Write-Warning $ResultString
        Add-AppveyorMessage -Message "PSScriptAnalyzer output contained one or more result(s) with 'Error' severity.`
        Check the 'Tests' tab of this build for more details." -Category Error
        Update-AppveyorTest -Name "PsScriptAnalyzer" -Outcome Failed -ErrorMessage $ResultString
        
        # Failing the build
        Throw "Build failed"
      }
      Else {
        Update-AppveyorTest -Name "PsScriptAnalyzer" -Outcome Passed
      }

This the content of my appveyor.yml file, which is the file from which Appveyor gets the build configuration.

Line 3 : This indicates from which VM template the build agent will be deployed. As its name indicates, this allows to have a build agent running in a VM with PowerShell version 5. If you believe only what you can see, add $PSVersionTable in the appveyor.yml and check the result in the build console. PowerShell 5 means we can easily add PowerShell scripts, modules and DSC resources to our build agent from the PowerShell Gallery using PackageManagement.

Line 10-11 : This is exactly what we do here. But first, because the PowerShell Gallery relies on NuGet, we need to install the NuGet provider. Then, we can install any PowerShell module we want from the PowerShell Gallery, PsScriptAnalyzer in this case. We didn’t specify the repository because the PowerShell Gallery is the default one.

Line 13 : This refers specifically to MSBuild and we don’t need or want MSBuild for a PowerShell project.

Line 15-End : This is where all the PSScriptAnalyzer stuff goes. So from an Appveyor point of view, this will be a test. Even though static code analysis is not testing, it kinda makes sense : we are assessing the code against a set of rules which represent a certain standard and we want a “Pass” or a “Fail” depending on whether the code meets the standard or not.

Line 16 : In YAML, the pipe character “|” allows values to span multiple lines. This is very convenient for code blocks, like here. That way, we don’t need to add “- ps:” at the beginning of each line.

Line 17 : Appveyor doesn’t have a direct integration with PSScriptAnalyzer like it has for some testing frameworks (NUnit, MSTest, etc…) but it’s OK. The Appveyor worker (the actual build agent) provides a REST API and even a few PowerShell cmdlets leveraging this API. One of these cmdlets is Add-AppveyorTest. Using this cmdlet, we are adding a new test, giving it a name and telling the build agent that the test is in the “Running” state.

Line 18 : We run PSScriptAnalyzer against all the files in the current directory, recursively. We specify the “Error” severity to output only the violations of level “Error“, because we don’t want a violation of severity “Information” or even “Warning” to make the test fail. We store the result in a variable for later use.

Line 20 : If there are any “errors” from PSScriptAnalyzer perspective, we want to display them as a message in the build console and in the error message of the “test”. That’s why we need to convert the output object(s) from PSScriptAnalyzer to a string.

Line 21 : Writing the violation(s) to the build console. We could use Write-Host or Write-Output as well but as we’ll see in a later screenshot, the warning stream makes it stand out more visibly.

Line 22 : This Appveyor-specific cmdlet adds a message to the build’s “Messages” tab. Specifying “Error” for the category just displays the message with a touch of red on its left :

Appveyor Message fail
 
Line 24 : Update-AppveyorTest is another cmdlet leveraging the Appveyor build worker API. Here, we are using it to update the status of our existing test and add an error message to it. This message is PSScriptAnalyzer output converted to a string, so we can check the test message to see exactly what the problem is :

Appveyor Test fail
 

Line 27 : We need to use “Throw” to explicitly fail the build. Otherwise, the build is considered as succeeded, even if the “test” fails.

Line 30 : If PSScriptAnalyzer didn’t output anything, meaning if there were no violation of the “Error” severity in any file scanned by PSScriptAnalyzer, we considered that our project passes the test. Again, we use Update-AppveyorTest but this time, we tell it that the outcome of the “test” is a pass.

Now, let’s see how this looks like when we run a build :

Appveyor Build success
 
Not much output, because all is well. Also, the test is green :

Appveyor Test Success
 
Do you like watching “Fail” videos on Youtube ? If yes, you are probably dying to see my build fail, right ? So, here we go :

Appveyor Build fail
 
Wow, the yellow background of the warning stream is not elegant but it sure stands out !

Also, if you want to see the “Passing” Appveyor badge on the GitHub repository, head over THERE.

This is it.
PSScriptAnalyzer is an important tool that any PowerShell scripter should use. Appveyor is awesome, so combining both of these tools is pretty powerful.

One thought on “Integrating PSScriptAnalyzer in an Appveyor Continuous Integration pipeline”

Leave a Reply

Your email address will not be published. Required fields are marked *