Cmb2: Use Semantic Versioning

Created on 26 Nov 2017  ·  3Comments  ·  Source: CMB2/CMB2

tl;dr - You already partly do it, just with different semantics to what the rest of us follow. Following semver strictly would give value to the main developer audience.


There are many different ways that software releases can be versioned - by name, by release date, by sequential integer, by some complex string of numbers that include internal build number / time and so on.

Sometimes releases may appear to be numerical, but turn out to be strings, when numbers are skipped over for technical reasons i.e. Windows 9, and PHP 6.

These version identifiers are aimed at different groups of users, but broadly, the less complex ones (e.g. names, like High Sierra, and Windows 10) are aimed at Users. The others with numbers are more aimed at developers - either developers of that software or developers who consume / develop _against_ that software.

CMB2 is typically aimed at a developer audience.

To ensure compatibility, developers have to understand what the version means - a date or name-based version misses out on an opportunity to let developers know if there was any significant change or whether it was simply one or more bug fixes. That means consumers have to read all of the change log to avoid any nasty surprises.

You know where this is heading, but Semantic Versioning (semver) is the de facto standard that for the majority of packages, at least in the PHP / WP space, can and do follow. Read the spec if you aren't familiar.

The question, is what versioning system CMB2 uses, and whether anything can be gleaned from it.

There are 38 releases for this repo, but 9 of them have a version number less than 2.0.0. That means there have been 29 releases to get from 2.0.0 to 2.2.6.1.

Let's look at the release versions from latest, going backwards. E indicates that an enhancement was added, and B indicates a bug was fixed (according to the release notes):

  • 2.2.6.1 EB
  • 2.2.6 EB
  • 2.2.5.3 EB
  • 2.2.5.2 B
  • 2.2.5.1 B
  • 2.2.5 EB
  • 2.2.4 EB
  • 2.2.3.1 EB
  • 2.2.3 EB
  • 2.2.2.1 B
  • 2.2.2 EB
  • 2.2.1 B
  • 2.2.0 EB
  • 2.1.2 B
  • 2.1.1 EB
  • 2.1.0 B
  • 2.0.9 EB
  • 2.0.8 B
  • 2.0.7 EB (including breaking change)
  • 2.0.6 EB
  • 2.0.5 B
  • 2.0.4 B
  • 2.0.3 EB
  • 2.0.2 E
  • 2.0.1 EB
  • Various 2.0.0.* as beta releases.

First off is to note that in the last few releases, there is an inconsistent format of the version string itself - sometimes it's a.b.c, and others it's a.b.c.d. The a.b.c format is implicitly equal to a.b.c.0.

There are two patterns which indicate at least an underlying effort to follow semver:

  • The "hotfix releases" (with the non-zero d part) tend to be bug-fix releases, though a couple of enhancements have also sneaked in. This extra .1 implies a _connection_ to the implicit .0, even if it's down at the d level.
  • There was a jump between 2.1.2 and 2.2.0, so despite 2.1.0 coming after 2.0.9 (indicative of not following semver), something in that 2.2.0 release suggested it was worth skipping over the rest of the 2.1.* versions (a good thing).

In all cases, a is typically 2, due to the project's history, and that does make the use of semver for this project less clear-cut than other packages.

One obvious point where semver has not been followed is the documented breaking change for 2.0.7.

As with any software, the aim is not to break backwards compatibility (BC). Or, more specifically, it should not break BC accidentally / without a clear indicator. Having it just buried within release notes / changelog is not sufficient.

Let's assume that at some point in the next year or two, WP bumps the minimum required version of PHP to 5.4.

Let's even allow an overly-generous five-year lag before namespaces are allowed to be used in CMB2. At whichever point in time that will be, the switch to namespaces is going to break BC, and at that point, theme and plugin developers will need to know that.

Releases that identify as having breaking changes are a necessary part of software development. They allow for changes in public API for better long-term usage, the removal of old deprecated code that adds to maintenance, and generally, is a chance to reduce technical debt - as an example think of the simplified code if PHP 7 was the minimum required version, and what scalar type declarations could do.

Let's take the above list of releases since the v2 betas to see what that would look like if semver had been followed. (For the purposes of this first example, I'm actively going to ignore the breaking change):

  • 2.15.0 EB
  • 2.14.0 EB
  • 2.13.0 EB
  • 2.12.2 B
  • 2.12.1 B
  • 2.12.0 EB
  • 2.11.0 EB
  • 2.10.0 EB
  • 2.9.0 EB
  • 2.8.1 B
  • 2.8.0 EB
  • 2.7.1 B
  • 2.7.0 EB
  • 2.6.1 B
  • 2.6.0 EB
  • 2.5.1 B
  • 2.5.0 EB
  • 2.4.1 B
  • 2.4.0 EB ~(including breaking change)~
  • 2.3.0 EB
  • 2.2.2 B
  • 2.2.1 B
  • 2.2.0 EB
  • 2.1.0 E
  • 2.0.0 EB
  • Various 2.0.0-beta as beta releases.

