Versioning in Octopus Deploy (Part I)


tree-338211_640
Versioning – NuGet and Octopus Deploy will force this issue of versioning on your projects and it’s in your best interest to give it some thought. Within Octopus, your releases are versioned as well as your NuGet packages however packages are versioned externally of Octopus, so some prudence will pay dividends down the road. I’ve found that one of the biggest hurdles with versioning is where to begin. NuGet and Microsoft have differences in their versioning system and there’s no apparent clear-cut path on what to do. In this deep dive, I hope to explain what I’ve found on my journey into the rabbit hole and shed a little light on the subject.
For years, I never gave versioning a second thought because I had always assumed systems had evolved some sort of logical consistency and while I may not be able to decipher each digit, there was always some meaning behind everything. That assumption was clearly inaccurate. When I began looking for some help on the matter, I didn’t realize versioning was a messy buffet of ideas and people trying to tie information together as a cohesive identifer. To be fair, versioning can be application and system dependent and depending on the level of integration you want and automating versioning makes it all the more complicated. I thought it would be a simple if not a a mature topic after all this time, but I could not have been more wrong. To cover this topic of versioning, I’m going to split things up into two parts: Versioning Releases in Octopus Deploy and Versioning NuGet Packages. Let’s start addressing versioning releases in Octopus.
Versioning Releases in Octopus Deploy
In Octopus Deploy, there’s two versioning mechanisms going on: one for your release and the other for which version of your NuGet package(s) to deploy as part of your project. In this article, we’re covering both but note that NuGet package versioning is commonly done outside of Octopus Deploy. Usually versioning occurs within the NuSpec file, but the OctoPack defaults to using the AssemblyVersion in the AssemblyInfo.cs file within your project.
dashboard-release-versions
For releases, you can version them to use your NuGet package version or you can create your own version template (aka variable template versioning). The image on the left is an example of my dashboard project “OctopusDemo Web” which uses NuGet versioning, and you can see the three latest deployments to my environments. It should be straightforward and simple to follow. The numbers indicate the version of the deployment; in this case my releases use the NuGet package version that was deployed in said release. Whichever you mechanism you choose regarding your releases, there’s really no advantages or disadvantages that tilt the scale as to which is more preferable, but there are edge cases where one is better suited than the other.

release-versioning-settings-versiontemplate
Variable template versioning

