Duplicati version numbering

Continuing the discussion from Issues to address to get out of beta:

As a user, I’d like to emphasize this. The current version numbering of Duplicati is not good.

In my opinion, you should not use the same set of leading number for stable, beta, experimental and canary releases.

The 2.0.4.23 release is an example of bad numbering. According to the version number, I expect it as a user to include all changes <= 2.0.4.23.

The main problem is as said previously, that there is no clear numbering scheme, so the version numbers are unpredictable and no milestone can be created based on a future version number

One proposition: assuming a version number W.X.Y.Z,

  • increment W only for major new versions (potential Duplicati 3, in practice W is lost for versioning purpose in the current usage)
  • increment X after every stable release
  • increment Y after every beta release
  • increment Z after every experimental or canary release

Reset all lower numbers to 0 for subsequent builds every time a higher level get incremented.

So given a chronological sequence of releases, this could look like this:

  • 2.0.4.29 canary release
  • 2.0.4.30 experimental release
  • 2.0.4.31 beta release of the 2.0.4 branch
    (— experimental and canary must increment Y after that point —)
  • 2.0.5.0 canary release
  • 2.0.5.1 canary release
  • 2.0.5.2 canary release
  • 2.0.5.3 experimental release
  • 2.0.5.4 canary release
  • 2.0.4.32 urgent bugfix on beta of the 2.0.4 branch release (does not include changes from 2.0.5.*)
  • 2.0.5.5 canary release
  • 2.0.5.6 experimental release
  • 2.0.5.7 beta release of the 2.0.5 branch with all changes from <= 2.0.5.7
    (— experimental and canary must increment Y after that point —)
  • 2.0.6.0 canary release for the new 2.0.6 branch
  • 2.0.5.8 stable release of the 2.0 branch with all changes from <= 2.0.5.8,
    (— beta, experimental and canary must increment X after that point —)
  • 2.1.0.0 canary release for the new 2.1.0 branch
  • 2.1.0.1 canary release
  • 2.1.0.2 experimental release
  • 2.1.0.3 beta release of the 2.1.0 branch with all changes from <= 2.1.0.3
    (— experimental and canary must increment Y after that point —)
  • 2.1.1.0 canary release for the new 2.1.1 branch
  • 2.1.1.1 canary release
  • 2.1.1.2 experimental release
  • 2.1.1.3 beta release of the 2.1.1 branch with all changes from <= 2.1.1.3
    (— experimental and canary must increment Y after that point —)
  • 2.1.2.0 canary release for the new 2.1.2 branch
  • 2.1.2.1 canary release
  • 2.1.1.4 bugfix on beta release for the previous 2.1.1.* branch
  • 2.0.5.9 bugfix on stable release for the previous 2.0.5.* branch
  • 2.1.2.2 canary release
  • 2.1.2.3 experimental release
  • 2.1.2.4 beta release
    (— experimental and canary must increment Y after that point —)
  • 2.1.3.0 canary release for the new 2.1.3 branch
  • 2.1.2.5 stable release of the 2.1 branch with all changes from <= 2.1.2.5
    (— beta, experimental and canary must increment X after that point —)
  • 2.2.0.0 canary release for the new 2.2.0 branch
  • 2.2.0.1 canary release

Interesting idea…I like it, but it seems a bit on the complex side.
I like that it achieves the goal of avoiding another 2.0.4.23 fiasco.

Well I agree with you that it’s not the prettiest version numbering system. I am not very fond of it but I tried to combine the existing practice of Duplicati (not following SemVer consistently, simply incrementing the version number at each release, be it canary, experimental, beta or stable) while avoiding the problem arising when there is a new release to higher tier release types (beta and stable) which don’t include all changes in canary/experimental.

The current practice cannot handle the fact that a release for a bugfix or a feature backport on a stable or beta branch has no version number available that:

  • is more than the previous beta/stable
  • but less than the following canary/experimental releases (between the previous beta/stable and the new beta/stable).

In the linked thread, there was a beginning of discussion of having feature freeze to be able to cut betas out of experimental/canary releases more often. I think this is a very good idea.

Currently, it seems that canary/experimental continuously receive new fixes and features which make these channels hard to “crystallize”.

