I have been doing a heap of reading about semver and how you can include build meta-data and other things, but I am really struggling to find a way to fit SemVer and Continous Delivery together.
Currently I am the primary maintainer or a main contributor for for:
https://github.com/TestStack/White
https://github.com/JakeGinnivan/VSTOContrib
https://github.com/DbUp/DbUp
https://github.com/Code52/DownmarkerWPF
https://github.com/TestStack/ConventionTests
And quite a few other smaller projects (https://github.com/JakeGinnivan?tab=repositories)
Most of these projects do not use SemVer, and I hit a button on TeamCity and it takes the last successful build and pushes it to NuGet, or the clickonce installers to Azure. How can SemVer work into the release process better, I have ideas that for clients SemVer could also be used to describe the type of changes in a project to the StakeHolders, they see a Major Version release = New Features, Minor = Adaption/Improvement to current features and Patch = Bug Fixes. Basically, I want a way of working which works in most scenarios as a default, then change from there. Currently it seems SemVer and Continuous Delivery are incompatible, which is a real shame.
I use GitHub Flow most of the time, I really like this as it works very well with Continous Delivery and Open Source. It also works awesome on commercial projects with large teams.
I have written two blog posts on different ways of releasing SemVer software, trying to put the WHOLE picture in place, including VCS management and build server. They are http://jake.ginnivan.net/release-nuget-semver-packages-from-teamcity and the second is using Git-Flow and GitFlowVersion to version http://jake.ginnivan.net/git-flow-versioning
- v2.0.0+ci5 is semantically the same as v2.0.0, so I can't publish it as a nightly. Honestly I think v2.0.0-whatever should be behind v2.0.0 and v2.0.0+whatver should be after v2.0.0. This would make conventions of nightlies or even CI builds of your package simply X number of builds after the last released version. Then I release the next version, it is tagged and it builds from there..
- Continuous delivery means that any CI build which goes through your pipeline should be able to be promoted, but SemVer really is a checkpoint and communicating the type of changes in that release via version numbers. Do we really mean that the CI package is a candidate which can be promoted, then if I tag, that is a new build which can be promoted separately?
I have other issues/questions, but they are mainly related to the above points, I would love to see how others are using CI and SemVer together. There doesn't seem to be many examples out there...
Lets take GitHub flow, and GitFlowVersions ideas and try to create a simpler more lightweight solution.
- Follow GitHubFlow
- Builds are v{lastmajor}.{lastminor}.{lastpatch+1}+ci{numberOfCommitsSinceLastTag}
- Introduce conventions of floating tags of
MajorChange
andMinorChange
. If at any point a pull request is a breaking major change, or minor change (rather than a patch) you can use one of these tags to affect the generated version. For instance if there is aMajorChange
tag since last release then the version will be v{major+1}.0.0+ci{numberOfCommitsSinceLastTag} - Beta's/RC's are also floating tags, making the current version {lastversion} + {floating tags}. A
MinorChange
tag plus aBeta
tag a few commits later would create a build with versionv{lastMajor}.{lastMinor+1}.0-beta
, subsiquent commits would have the suffix-beta{numberOfCommitsSinceBetaTag}
This could be a really light weight way to keep track of the SemVer, then when you release you simply tag. You can delete or leave those floating tags, it doesnt really matter. If they are behind the last release, they mean nothing. Do we even need to track the potential next version? This would also make the publish as pre-release a convention, only version tags are released as stable versions. And all released versions can be rebuilt at any time.
Feedback on this topic would be great
Question The First
Well, this isn't adhering to semver any more - but I don't think this is essential to the discussion at hand.
Personally, I'd have different sorts of releases without needing to abuse the custom metadata:
There's a finite set of transitions between states here, so even though there's four different types it's still easy to grok what to expect from a release (exactly the point of semver).
By leaning too much on the build server for generating your version number, you probably tie yourself to a specific axis of changing these versions. In some of my side-project I've found myself switching back to scripts which update the version locally, rather than having to jump through hoops to manually bump the version on the build server.
I guess it comes down to how you co-ordinate your releases. CD generally wants every change to be something you could possibly ship (which is good), but on the other hand you want to be really controlled about your releases (which is also good). The benefits of mixing them together, however, I'm a bit skeptical about.
Question The Second
Keeping your code in a close-to-shippable state is awesome, and something we all should strive for. If a side-effect of that is you do more interim releases that pass your same pipeline, what's the downside?
A couple I can think of:
But those are things we can mitigate/resolve these risks:
On the Idea
I think doing less CD (note: still do the same degree of CI) and more self-versioning (I just made that word up) would make for a much simpler experience.
A couple of things I'll call out:
Major/breaking changes are significant enough that I think automating this is a bit scary.
Why not just rev the version inside the pull request before merging it in?
Generally you're either making release candidates or not (i.e. things have stabilized enough). Does that require it's own tag? I don't think so.