Continuous integration with Atlassian Bamboo

The continuous integration is a frequent theme in the application development, expecially in the projects with many developers involved that work on differents components of the application.

Just because the developers works on different features, a process that integrate the new code frequently in project and verify that all the dependencies of that are working yet is recommended.

A practice to integrate daily the new code in the shared project repository avoid problems like integration hell, where a developer has troubles to integrate code of another developer, that worked isolated for a long period.

Again, a process that manage this integration allow us to introduce in this phase the automatic tests and discover eventually regressions in the code modified.

There are different products to manage the continuous integration process and one of those is Bamboo, a product owned by Atlassian and in this post I want to talk about the configuration of the continuous integration on a .NET project with a bunch of tests implemented with NUnit.

Server configuration

Before to proceed with a project configuration we need to take care about the executables that Bamboo will needs to execute the process.

In my case I need the MSBuild and NUnit executables and I can configure them in the server capabilities section of the Bamboo configuration:

configuration7

In my case I use the MSBuild installed with Visual Studio, but you can download that from this url.

The NUnit console is the executable used for the tests execution and you can find it here.

Plan

When I need to configure a new project in Bamboo, I need to do a new plan.

A plan is composed by one or more stages; for example in my case I have a build stage, a test stage and a deploy stage.

In the stages I will create the jobs that will do some stuff.

In the plan configuration I need to take care about the referenced repository, that is the repository where Bamboo will load the source code:

configuration5

In my case I have specified the url of a GitHub repository.

Another thing that I can do is define a trigger for the plan, that is an event after which the plan execution will be fired.

I define a branch that Bamboo will polling for new changes:

configuration6

Every time a new commit will be pushed on the master branch, the plan will be executed.

Build

Now I configure the Solution Build job in the Build stage; every job is composed by one or more tasks and in this case I have three tasks.

The first one is the Source Code Checkout, that is the phase where Bamboo get the source code from the repository and copy all the content in his working directory (locally on the server where is installed).

The second one is a Script configuration, in my case I need to restore some nuget packages before to build the project; I do that by writing a script that launch the nuget executable with the option restore:

configuration8

You can find the nuget executable download here.

The last step is the MSBuild task and we use the executable configured above:

configuration9

Another thing that we can do in the job configuration is define an artifact, thus the output of the job will be available for the next jobs:

configuration10

In this way, we speedup the next job because it won’t need to checkout the repository again.

Test

The test job is more simple, because it has the source code already available and it has only the test runner:

configuration11

Again here we use the other executable configured above and we have only to specify the dll of the test project.

We don’t forget to configure the artifact for the job and use that produced in the previous job:

configuration12

Deploy

The last stage is the deploy.

To have a clean situation I do again a Source Code Checkout and than I  execute a powershell script:

configuration13

The script was explained in the previous post and deal with some stuff like build, apply a version to the assembly and copy the result in a shared directory.

That’s all, when you’ll run the plan, the result (if the project is ok :))) will looks like this:

configuration4

 

Advertisements
Continuous integration with Atlassian Bamboo

Deploy a .NET project with powershell and git

In this topic I want to share my experience in writing a powershell script to compile and publish a .NET project.

I use Git and a GitHub repository, so in my mind the script should restore the nuget packages, build the project with MSBuild, take the last tag (version) from the master branch of the GitHub repository and apply (if valid) the version found in the tag in the project assembly.

Finally, it have to produce a folder with the deployment package.

So, let’s start with the steps to implement this script.

Project configuration

Before to write the powershell script, I need to setup the configuration for the project deploy.

So right click on the project (in my case a web project) and select Publish, it will appear this window:

configuration1

Then we need to create a new profile and select (in my case) the folder option:

configuration2

After that, we will have the a new pubxml file in the solution:

configuration3

We will use this file in our powershell script.

Source code versioning

Now it’s the time to implement the script and the first step that I want to do is apply a version to the assembly and use it in the name of the folder where the application will be published.