In the meantime, plenty of fixes in canary/experimental could be backported into beta/stable over time (the Default Filter speedup is a very good example, it is a very small fix, that could have been backported easily to beta and stable, but in the current development process, it bakes for months in canary/experimental releases that are hard to “crystallize”).

The above versioning scheme could actually be tweaked slightly to allow for a feature freeze process.

For example:

  • 2.0.4.29 canary release
  • 2.0.4.30 experimental release
    (— feature freeze for 2.0.4.* >>> canary must increment Y after that point —)
  • 2.0.4.31 beta release of the 2.0.4 branch
  • 2.0.5.0 canary release for the new 2.0.5 branch
  • 2.0.5.1 canary release
  • 2.0.5.2 canary release
  • 2.0.5.3 experimental release
    (— feature freeze for 2.0.5.* >>> canary must increment Y after that point —)
  • 2.0.6.0 canary release for the new 2.0.6 branch
  • 2.0.4.32 urgent bugfix on beta of the 2.0.4 branch release (does not include changes from 2.0.5.*)
  • 2.0.6.1 canary release
  • 2.0.5.4 second experimental release for branch 2.0.5
    (no need to bump Y in canary, because this release still follows the 2.0.5 branch and does not include things from 2.0.6)
  • 2.0.5.5 beta release of the 2.0.5 branch with all changes from <= 2.0.5.5
  • 2.0.6.2 canary release
  • 2.0.5.6 stable release of the 2.0 branch with all changes from <= 2.0.5.6,
    (— beta, experimental and canary must increment X after that point —)
  • 2.1.0.0 canary release for the new 2.1.0 branch (similar to 2.0.6.*, but with X incremented)
  • 2.1.0.1 canary release
  • 2.1.0.2 experimental release for branch 2.1.0
    (— feature freeze for 2.1.0.* >>> canary must increment Y after that point —)
  • 2.1.0.3 beta release of the 2.1.0 branch with all changes from <= 2.1.0.3
  • 2.1.1.0 canary release for the new 2.1.1 branch
  • 2.1.1.1 canary release
  • 2.1.1.2 experimental release
    (— feature freeze for 2.1.1.* >>> canary must increment Y after that point —)
  • 2.1.1.3 beta release of the 2.1.1 branch with all changes from <= 2.1.1.3
  • 2.1.2.0 canary release for the new 2.1.2 branch
  • 2.1.2.1 canary release
  • 2.1.1.4 bugfix on beta release for the previous 2.1.1.* branch
  • 2.0.5.9 bugfix on stable release for the previous 2.0.5.* branch
  • 2.1.2.2 canary release
  • 2.1.2.3 experimental release
    (— feature freeze for 2.1.2.* >>> canary must increment Y after that point —)
  • 2.1.2.4 beta release of the 2.1.2 branch with all changes from <= 2.1.2.4
  • 2.1.3.0 canary release for the new 2.1.3 branch
  • 2.1.2.5 stable release of the 2.1 branch with all changes from <= 2.1.2.5
  • (— beta, experimental and canary must increment X after that point —)
  • 2.2.0.0 canary release for the new 2.2.0 branch (similar to 2.1.3, but with X incremented)
  • 2.2.0.1 canary release

Whether to set a feature freeze when doing an experimental or a beta release is left open. I prefer freezing at the experimental level, to leave room for bugfixes before having a beta. A beta release is kind of a release candidate and should not see many bugfixes after it is released. It will be promoted to stable after some time.

I would suggest that it could be easy to say with W.X.Y.Z
W is major version/arch change.
X is next release update (yay features!).
Y is next bug/security fix.
Z is basically build number for experimental use.

In this way, when a (beta) release happens that may not get everything from experimental, that is accounted for by the X and Y numbers. Setting Y+1, but the next value at 0 again, would allow for the release itself, and then Z being 1 would be all the non-released work being added back in for the next experimental build. Requiring Y to increment when a database version change happens would seem to make sense in this way as well. This would also allow targeting of version numbers fairly easily for specific major change sets as well, such as putting a fix into a Y+1 update.

I see a beta has been released as 2.0.5.1 and two canaries as 2.0.5.100 and 2.0.5.101 respectively.

