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:
Then we need to create a new profile and select (in my case) the folder option:
After that, we will have the a new pubxml file in the solution:
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.