Having a fully automated build and release process is, in my opinion, one of the best things you can do as a development team. We’ve spent the last 2 years moving to a fully automated build and release process and it has had an enormous impact on the way we develop and, more importantly, release software. Releasing has gone from something we do on average quarterly to something we can do daily if required. I shudder when I think of doing a manual release now – the time taken, the mistakes when setting up the release (manual backups, spelling errors or wrong values in configs, not remembering to copy all the necessary files or folders, etc…).

Here I want to demonstrate one fantastic benefit of having an automated release process – knowing exactly what you’ve deployed, down to every single line of code.

Here’s a screenshot of an Octopus release, which shows exactly what commit this code is running from:

We can see that this release is currently on our test environment by the green tick next to “Test” under the “Lifecycle” section. The bit in the red box is what we’re really interested in here. This tells this release is running the code that was checked in with commit id “ff83e86…”. We can take this id and link it back to our VCS (we currently use BitBucket, a VCS based on Git). Here is the exact source code now running in test:

releasing-blog-5

So how do we include the commit in the release? Octopus uses NuGet packages as its deployment mechanism. NuGet packages can contain release notes, and it is these release notes that get displayed in the red box in the image above. We can include a release notes file in the project, use TeamCity to update it with the commit using a straightforward PowerShell script, and include it when building the NuGet package.

Setting up the files

There are two files we need: the release notes file and the PowerShell script to update the release notes file.

releasing-blog-2

Note that here I’ve included them at the solution level as there’s only one project we will deploy, however these can be put at a project level if required.

Both the files are simple affairs. Here’s what each file contains:

ReleaseNotes.txt

Commit: %commitId%

UpdateReleaseNotes.ps1

Param(
[string]$commitId
)
(Get-Content .\ReleaseNotes.txt) | Foreach-Object {$_ -replace '%commitId%', $commitId} | out-file .\ReleaseNotes.txt

The release notes contains a placeholder for the commit id. The PowerShell script opens the release notes file, replaces the placeholder with a passed in parameter and saves it. This parameter will come from TeamCity.

Running the PowerShell script

Next up we need to run this script from our build server, passing in the commit id that triggered the build. In the build configuration, add a build step to run a PowerShell script:

releasing-blog-3
(Note to self: update TeamCity!)

Here we are running the PowerShell script and, in the Script Arguments, passing in one of TeamCitys built-in parameters – the commit id from our VCS that will be used for the build.

Adding the release notes to the NuGet package

Now all that is left is to add the ReleaseNotes.txt to the NuGet package that is built by OctoPack. OctoPack has a number of parameters it accepts, one of which is the location of a release notes file:

releasing-blog-4

And we’re done! Now, whenever we deploy the release using Octopus, we will see the commit that the release was built from.

Edit: Erik Eckhard has a great way of achieving the same result without adding a file to your solution in the comments below.

SHARE IT:

Commenting area

  1. Erik Eckhardt 13th April 2016 at 12:41 am · · Reply

    You don’t have to create a solution or project file. All you need is to create the file in the temp build directory. For example, instead of outputting to “.\ReleaseNotes.txt”, you can output to "%system.teamcity.build.tempDir%\releasenotesfile_%teamcity.build.id%.txt".

    Then, in your build step, use the parameter: /p:OctoPackReleaseNotesFile=%system.teamcity.build.tempDir%\releasenotesfile_%teamcity.build.id%.txt

    However, doing all this means that each package you deploy will have its own copy of the build steps, and the release itself won’t have the release notes (this is a drawback because the Overview page only shows the release-level release notes, not any package-level release notes, at least with more than one package as I can’t confirm what happens with one package).

    Furthermore, see Generating a project change log with TeamCity and Powershell for a script that makes a much grander set of release notes, including all commits since the last build (or release? not sure). I souped it up to include the commit sha, with a link back to the source control web site’s commit page. I also plan to update the script to add links to anything that looks like a case reference back to my project management software. And finally, I plan to use the committer’s user name when TeamCity hasn’t yet been told which TeamCity user that committer actually is (do this in your user profile).

    Last, if you accept building a new release every time you build, then add a TeamCity step, “OctopusDeploy: create release”, and in the additional command line arguments, put

    --releasenotesfile="%system.teamcity.build.tempDir%\releasenotesfile_%teamcity.build.id%.txt"

    This makes the Overview page in Octopus awesome!

    • Edward Ridge
      Edward Ridge 28th April 2016 at 10:21 am · · Reply

      Thanks Erik, I really like the temp file idea, very clean.

      I’ve toyed with the idea of generating a changelog of commits between releases, but it feels to me like it would have to be done at deploy time rather than build time – you could have multiple builds that get deployed (e.g. to test environments) between actual releases to production, and a change log would need to take into account all of them. It’s something I’ll try to follow up with a blog on.

      Thanks for the comment!

Leave a Reply

You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>