Conditional Versioning

Hey

I’ve been playing around quite a lot with release versions trying to come up with the best approach. We follow a pretty standard dev cycle where multiple times during a sprint a release is made to a test environment. Once we have enough work for a production release we merge our dev code into our master branch and create a release from that code.

Ideally I want to automate my versioning so I can do something like this:

We’re working on version 1.0.1 so I create pre-release packages that get picked up by a pre-release channel and generate version numbers such as 1.0.1-r1, then 1.0.1-r2 and so on. Once everything is ready for version 1.0.1 I’d want to generate new packages without a pre-release suffix and have my default channel pick these up and create the version number without the suffix, 1.0.1.

After this has happened I’d want the first pre-release to automatically increment the patch part of the version number, and reset the suffix, so that the next pre-release version number would be 1.0.2-r1 and so on.

Is there any way to achieve something like this?

Cheers
Joe

Or as an alternative a way to use a 4 digit version number. So if in production was version 1.0.1.0, I’d want my pre-release channel version to be generated as 1.0.1.1, 1.0.1.2 etc. Then once I deploy using my default channel for it to be 1.0.2.0, and subsequent pre-releases to be 1.0.2.1 etc.

I can’t seem to find any way to do something like this and version template doesn’t support variables. If it was possible to have a different version template per channel and to be able to access named channel variable something like this could work, but perhaps I’m not understanding these Version variables correctly?

If I had two channels, what’s the difference between using Octopus.Version.LastMajor and Octopus.Version.Channel.LastMajor. I assume that the channels have their own variable, but what is the one accessed when you don’t supply Channel and when is it incremented? Is there further documentation on these variables as I wasn’t able to find anything other than what is in the app.

Hi Joe,

Firstly, I suspect you already know this but just in case, a release can take it’s version from an included NuGet package. This is great if one your packages is already versioned as you would like your release to be. This can be done via Project -> Settings -> Release Versioning.

Assuming you don’t want to take the version from an included package, then unfortunately you can’t currently achieve exactly what you want, as the version template is defined at the Project level, rather than at the Channel level.

However, that wasn’t the answer I wanted to give you, and we have a hunch that with a small change you would be able to do the following:

  • Define a variable scoped to your Default channel, e.g. IsProd and set it’s value to True.
  • Define a variable scoped to your Dev channel, e.g. IsPreRelease and set it’s value to True.
  • Enter the following in the Project ->Settings -> Version Template field:
#{if IsProd}
#{Octopus.Version.Channel.LastMajor}.#{Octopus.Version.Channel.LastMinor}.#{Octopus.Version.Channel.NextPatch}
#{/if}
#{if IsPreRelease}
#{Octopus.Version.Channel.LastMajor}.#{Octopus.Version.Channel.LastMinor}.#{Octopus.Version.Channel.LastPatch}#{Octopus.Version.Channel.NextSuffix}
#{/if}

The above template is using different values depending on which of the IsProd or IsPreRelease variables are set.

You can follow the issue above. If all goes well, it should be released in the next few days. Either way, I will update this ticket.

In the meantime (or if that change can’t be completed for any reason), I think your best option may be to set the Version template to:

#{Octopus.Version.Channel.LastMajor}.#{Octopus.Version.Channel.LastMinor}.#{Octopus.Version.Channel.LastPatch}#{Octopus.Version.Channel.NextSuffix}

This will work for the pre-release channel, but you will need to manually increment the version number for releases to the production channel. I’m assuming these happen less frequently.

With either approach you will also want to set the Package Version Rules for each channel, to select only packages without a pre-release suffix for the prod channel (and vice-versa for the dev channel). Details of doing so can be found in the “Version Rules” section of the Channels document.

I hope this helps,
Michael

Hey Michael

Thanks for the detailed answer. I did know about Nuget package versioning but that’s not the way I wanted to go.

The change sounds good and hope it can be implemented, but even with that patch the Pre-release channel’s LastPatch isn’t going to be incremented after a production release right? What I’d love to be able to do is use #{Octopus.Version.Channel.Default.LastPatch}, which would specify the Default channel, therefore the Pre-release version always uses the Default’s channel’s LastPatch var. Also I assume the suffix would continue to increment and would never reset.

