What version numbering scheme to use? - schema

I'm looking for a version numbering scheme that expresses the extent of change, especially compatiblity.
Apache APR, for example, use the well known version numbering scheme
<major>.<minor>.<patch>
example: 4.5.11
Maven suggests a similar but more detailed schema:
<major>.<minor>.<patch>-<qualifier>-<build number>
example: 4.5.11-RC1-3732
Where is the Maven versioning scheme defined? Are there conventions for qualifier and build number? Probably it is a bad idea to use maven but not to follow the Maven version scheme ...
What other version numbering schemes do you know? What scheme would you prefer and why?

I would recommend the Semantic Versioning standard, which the Maven versioning system also appears to follow. Please check out,
http://semver.org/
In short it is <major>.<minor>.<patch><anything_else>, and you can add additional rules to the anything else part as seems fit to you. eg. -<qualifier>-<build_number>.

Here is the current Maven version comparison algorithm, and a discussion of it. As long as versions only grow, and all fields except the build number are updated manually, you're good. Qualifiers work like this: if one is a prefix of the other, longer is older. Otherwise they are compared alphabetically. Use them for pre-releases.
Seconding the use of semantic versioning for expressing compatibility; major is for non-backwards compatible changes, minor for backward-compatible features, patch for backward-compatible bugfixes. Document it so your library users can express dependencies on your library correctly. Your snapshots are automated and don't have to increment these, except the first snapshot after a release because of the way prefixes are compared.

Purely for completeness, i will mention the old Apple standard for version numbers. This looks like major version. minor version. bug version. stage. non-release revision. Stage is a code drawn from the set d (development), a (alpha), b (beta), or fc (final customer ship - more or less the same as release candidate, i think).
The stage and non-release revision are only used for versions short of proper releases.
So, the first version of something might be 1.0.0. You might have released a bugfix as 1.0.1, a new version (with more features) as 1.1, and a rewrite or major upgrade as 2.0. If you then wanted to work towards 2.0.1, you might start with 2.0.1d1, 2.0.1d2, on to 2.0.1d153 or whatever it took you, then send out 2.0.1a1 to QA, and after they approved 2.0.1a37, send 2.0.1b1 to some willing punters, then after 2.0.1b9 survived a week in the field, burn 2.0.1fc1 and start getting signoffs. When 2.0.1fc17 got enough, it would become 2.0.1, and there would be much rejoicing.
This format was standardised enough that there was a packed binary format for it, and helper routines in the libraries for doing comparisons.

After reading a lot of articles/QAs/FAQs/books I become to think
that [MAJOR].[MINOR].[REV] is most useful versioning schema to
describe compatibility between project version (versioning schema
for developer, does not for marketing).
MAJOR changes is backward incompatible and require changing
project name, path to files, GUIDs, etc.
MINOR changes is backward compatible. Mark introduction of new
features.
REV for security/bug fixes. Backward and forward compatible.
This versioning schema inspired by libtool versioning semantics and by articles:
http://www106.pair.com/rhp/parallel.html
NOTE: I also recommend provide build/date/custom/quality as additional info (build
number, build date, customer name, release quality):
Hello app v2.6.34 for National bank, 2011-05-03, beta, build 23545
But this info is not versioning info!

Note that a version number scheme (like x.y.0 vs. x.y) can be constrained by external factors.
Consider that announcement for Git 1.9 (Januaury 2014):
A release candidate Git v1.9-rc2 is now available for testing at the usual places.
I've heard rumours that various third-party tools do not like the two-digit version numbers (e.g. "Git 2.0") and started barfing left and right when the users install v1.9-rc1.
While it is tempting to laugh at them for their sloppy assumption, I am also practical and
do not mind calling the upcoming release v1.9.0 to help them.
If we go that route (and I am inclined to go that route at this moment), the versioning scheme will be:
The next release candidate will be v1.9.0-rc3, not v1.9-rc3;
The first maintenance release for v1.9.0 will be v1.9.1 (and Nth one be v1.9.N); and
The feature release after v1.9.0 will be either v1.10.0 or v2.0.0, depending on how big the feature jump we are looking at.

Related

Excluding New Dependencies in Gradle File