My repository provider is GitHub and everytime I release a version on the master branch, I apply a tag on the commit with the release number, like 0.2.0.

So my script have to be able to get the last tag from the master branch and apply it to the assembly.

We have some options to apply the version on a .NET application, the most standard way is use the AssemblyInfo.cs file, where we could have attributes like AssemblyVersion, AssemblyFileVersion, and also AssemblyInformationalVersion.

If the first two attributes need to have a version in standard format, the last attribute leave us the freedom to use a custom versioning, for example if we want to include in the versioning the current date, or the the name of the git branch and so on.

For this reason I’ll update the AssemblyInformationalVersion.

So, first of all I need to retrieve the version from the tag applied on the GitHub repository:

$version = $(git describe --abbrev=0 --tag)

By executing this git command from the solution folder, I can retrieve the last tag applied and use it as the new version, or part of it.

Now I can check if the version has a specific format, for example I want that the version is composed by two or three numbers:


$versionRegex1 = "\d+.\d+.\d+"
$versionData1 = [regex]::matches($version,$versionRegex1)
$versionRegex2 = "\d+.\d+"
$versionData2 = [regex]::matches($version,$versionRegex2)

if ($versionData1.Count -eq 0 -and $versionData2.Count -eq 0) { Throw "Version " + $version + " has a bad format" }

If these checks are satisfied, I can apply the version and I search the AssemblyVersion.cs files in the solution:


$files = Get-ChildItem $sourceDirectory -recurse -include "*Properties*" |
?{ $_.PSIsContainer } |
foreach { Get-ChildItem -Path $_.FullName -Recurse -include AssemblyInfo.* }

If I have found the files, I can apply the new version:


if ($files) {
Write-Host "Updating version" $version
foreach ($file in $files) {
$filecontent = Get-Content($file)
attrib $file -r
$informationalVersion = [regex]::matches($filecontent,"AssemblyInformationalVersion\(""$version""\)")

if ($informationalVersion.Count -eq 0) {
Write-Host "Version " $version " applied to " $file
$filecontent -replace "AssemblyInformationalVersion\(.*\)", "AssemblyInformationalVersion(""$version"")" | Out-File $file
}

}
}

I check that the attribute has not the new version value yet, otherwise nothing needs to do.

The hardest step is completed, now I can build and deploy my project.

Build and deploy

I order to build the project I need MSBuild 15, that in my case is already installed with Visual Studio 2017.

But, if you haven’t, you can download it from the Microsoft web site and this link.

If you have some nuget packages in the project, in order to restore the packages before to build you need the nuget executable as well, and you can download it from this link.

Now we are ready to write the code to build and deploy the project:


$msbuild = "C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin\msbuild.exe"
$solutionFolder = $PSScriptRoot + "..\..\"
$solutionFile = $solutionFolder + "\EFContextMock.sln"
$projectFile = $solutionFolder + "\WebApp\WebApp.csproj"
$nuget = $solutionFolder + "\nuget\nuget.exe"
$version = $(git describe --abbrev=0 --tag)
$publishUrl = "c:\temp\EFContextMock\" + $version

SetAssemblyInfo $solutionFolder $version

Write-Host "Restore packages"

& $nuget restore $solutionFile

if ($LastExitCode -ne 0){
$exitCode=$LastExitCode
Write-Error "Build failed!"
exit $exitCode
}
else{
Write-Host "Build succeeded"
}

Write-Host "Building"

& $msbuild $projectFile /p:DeployOnBuild=true /p:PublishProfile=Publish.pubxml /p:PublishUrl=$publishUrl

if ($LastExitCode -ne 0){
$exitCode=$LastExitCode
Write-Error "Build failed!"
exit $exitCode
}
else{
Write-Host "Build succeeded"
}

After some variables setup I assign the version with the code discussed above and I restore the nuget packages.

The msbuild command uses the pubxml file created in the first step; one of the parameters of the command is the PublishUrl, that in my case is a local path.

You can find the complete powershell script here.

Deploy a .NET project with powershell and git