Quantcast
Channel: Randy Riness @ SPSCC aggregator
Viewing all articles
Browse latest Browse all 3015

MSDN Blogs: PowerShell module with continuous integration, static analysis and automatic publish to gallery

$
0
0

 

Recently our team released the Reporting Services PowerShell Tools as a project to collaborate with the community, we had a lot more feedback and participation that we ever though and we decided to push it a little further and publish it to the PowerShell Gallery.

We aren’t by any means PowerShell experts and when we published the module we found that we should have run the PSSScriptAnalyzer , so we run it and fixed but this will not scale as a manual task and also I would like to automate the publishing to the gallery so is in sync with the code in the repo.

Investigating around fin this great starting point in the http://ramblingcookiemonster.github.io/GitHub-Pester-AppVeyor/ blog post, it describes how to use AppVeyor for running unit tests with Pester, however I wanted something slightly different, my main goals are:

  1. Provide static analysis using PSSScriptAnalyzer and show the results to the users submiting the pull request
  2. After the PR is merged into main publish automatically to the PowerShell gallery

So started by onboarding the Github repo to AppVeyor and created a New Project based on our repo, the procedure is pretty straightforward and AppVeyor has plenty of documentation so I’m not including any detailed instructions.

Onboarding the ScriptAnalyzer

First thing is to add the appveyor.yml file in our github repo, that one was pretty interesting as my initials attempts failed , basically I wanted to install the PSScriptAnalyzer module but it failed with  

Exception calling “ShouldContinue” with “2” argument(s): “The method or operation is not implemented.”

At C:Program FilesWindowsPowerShellModulesPowerShellGet1.0.0.1PSModule.psm1:5908 char:8

+ if($Force -or $PSCmdlet.ShouldContinue($shouldContinueQueryMessag …

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException

+ FullyQualifiedErrorId : NotImplementedException

Install-Module : NuGet provider is required to interact with NuGet-based repositories. Please ensure that ‘2.8.5.201’ or newer version of NuGet provider is installed.

At line:1 char:1

+ Install-Module -Name PSScriptAnalyzer

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ CategoryInfo : InvalidOperation: (:) [Install-Module], InvalidOperationException

+ FullyQualifiedErrorId : CouldNotInstallNuGetProvider,Install-Module

Command executed with exception: NuGet provider is required to interact with NuGet-based repositories. Please ensure that ‘2.8.5.201’ or newer version of NuGet provider is installed.

 

The solution is to install first the nuget package provider, the install section end up being

install:
ps:Install-PackageProvider -Name NuGet -Force
ps:Install-Module -Name PSScriptAnalyzer -Force

 

The next step was to produce a XML results file, I spend some time figuring out what would be the simplest schema and selected junit and then used some magic string manipulation to get the results of the script analyzer into the testresults file  

# Execute the script analyzer

$results = Invoke-ScriptAnalyzer Path .functions Recurse | where severity -eq “Error”

# Format the results

$header = “<testsuite tests=`”$($results.Count)`”>”

$body = $results | ForEach-Object {“<testcase classname=`”analyzer`” name=`”$($_.RuleName)`”><failure type=`”$($_.ScriptName)`”>$($_.Message)</failure></testcase>”}

$footer = “</testsuite>”

$header + $body +$footer | out-file .TestsResults.xml

# Upload results

$wc = New-Object ‘System.Net.WebClient’

$wc.UploadFile(“https://ci.appveyor.com/api/testresults/junit/$($env:APPVEYOR_JOB_ID), (Resolve-Path .TestsResults.xml))

# Fail if there are issues

if($results.Count -gt 0){throw “ScriptAnalyzer found $($results.Count) issues”}

 

That give me this nice UI when the script analyzer find any issue

clip_image001

You can check the entire script in our repo appveyor.yml

Publishing to the PowerShell Gallery

I want to control the publishing process, I don’t want every single commit to master to publish a new version of the module to the PowerShell Gallery, so I decided to use git tags in order to request a publish, basically when a new tag is added the continuous integration process will run the tests and if they pass use the tag label as the version to publish in the gallery, the general workflow is

  1. Update the module manifest (.psd1) with the tag version
  2. Publish to the PowerShell Gallery
  3. If the publish is successful commit back to the repo the new module manifest (.psd1)

Interacting with the PowerShell gallery is based on a secret key they provide to use it in the Publish-Module cmdlet, in order to be used in your AppVeyor script you should encrypt it, the detailed instructions are available here https://www.appveyor.com/docs/build-configuration/#secure-variables

Also here are the instructions on how to interact with git from the AppVeyor script https://www.appveyor.com/docs/how-to/git-push/

One issue that I hit was that my git commands from powershell where treating the git console messages as errors, searching around found this workaround and implemented in the AppVeyor script, the deploy section looks like this.

 

# Deploy to Powershell Gallery only where there is a tag which will have the version number

$deploy = ($env:APPVEYOR_REPO_TAG -eq $true)

if ($deploy)

{

   git checkout jtarquino/autopublish

   Write-Host “Starting Deployment tag $env:APPVEYOR_REPO_TAG_NAME

   $moduleName = “ReportingServicesTools”

   $currentVersion = (Import-PowerShellDataFile .$moduleName.psd1).ModuleVersion

   ((Get-Content .ReportingServicesTools.psd1).replace(“ModuleVersion = ‘$($currentVersion)‘”, “ModuleVersion = ‘$($env:APPVEYOR_REPO_TAG_NAME)‘”)) | Set-Content .$moduleName.psd1

   Publish-Module Path . NuGetApiKey $env:galleryPublishingKey

   git config global core.safecrlf false

   git config global credential.helper store

   Add-Content $env:USERPROFILE.git-credentials” “https://$($env:access_token):x-oauth-basic@github.com`n

   git config global user.email “yourEmail@outlook.com”

   git config global user.name “Your Name”

   git add ReportingServicesTools.psd1

   git commit m “Automatic Version Update from CI”

   git push

}

 

For some unexplainable reason I wasn’t able to use the Update-ModuleManifest cmdlet so I did the manual replacing of the module version.

If you are interested in the entire deployment file it is available here in our repo appveyor.yml


Viewing all articles
Browse latest Browse all 3015

Trending Articles