And now, including the breaking change:

  • 3.11.0 EB
  • 3.10.0 EB
  • 3.9.0 EB
  • 3.8.2 B
  • 3.8.1 B
  • 3.8.0 EB
  • 3.7.0 EB
  • 3.6.0 EB
  • 3.5.0 EB
  • 3.4.1 B
  • 3.4.0 EB
  • 3.3.1 B
  • 3.3.0 EB
  • 3.2.1 B
  • 3.2.0 EB
  • 3.1.1 B
  • 3.1.0 EB
  • 3.0.1 B
  • 3.0.0 EB (including breaking change)
  • 2.3.0 EB
  • 2.2.2 B
  • 2.2.1 B
  • 2.2.0 EB
  • 2.1.0 E
  • 2.0.0 EB
  • Various 2.0.0-beta as beta releases.

I'm not sure what concerns there are about using semver, but one often touted is that version numbers will get massive. That doesn't seem to concern Chrome (currently v62) and Firefox (v57), but as can be seen, the whole not-quite-3-years of CMB2 would only have got up to 2.15.0 or 3.11.0. Would developers be less inclined to use it because of that? I doubt it - more likely, they would be more appreciative of the project, _because_ it followed semver.

As mentioned in the tweet that elicited the invite to open this issue - an intention not to break BC doesn't mean you can't follow semver; it has other value for the target audience for BC-compatible enhancements and bug-fix releases.

Based on all of this, I would propose two things:

  • Treat "CMB2" and its expanded form as the marketing name. Users don't really care for version numbers, so while "CMB2 v3.1.4" may seem a little odd at first, Users will be fine with it. However, Developers can get _value_ from understanding what a 3.1.4 release might have compared to the 3.1.3, 3.0.8 and 2.18.5 releases.
  • Switch to use semver strictly. Put out bug-fix only releases as a bump to the patch level (c in our example, or z in the semver document), and any addition of an enhancement automatically means the minor release (b in our example, or y in the semver document) is bumped.

Most helpful comment

Cool, I dig it. However, next release, if bug-fix only, will be 2.2.6.2, for arbitrary reasons that make sense to me (namely that it'd be weird to make the change when there is already a d level hotfix for this release). Next version which has enhancements will be 2.3.0 and I will include a note in the changelog about switching to semver.

All 3 comments

Thank you very much @GaryJones for your inciteful thoughts. Your comment about an “underlying effort” to follow Semver is exactly right. I am on board with doing this to follow Semver more accurately. How would you propose moving forward? Based on your suggestions, are you saying to retroactively apply the updated versioning? I’m not a fan of that idea for a few reasons, but would like to hear your thoughts either way. As always, I appreciate your feedback.

are you saying to retroactively apply the updated versioning? I’m not a fan of that idea for a few reasons, but would like to hear your thoughts either way.

No, definitely not. Can you imagine the support burden and confusion that would have when two different releases were tagged with the same version number?!

The latest release is 2.2.6.1. Let that, and everything before it stay as is.

The next version is decided, at release time, based on what's being included. If it's a bug-fix only release, it will be 2.2.7. If you also add some enhancements (whether or not it includes bug fixes or not), then use 2.3.0.

The extra advantage of doing this is the following scenario:

Let's say 2.2.7 has a security issue, but 2.3.0 and 2.3.1 have already been released. No problem - take the 2.2.7 releases, and hotfix into a 2.2.8 release. Take the 2.3.1 release and hotfix it into 2.3.2.

That's pretty much what WP has done since auto-updating has come in. Now, since these are not considered "major" releases like WP does, you may want to only support to a limited number of x.y releases back, or maybe none, but with semver, the option is there. Those who have CMB2 active as a plugin will just get the latest version that's pushed to the .org repo, but those using it via Composer dependency, or as a manual include, can pick whether they just want to be hotfixed, or take a deeper look at the next minor branch.

Cool, I dig it. However, next release, if bug-fix only, will be 2.2.6.2, for arbitrary reasons that make sense to me (namely that it'd be weird to make the change when there is already a d level hotfix for this release). Next version which has enhancements will be 2.3.0 and I will include a note in the changelog about switching to semver.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mathetos picture mathetos  ·  8Comments

apokyro picture apokyro  ·  5Comments

abuyoyo picture abuyoyo  ·  7Comments

gorirrajoe picture gorirrajoe  ·  4Comments

kidatart picture kidatart  ·  7Comments