Recently I decided I would kill two birds with one stone, I figured I would learn a bit of Powershell and setup some build scripts for our project. I have been wanting to play around with Powershell for the longest time but could never really either find the time or the reason to play with it. So I figured that setting up build scripts would be a perfect use of my time (I know I could have choose any other build language/framework but PSake meet my need).
In this post I will walk you though how to setup a build from scratch. I will warn that because I am a COMPLETE NOOB with powershell it is very likely that my powershell code is less than optimal but it meets my needs.
In my script we are going to accomplish 3 things:
- Setup a PSake Task to perform a clean on our solution
- Setup a PSake Task to perform a build on our solution
- Setup a PSake Task to run Tests in our solution
Before you continue I would suggest you download PSake and read the Readme.markdown script because this will tell you how to setup PSake to be run via Poweshell. Once you have read the markdown file you can continue.
Creating your shell ps1 file.
You will want to create a build file to put the following code into. Call it build.ps1 for our purposes.
Adding the Clean Task
The raw PSake ‘Task’ for the clean.
task Clean {
Invoke-Clean "My Solution" "..\Subfolder\MySolution.sln"
}
As you can see from the task above this is just a pass through call into another method called Invoke-Clean. I have done this because over time I expect to build out multiple build scripts, one per application, and I don’t want to duplicate the code which does a clean in each script.
Here is the actual Invoke-Clean function
function Invoke-Clean
{ [CmdletBinding()]
param(
[Parameter(Position=0,Mandatory=1)] [string]$BuildName = $null,
[Parameter(Position=1,Mandatory=1)] [string]$SolutionFileWithPath = $null
)
Write-Host "Running Clean for" $BuildName "on Solution @" $SolutionFileWithPath
C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe /verbosity:m /t:Clean $SolutionFileWithPath
}
The code above is doing 2 things.
- I an writing to the host (aka console) that I am running a clean for the given build
- I am directly referencing the msbuild.exe from the folder. Now with PSake you don’t always have to do this because it just ‘knows’ where msbuild is located. However, I am building a silverlight app and the version of msbuild that PSake was finding was wrong and this was my solution for this.
Adding the Compile Tasks
When doing a compile we are going to simply call out to MSBuild and allow it to do its thing. Below is the PSake task for doing a compile
task Compile -depends Clean {
Invoke-Build "My solution" "..\Subfolder\MySolution.sln"
}
Again the task above is just wrapper call around the Invoke-Build function. It is the Invoke-Build function which is doing all the heavy lifting. Below is our function.
It is important to point out that our Compile task depends on the Clean task. This means that the Clean task will be run prior to the actual compile.
function Invoke-Build
{
[CmdletBinding()]
param(
[Parameter(Position=0,Mandatory=1)] [string]$BuildName = $null,
[Parameter(Position=1,Mandatory=1)] [string]$SolutionFileWithPath = $null
)
Write-Host "Running Build for" $BuildName "on Solution @" $SolutionFileWithPath
C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe /verbosity:m $SolutionFileWithPath
}
The Invoke-Build above is also calling to a specific version of the MSBuild but this time rather than doing a clean it is doing a compile. Of course if you want to perform more actions via MSBuild you can find the full list of command line switches on MSDN.
Adding the Test Tasks
The last task I want to build is the testing task. Because our team is using MSTest the code below is for this. if you are using NUnit or any other testing framework the code should be close to this but of course calling the correct runner exe.
task Test -depends Compile, Clean {
Invoke-MSTest "MyTestDll.dll" "..\Subfolder\UnitTests\bin\Debug\MyUnitTests.dll" "MyUnitTests.dll.trx"
}
Our Test task above is pretty simple. We are passing in 3 values, Display name, the dll to test and because this is MSTest I am providing the name of the output file I want generated with the test results.
Below is the implementation for Invoke-MSTest.
function Invoke-MSTest
{
[CmdletBinding()]
param(
[Parameter(Position=0,Mandatory=1)] [string]$TestName = $null,
[Parameter(Position=1,Mandatory=1)] [string]$TestDll = $null,
[Parameter(Position=2,Mandatory=1)] [string]$ResultTrx = $null
)
Write-Host "Running Tests for" $TestName "Located @" $TestDll " Output to:" $ResultTrx
if ( Test-Path $ResultTrx )
{
Write-Host "Found" $ResultTrx "it will be deleted prior to running the test"
Remove-Item $ResultTrx
}
$result = mstest /testcontainer:$TestDll /resultsfile:$ResultTrx
foreach( $line in $result )
{
if ( $line -ne $null )
{
if ( $line.StartsWith("Passed") -ne $true )
{
$line
}
}
}
}
Looking at the Invoke-MSTest function above you can see I am doing more than simply making a call out to MSTest. I am doing 2 specific things.
- I am checking to see if there is an existing output file and if there is I am deleting it
- I am only outputting the failure test results to the console. This allows me to remove all the extra noise of passed tests.
As you can see from above getting up and running w/ PSake is not that hard and does not take much effort.
Till next time,
Posted
02-04-2012 10:16 AM
by
Derik Whittaker