As you can see, you can customize your release versioning mechanism within Octopus. The image on the right shows that by default Octopus uses it’s own system variables (denoted by the #{ }) for templating your release version. You can find this menu in your “Settings” tab within your project. There are other system variables that are available, but these default variables make sense as is. By using this release versioning from the variable template, when you create a new release, it will apply the current values of the system variables. In this case, if you created a new project, the first release version would be 0.0.1.  The subsequent release would be 0.0.2 and so on and so on.
release-versioning-settings-nugetpackage
NuGet versioning in Octopus

NuGet versioning is just as simple; the value your release version will reflect is the NuGet package that’s been selected. Keep in mind, Octopus needs to know which step within your process to extract the NuGet package version. If your deployment process deploys multiple NuGet packages, you still have to pick one. This not might not be the best approach for you as it may be confusing at a glance to see what release deployed which packages.
Note: Don’t forget to “promote” your releases across environments – this keeps the release version consistent, uses the same NuGet package version(s) and at a glance keeps things logically simple to decipher.
It really is a matter of taste, but I have noticed that there are unforeseen warts with the NuGet versioning option compared to the variable template way. Two things to keep in mind:

  • If you change your deployment process frequently (which you really shouldn’t after a while), you’ll run into problems when you try to redeploy a NuGet package. Any changes you make to your deployment process require you to create a new release. If you change your process, but you want to reuse a NuGet package that was previously deployed, Octopus will warn you because you cannot have duplicate release versions. This becomes a sticky matter and the whole NuGet versions for releases gets to be cumbersome. You either have to delete the previous deployment, edit the version number or redeploy the same release (which we don’t want because we already changed the process). It’s not a terrible problem, but it’s confusing when you initially encounter it.
  • Multiple NuGet packages within a deployment process, as we mentioned earlier, can obfuscate what your releases have really deployed to an environment. Imagine having two packages (or more) as part of your process. When you deploy the release, which package should indicate the version of the release? What happens if only one of the NuGet packages need to be updated but it isn’t the package that versions the deployment? The work around would be to break out your applications into their own projects, but this makes continuous deployment more difficult as you’d have to deploy each release within each project. Note, you can do multiple deployments from different projects in a continuous deployment configuration, but you’ll have to leverage the octo.exe and PowerShell to make that happen. From a tracing perspective, it’s clear to see which NuGet package has been deployed, but from a process point of view, it’s fragmented and requires more configuration and time.

These issues are relatively simple to overcome. The point in bringing awareness is to emphasize the possible pitfalls however minor they may be. I’m not advocating one versioning system or the other, but in my experience, variable template is much easier in comparison to NuGet versioning. NuGet versioning makes perfect sense in small projects with only one nuget package to deploy, but every team I’ve coached has their own wrinkles and nuances. If you have a simple deployment process that uses one NuGet package, NuGet versioning makes sense. If you have multiple packages in your deployment process then the NuGet versioning system falls apart and variable template versioning is the preferable option. For what it’s worth, how you configure your deployment process or setup your projects, either system is workable. Only you will know what’s best for your project.
Versioning NuGet Packages
Looking back on all the reading and research I did in addition to the discussions with my colleagues, I feel I can say with some confidence that the simplest way of versioning is leveraging the built-in auto-generated Build/Revision numbers, but ultimately it comes down to what is appropriate for your team, project and code base. I prefer a simple and automated approach rather than elaborate schemes, but needs really dictate what you should work towards. To cut to the chase, the best versioning system is one that uses dates.
For simple (or “dumb”) NuGet versioning, I’ve found leveraging dates within your version number to be the most succinct method. This is not a new idea.  Jeff Atwood has a great post on the subject of version numbers, although I didn’t read this post until after my conclusion. Jeff’s post has a few phrases that cut straight to the point, I’m going to quote him directly in regards to versioning NuGet packages.

I like to think of version numbers as dogtags for your software

I never thought about it in terms of dogtags, but the analogy fits. With TFS, there’s changesets that allow you to rollback to a specific check-in. Other CI solutions have an equivalent function; Git has hashes; all CI solutions have some similarity and the identifier that’s most important allows you to find the precise change within version control. But realize that a build is nothing that special – unless proven otherwise. Having automated deployments through out your environments really puts a build through it’s paces for testing to see if it’s worthy of production. Over time, old builds (packages) can be discarded. So really version numbers are the ID of your build – they need to give you some reference key as to what point in time that build was done and/or against what changeset/hash.
I approach versioning NuGet packages in two varieties; in colloquial military terms, I have a dumb versioning and a smart versioning. Maybe it was Jeff’s dogtag analogy that steered me towards the military vocabulary, but it is applicable in our case as well.
“Dumb” Versioning
mk82-dumb-bomb
For dumb (aka simple) versioning, I use dates. Dates are great as Jeff had pointed out. They’re easy to generate and somewhat easy to trace back to which is the whole point. How easy is this?
One way to do this in your project in Visual Studio (while using MSBuild and/or TFS), you can use the Microsoft versioning mechanism of generating version number: Major.Minor.Build.Revision. To do this, in your AssemblyInfo.cs file within the project you want to generate the NuGet package with a unique versioning system that’s also sortable by date; in the AssemblyInfo.cs file, change the “AssemblyVersion” from “1.0.0.0” to “1.0.*”. Using the asterisk ‘*’ character will let MSBuild fill in the Build and Revision numbers. Fortunately, these numbers are unique and date sortable – that is to say, the most recent build will always have the highest value by comparison to previous builds.
By changing to “*” for your Build and Revision digits, MSBuild will do the following:
– The Build number generated is the total number of days since December 31st, 1999 – similar to the Unix Epoch.
– The Revision number generated is the total number of seconds since 12AM (on the machine doing the build) divided by two. A another strange numerical format but it’s consistent, sortable and has a limited number of digits. So the absolute maximum number of seconds per day is 24 hours x 60 minutes x 60 seconds = 86400. Divided by two, that gives us 43200.
myget-feedUsing the asterisk for build and revision basically gives you: major.minor.date.time. This keeps things sortable and easy to navigate (within a given major/minor combination). How so? Looking on the right, you can see my sample NuGet feed for my OctopusDemo.Web MVC project. You can see I used the “1.0.*” for my AssemblyVersion within my AssemblyInfo.cs file within the MVC project. With a quick glance, you can see a simple pattern emerge:

  • 1.0.5382.36084
  • 1.0.5382.10307
  • 1.0.5382.9566
  • 1.0.5382.8560
  • 1.0.5382.2664
  • 1.0.5369.29184
  • 1.0.5369.27989
  • 1.0.5368.11967
  • 1.0.5368.8888

Right away the build number sorts everything by date. The build numbers give us a relative identifier from the base date of December 31 1999. If you use a date calculator, you can start with December 31, 1999 and add 5382 days and you’ll get the date of September 26, 2014. Is it necessary to calculate the date? Not really. But if you ever needed to know the exact date, you can figure it out.
How many days of builds are represented here in these nine packages? Answer: three – 5382, 5369 and 5368 all represent unique days. Easy enough to spot. Just to the right of the build number is the revision number (aka time) which gives you another relative identifier. The highest revision number with a given build number is the last build of that day. The great thing about this simple versioning mechanism is that larger numbers will always be generated, thus making sorting a breeze. The largest version number will always be the most recent in terms of date and time.
What about calculating the time of the build? Same idea as the build number but a little more work. Take the last string of digits – 36084 x 2 = 72168. 72168 seconds / (60 sec. x 60 min = 3600) * 20.04666. This translates to: 20 hours and 2.4 minutes – or 10:02PM. A simpler formula for time is: (revision-number/1800). The result is the number of hours in a 24hr clock.
Is this the best pattern for versioning everything? No, but for 99% of most projects I’d wager it’s good enough. Jeff’s take on versioning I think is spot on: most users don’t care about version numbers. Developers need version numbers temporarily at best or in case of emergency. Most of our teams use this automated versioning mechanism and so far, it’s been very successful. Since Octopus can pick the latest package easily, teams that use the octo.exe for continuous deployment easily without knowing the actual version number since the sorting favors the latest version.
Keep in mind, this is just one possible way of versioning by date/time. Alternatively, you could use a PowerShell script to create your own version number scheme, but I doubt anything is easier than changing “1.0.0.0” to “1.0.*”. Changing the AssemblyVersion in the AssemblyInfo.cs file for your project is the quickest and easiest way to uniquely version your packages.
After using this method for some time, I’d say it’s my default method of versioning. It works. It’s simple, and it’ll always create a unique, sortable number. What’s not to like? Well I admit it’s  a *little* vague. If you had to know the exact changeset (Team Foundation Version Control) or hash (Git), this method will get you close – but not on the mark. For teams with strict QA and trace-ability requirements, a version number may need more than just a date. This is going to be a subjective decision for each company, project and team. If you need something more precise, use smart versioning.
“Smart” Versioning
paveway_iiiFor a more precise (aka smart bomb) versioning, I try to tie versions directly to the changeset (within TFS). If you’re using Git, it’s a little complicated as hashes don’t quite work within a version number. Maybe it would be better to store that within the NuGet NuSpec file, under release notes albeit that requires a bit of configuration. So far, I have yet to actually use complex versioning, however I imagine at some point in time in the next few months I’ll need to create a proof of concept for a few teams.
With Octopus Deploy and NuGet, dates solves a lot of problems. It’s not perfect, but it’s close enough and simple enough to automate. Simply put, dates give us a way to trace back to the code that was compiled in whatever CI solution you use. I work with TFS so changesets are a great number to embed into a Nuget package version if it was easy – but it isn’t. You have to modify your build template with Windows Workflow to get the desired information.
So what’s so smart about “smart” versioning? Ultimately, “smart” versioning comes down to what you need. Maybe you need a changeset or a hash. Maybe you need more precision compared to a date/time stamp, and that’s fine. Just realize that it’ll take a lot more work to get a “smarter” versioning system to work – so if you absolutely sure you need it, go down that route. Otherwise, fallback to the simple “dumb” versioning and save yourself some time.
Conclusions
This was a difficult deep dive to write. At some point, I will follow up this deep dive with another on Git versioning and a fully working “smart” versioning example, time permitting of course. But as a primer on versioning within Octopus and NuGet, I hope this deep dive was at the least good start for you. I had no where to start so I just read everything as best as I could and tried to implement a few methods – some worked, others didn’t. Either way, I thought there should be some sort of primer or map on how to proceed. How you choose to version your projects is up to you and the needs of your project, but I think there are a few key takeaways or best practices from my experience:
1. If continuity of your versions matter, then you need to have a strategy from the beginning.
2. No versioning system is perfect for everyone. If you just need something quick – use the * in the AssemblyInfo.cs trick. If you need something more precise to trace back to the check-in/buildnumber/changeset/hash/etc. by all means go ahead – just keep in mind Octopus Deploy sorts by version number so any scheme you create, just make sure the values increase over time. Otherwise you’ll have to pass a precise version number for your package in your octo.exe call.
3. If you’re deploying only one NuGet package in your deployment process use NuGet versioning for your releases; otherwise use the variable template versioning method. I prefer the variable template but to each his/her own opinion.
4. Use dates (somewhere) in your NuGet package versions – in some format. If you’re crafting your own date format, make sure you use ISO format for sorting! (YYMMDD) If you need time, use YYMMDDHHMM or use the build/revision automated system from MSBuild in your AssemblyInfo.cs.
5. Simplicity and automation trump a lot of custom version numbers. If you can’t automate your version numbers and if it isn’t easy to decipher and translate into something meaningful, it’s probably too complicated and not worth your time.
6. If you want to use the same build number for all your assemblies (as you probably should) you can share version numbers across assemblies in your solution. It’s very easy to do.
7. All versioning can be modified later should things change. It’s important having some consistency for your sprints but ultimately, if things need to be reworked, they can be.
8. For more information on maintaining version numbers using the MSBuild versioning of major, minor, build, revision, check out this great accepted answer on Stackoverflow.
I’ll follow up this deep dive with part two – one that covers (in depth) how to do custom versioning in TFS with both Tfvc and Git. I’ve been meaning to try out JetBrain’s TeamCity for the longest time and that may be a supplementary deep dive but I’ll try to incorporate it on part two of the versioning deep dives as an example. But that’ll do it for this deep dive. I still have a lot more deep dives on deck so stay tuned.

ianpaullin

Share

4 Responses

  1. As for how to version your NuGet packages, check out the GitVersionTask NuGet package. It uses SemVer to automatically version your assemblies (and thus your NuGet packages), in accordance with GitFlow.

Leave a Reply

Your email address will not be published. Required fields are marked *

Post comment