Cheers
Joe

Hi Michael

Today I came up with a solution that does what I want.

Last week I stopped using Octopus to auto create the release, and switched to calling Octo.exe in my CI tool so that I could use GIT commit messages since the last prod release for release notes.

This got me thinking whether the version param of Octo.exe supports the ‘c’ and ‘i’ notations for current and increment, which is does!

First I manually created a release as version 1.0.0.0, then for calling Octo when building off my dev branch I use --version c.c.c.i --channel “Pre-release”. This results in releases like 1.0.0.1, 1.0.0.2 etc that are in my Pre-release channel and can get no further than the test environment.

I have a separate job in my CI tool for building packages from the master branch, where on calling Octo.exe I use --version c.c.i.0, so the release would be 1.0.2.0. In doing this Revision var is set to 0, and further builds from the dev branch create 1.0.2.1 and so on.

It seems to be working quite nicely this way. I have the version as a parameter on my build so that if I did want to override it manually to update one of the other numbers I can.

Where I can see this falling down though is where I have a feature branch that I’m deploying to it’s own test environment, in which case I’d probably want to update the Minor version number, which I could do with --version c.2.c.i; the only problem being the Minor var in Octopus would then be 2, and deployments to the other test environment would pick it up.

Fortunately we don’t often have to feature branch, so I’ll worry about it when I really have to. That said you’re suggested patch to have different version templates per channel could be a solution as I could have my feature branch versioning be completely different.

Cheers
Joe

Nice! Invoking octo.exe with different parameters for each branch is a neat solution.

Regarding your feature-branch issue, it’s a shame the semantic-version-mask can’t be used to increment the pre-release tag (e.g. c.c.c-i). Then you could give your feature-branches a version with a SemVer 2.0 compatible pre-release version (e.g. 2 3.2.1-alpha.1) that could be incremented. Better support for SemVer 2.0 version numbers is something we are going to look at, so this may be possible in the future.

I’m glad you’ve found a solution.

Happy Deployments!

Thanks Michael

I think for now if I need a feature branch I’ll use c.c.c.c-feature-buildno as that wouldn’t increase any of the version numbers in Octopus, and I can just use the CI tool’s incremental build number as part of the semantic-version-mask. Essentially gives the same thing.

Cheers

Hi,

Been trying this out on 3.2.23, but channel-scoped variables don’t seem to be working.

Have I misinterpreted #2285 or is this a bug?

I’ve tried the pattern you described (but with different variable names) and it seems to be only working with unscoped variables…

I am also trying to use the supplied solution.

I have IsDevelopment set to True scoped to Development channel. I have IsDevelopment set to False scoped to Test channel. I have also tried with 1 and 0.

My variable template is:

#{if IsDevelopment == True}1.0.0.1#{/if}
#{unless}2.0.0.1#{/unless}

My release version comes out at 1.0.0.12.0.0.1. I guess this is due to both being true - but the create release page doesn’t use only the variable scope of the selected channel.

Hi Hamish,

Thanks for getting in touch. It looks like the problem is that the syntax of the two statements is invalid, and therefor evaluates as ‘True’. Using == is not supported and the unless block works like a if not block, not like an else. Try using the following template:

#{if IsDevelopment}1.0.0.1#{/if}
#{unless IsDevelopment}2.0.0.1#{/unless}

For further information see the conditionals section of the variable documentation.

Hope that helps,

Robert W

I have tried that, too. IsDevelopment is set to True, scoped to my Development channel. When I create a release, it sets 2.0.0.1 for both. The variable is always false. I haven’t played around with the scoping of the variable, but it honestly appears as though the variables are not available at the Create release page. I worked around it using a different method of generating release versions.

Hi Hamish,

I’ll look further into why the variables are not available, but in the mean time you could use the Octopus.Version.Channel.LastMajor and relates variables if you already have a release for each of the channels. This might be more suitable than your work around.

Robert W