I have an app that runs perfectly without new dependencies like this one:
A newer version of androidx.navigation:navigation-fragment-ktx than 2.4.2 is available: 2.5.0
If I upgrade to v.2.5.0, my app has warnings about unrelated elements like for example references to menu objects.
Should I wait and allow these Gradle warnings such as above notice until another upgrade comes along and try the new dependency then?
You shouldn't need to update anything unless you have a reason to. It's often a good idea (as well as new features you also get bug fixes) but it's usually not required. Specifying all your dependency versions means you get a repeatable build that should always work, so long as those versions are available
The thing about libraries is they often have dependencies on other libraries, and updating one might introduce a requirement for other stuff to be updated (which might be why you're seeing other errors appear. That broadly shouldn't happen (making things independently updateable is part of the reason for breaking everything out into separate libraries!) but here's a blog post from when they introduced it:
Starting with the AndroidX refactor, library versions have been reset from 28.0.0 to 1.0.0. Future updates will be versioned on a per-library basis, following strict semantic versioning rules where the major version indicates binary compatibility. This means, for example, that a feature may be added to RecyclerView and used in your app without requiring an update to every other library used by your app. This also means that libraries depending on androidx may provide reasonable guarantees about binary compatibility with future releases of AndroidX -- that a dependency on a 1.5.0 revision will still work when run against 1.7.0 but will likely not work against 2.0.0.
Really you have to look at the release notes for a library to see if there are any breaking changes you need to worry about. For example, here's the one for the Activity Jetpack component and if you search "dependency changes" you'll see where updating actually requires a specific minimum version of another thing
Also sometimes a library will pull in an old version of another library it depends on, so you might be explicitly interacting with a very old version of a component just because you never added it as a dependency yourself. Then if that first library requires a much newer version of that dependency, you might suddenly get a large jump that requires a bunch of changes to your code, even though it doesn't seem to have anything to do with what you updated!

Why do angular releated projects do not use semver 2.0 for prerelease tags?

A lot of angular related projects use a pre-release versioning scheme of the following:
e.g. angular-cli
1.0.0-beta.22,
1.0.0-beta.22-1,
1.0.0-beta.24
e.g. #angular/material
2.0.0-alpha.9
2.0.0-alpha.9-1,
2.0.0-alpha.9-2,
2.0.0-alpha.9-3,
2.0.0-alpha.10,
2.0.0-alpha.2.0.0-alpha.11,
2.0.0-alpha.11-1,
Due to the way semantic versioning works (dot separators, numeric always lower precedence to alphanumeric parts), 2.0.0-alpha.9-experimental-pizza is still the highest version for #angular/material, even tough 2.0.0-alpha.11 is released.
Similar for angular-cli, where 1.0.0-beta.22-1 is still the highest version, even though 1.0.0-beta.24 is released.
This causes package.json dependencies with ^ versions, e.g.
"angular-cli" : "^1.0.0-beta.22-1"
to not upgrade to 1.0.0-beta.24, because 24 is a numeric version and therefore smaller than 22-1.
I also posted this as an issue to the #angular/material issue tracker here but got no response.
Is this just an oversight, or am I missing something?
Update:
angular-cli now has versions
angular-cli#1.0.0-beta.25
angular-cli#1.0.0-beta.25.1
angular-cli#1.0.0-beta.25.2
angular-cli#1.0.0-beta.25.3
etc.
So it seems this was an oversight.
Short answer is that these are manual processes. The team hasn't invested in automating them yet. At least that's speaking for the Angular CLI, since I'm a contributor to the repository source code (but not a team member).
In pretty much all recent releases, something happened at the release, so they had to issue another version. Hence things like 1.0.0-beta.xx, has been quickly followed by 1.0.0-beta.xx-1.
Some tests are hard to run before publishing the packages. Especially for the CLI which publishes a range of packages not just one (a couple webpack plugins that the CLI uses are available as separate packages for other non-CLI seed projects to use).
Usually when the team is happy with a version, they explicitly tag it as latest, which is something npm allows publishers to do, so, you shouldn't in theory have this Angular Material alpha 9 vs alpha 11 problem, unless alpha 11 is not tagged as latest or something.
Long time later, I think it was an oversight in the alpha / betas. This is now resolved and angular projects follow semver also for the pre-release tags.

Variable name change bumps SemVer major or minor?

Lets say I have a function that can be called via an API like $MyFunction and for brevity $MyFunction returns 12. Now lets say I rename $MyFunction to $The12Function but it still returns the same result (in this example the integer 12). Does this warrant a bump to the major or minor SemVer version number?
One could argue that I am not allowing for backwards compatibility because $MyFunction no longer works. However, one could also argue that there is backwards compatibility because you can still return the same result via $The12Function.
From http://semver.org:
Given a version number MAJOR.MINOR.PATCH, increment the:
MAJOR version when you make incompatible API changes,
MINOR version when you add functionality in a backwards-compatible
manner, and
PATCH version when you make backwards-compatible bug fixes.
So, in your case, if you don't also maintain the old function name, in order to retain compatibility with older versions of the API you should increment the major version number.
One way to look at it, in order to know if compatibility is broken, would be to imagine that your API and functionality is encapsulated in a library which offers this functionality to other programs. You now make changes to that API. If the programs which linked to the old version of your API need to be changed in order to use the new version of your library, you have broken compatibility and the major version should be changed. You may solve this problem by overriding and maintaining the deprecated old function calls, but it would increase the complexity of the API.

Rules for incrementing patch number in semver

According to semver
"PATCH version when you make backwards-compatible bug fixes."
and
"A bug fix is defined as an internal change that fixes incorrect behavior."
With this in mind lets say I have a variable that can be called, like a color. And for some reason I need to change the color value.
v1.0.0
$color: #FFF;
v1.0.1
$color: #F0F0F0;
Now this is a variable that is defined in the API as something users can call. I haven't changed the actual variable that is called, only the value it returns. To do this I have to make a change to my code, on an API element, and I must merge this code into the production branch. But does something like this truly warrant incrementing the patch version number of your API?
The point of semantic versioning is to manage dependencies of software systems. Semantic versioning provides an organized specification to standardize this process in order to reliably track the state of these systems. As the specification states,
Once a versioned package has been released, the contents of that version MUST NOT be modified. Any modifications MUST be released as a new version.
If your changes affect the behaviour of your api (inputs or outputs) and require a release to be made then that release should be pegged to an appropriate version number. This will allow the users of the package to depend on your package with confidence. Each version will behave as expected; there should be no ambiguity.
As an example, let's say you make the change and release it but don't increment the patch number. You could potentially have two users who think they are using the same code but get different values when calling the $color api depending on when they acquired v1.0.0.
It's worth noting that there are different ways to approach getting this change to users depending on how you release your package. I can think of two possible cases:
If the package source is public, in early development of the package a quick change could be pushed to a development branch in which users could acquire changes at their own risk.
Alternatively, if the package is not open source, a pre-release could be made by appending an identifier to the version (see items 9 & 10 in the spec).
These are just a couple options. There may be others depending on your specific situation.
TL;DR Answer
Most importantly is that once v1.0.0 has been released, v1.0.0 should always behave the same way. Regardless of how trivial these changes may be they are still changes. This goes for all versions, X.Y.Z.

How to break a maven build when dependencies are out of date?

I love the maven-versions-plugin but sometimes I forget to run it for a while. Is there a way to make a maven build fail (and thus have a continuous build fail) when certain important dependencies are out of date?
I think you're approaching this incorrectly. Mail yourself the output of the maven-versions-plugin if you want, but don't fail the build due to changes outside of your control.
Even more, why would you want to needlessly update to the latest versions? I have seen many tricky problems appear due to upgrades which have brought slight changes to previous behaviour.
This, in general, is a bad practice - to update versions automatically. There is no practical reason of using the latest version of any package. If the library you're using satisfies your requirements you should stay with this version for security/stability reasons. And forever.
I think that maven-versions-plugin is an anti-pattern itself.
ps. When and if you want to do integration testing of modules developed by different teams/programmers, it is "integration testing". Even in this case I still think that on-fly version updating is the wrong approach. Root project should not do this integration testing, instead, every sub-module (or JAR, in your case), has to be responsible for integration testing of itself together with the rest of the system. When a sub-module increases its version it has to validate whether everything is still fine, and only then has to release a new version to the repository. And when the sub-module is doing the validation it has to be dependent on statically specified version numbers.