Does this mean that the chosen solution is to increase Y and set Z=0 for every beta and then continue with canaries with Z+100 and so on?

Is there a formalized discussion/decision/procedure for the numbering that the release maker uses currently?

When is it planned to use W and X in the W.X.Y.Z version number format?

(just asking out of curiosity)

Not quite, but close. Fitting Stable, Beta, Experimental, Canary, and Nightly into three numbers got too tight (the initial 2 is wasted), so Experimental, Beta, and Stable, were declared the careful release side (which they are – except Stable isn’t available yet), subject to respins at launch times, promotions, and patches, Nightly (not available yet) and Canary are from GitHub master, and get replaced not patched.

When Canary looks safe and it’s time, an Experimental is built at Z=0, and respins or promotions bump .Z. Changes may be small. 2.0.5.1 Beta is a release note and number away from 2.0.5.0 Experimental.

As a bit of build trivia, I found out that the change flow from Experimental to master is actually that way instead of master being changed first and moved to Experimental. If you’re interested in either build or release issues (which you seem to be), I’d note that there’s currently an opening for a release manager.

Not every Experimental gets promoted further. This isn’t new. 2.0.4.21 was not promoted, and could be considered a content preview. 2.0.5.0 was intended to be Beta release candidate, but the release note didn’t really comment on which style of Experimental it was. Once Stable is reached, perhaps Beta can be the Stable release candidate and Experimental can be a content preview. Or maybe something gets retired (it seems a lot of channels), or so many developers volunteer (I wish…) that change is required.

Duplicati has a history of releases at 2.0.Y.Z where Y goes up on new content, and Z is small. To keep that plan, the content-level bump (Y) remains at Experimental build, and Z remains memorably low (0). Because some people may find .0 frightening, it got put at Experimental, and later channels are higher.

Having Z get double-use relieved the numbering squeeze. Canary and Nightly get .100 and on forever. The widely used formal releases get the low numbers, and the double-use shows up less on right side.

The sometimes-needed ability to pick up a Canary as a placeholder while waiting for a fix to propagate still works. For example I might say use this Canary, change update channel Settings to Beta, and wait.

There’s sort of a leapfrog effect, where Canary/Nightly starts at higher .Z=100 and also bumps Z faster (probably). Higher number implies forward compatibility from lower .Z of the widely used releases, then when time comes to bump .Y, forward compatibility (and autoupdate) are implied by the numbering too.

The goal of this redesign was to leave numbering space for patches and respins for channels that have them, to avoid the 2.0.4.22 Canary to 2.0.4.23 Beta confusion when 2.0.4.23 was basically 2.0.4.5 Beta plus a patch, but Canary had already taken 2.0.4.6. It’s a simple tweak in a way to just start it later on…

There was a discussion similar to this which included tables of actual history (including 2.0.4.23 oops) compared to how history would have played out under this plan, and release maker has used it so far.

X was proposed to be Stable, to make it appear to be more significant than the more frequent Y bump. That’s somewhat far ahead to be thinking of, and W is even further. Because .NET Framework is now somewhat stagnant, and the future is .NET 5, I’m not sure how Duplicati will handle it. Maybe new W? Things are pressed enough in short term (more volunteers would help) that long-term planning suffers.

Thanks for the detailed reply. I was afraid I was too terse in my previous message which might sound slightly aggressive, which was absolutely not the intention.

While still quite an unusual numbering system, this solution seems the easiest in the interim. It mostly keeps the previous way of doing it while leaving a big enough number gap in Z to handle bugfixes.

I did note the open release manager position from another thread. Would it be that duplicati was a python project, I’d have given some thought, but on top of severely lacking time (like everyone else) I have absolutely zero experience in .NET so that’s not for me I think.

Thanks again for the work done!

Thanks for considering release manager. As mentioned, it’s highly flexible and some of it is just helping make the decision of when-is-it-ready. We’re not currently ambitious (or numerous) enough to get fancy with pushing code to one branch or the other. For now, minimal staffing requires some lightweight ways.

restore_from_python.py #2424 is an Independent restore program seemingly needing some care.
If you like, of course. :wink: