I’ve just written up a piece at InfoQ on how OSGi have abandoned -SNAPSHOT versions, and I thought I’d take a minute to explain what I meant by the ‘human tooling’ problem.
The issue is whether or not SNAPSHOTs shold be built in a ‘lower’ numerical
namespace using 1.2.3-456
which sorts less than 1.2.3
. By encouraging
a difference between ‘unreleased’ and ‘released’ versions, it becomes clear
whether there are changes which are important, and allows developers to report
bugs against a specific version (instead of just ‘the latest version’).
According to both the Semantic Versioning and the Eclipse Version Numbering rules, the patch number (third segment) should be changed whenever there is a difference between build artefacts. As I’ve listed on the InfoQ article, that plainly doesn’t happen in some cases:
- org.eclipse.cdt.codan.checkers.ui_1.0.0.201109151620.jar
- org.eclipse.cdt.codan.checkers.ui_1.0.0.201202111925.jar
- org.eclipse.core.filebuffers_3.5.200.v20110505-0800.jar
- org.eclipse.core.filebuffers_3.5.200.v20110928-1504.jar
- org.eclipse.core.variables_3.2.500.v20110511.jar
- org.eclipse.core.variables_3.2.500.v20110928-1503.jar
- org.eclipse.emf.ecore_2.7.0.v20110912-0920.jar
- org.eclipse.emf.ecore_2.7.0.v20120127-1122.jar
- org.eclipse.equinox.frameworkadmin.equinox_1.0.300.v20110506.jar
- org.eclipse.equinox.frameworkadmin.equinox_1.0.300.v20110815-1438.jar
- org.eclipse.equinox.p2.updatesite_1.0.300.v20110510.jar
- org.eclipse.equinox.p2.updatesite_1.0.300.v20110815-1419.jar
- org.eclipse.jdt.compiler.tool_1.0.100.v_B76_R37x.jar
- org.eclipse.jdt.compiler.tool_1.0.100.v_B79_R37x.jar
- org.eclipse.jface_3.7.0.I20110522-1430.jar
- org.eclipse.jface_3.7.0.v20110928-1505.jar
- org.eclipse.ltk.core.refactoring_3.5.201.r371_v20110824-0800.jar
- org.eclipse.ltk.core.refactoring_3.5.201.r372_v20111101-0700.jar
- org.eclipse.pde.runtime_3.4.201.v20110819-0851.jar
- org.eclipse.pde.runtime_3.4.201.v20110928-1516.jar
- org.eclipse.ui_3.7.0.I20110602-0100.jar
- org.eclipse.ui_3.7.0.v20110928-1505.jar
The point of showing the cross-section of the above is not to highlight
specific projects, but to show this is a widespread problem that goes
across all projects. The problem is, there is no ‘penalty’ for leaving a
1.2.3.qualifier
as the Manifest entry and just spinning out builds with
new build qualifiers in place.
The key advantage of having a different version numbering format between release versions and pre-release versions is to ensure that at release, the version number is updated appropriately. This means that the development process generally follows:
- Create 1.0.0-SNAPSHOT for development
- Do work
- Release 1.0.0
- Update version to 1.0.1-SNAPSHOT
- Do work
- Release 1.0.1 or 1.1.0 (or 2.0.0) as appropriate
- goto 10
The decision as to what to call the next number can either be tracked by updates to the -SNAPSHOT itself (e.g. moving to 1.1.0-SNAPSHOT) or can be deferred to later in the process. There’s even tooling to help you do that (the mvn release plugin) – though this just removes the -SNAPSHOTS for you rather than doing any semantic analysis.
This pattern is so common that it’s even codified as a bullet point in the Semantic Versioning specification:
A pre-release version MAY be denoted by appending a dash and a series of dot separated identifiers immediately following the patch version. Identifiers MUST be comprised of only ASCII alphanumerics and dash [0-9A-Za-z-]. Pre-release versions satisfy but have a lower precedence than the associated normal version. Examples: 1.0.0-alpha, 1.0.0-alpha.1, 1.0.0-0.3.7, 1.0.0-x.7.z.92.
The ‘pre-release versions satisfy but have a lower precedence than’ sums
up the rule in a nutshell: in other words, anywhere a 1.2.3 is valid then
all 1.2.3-* are valid as well; anywhere a 1.2.3 is not valid then
all 1.2.3-* are not valid. So, in a range like [1.2.3,4.5.6)
then any
pre-release state of 1.2.3-* is included, but any pre-release state of
4.5.6-* is not included.
This was even implemented successfully in Equinox, with an implementation in 3.8M6.
Unfortunately, the concerns listed by the CPEG were out of touch with how developers work outside of the OSGi space, and instead of reaching out with a mechanism which would have been compatible for released artifacts (whilst providing a SNAPSHOT style build system that would not be loadable on older OSGi runtimes) it has been removed from the specification. Given that OSGi R5 is a major release of the runtime, this would have been the ideal time for introducing a new version syntax, and one that would have been quickly adopted elsewhere.
So instead of having ‘memorable’ artifact names like org.eclipse.ui_3.7.0.jar
we’ll be stuck with unmemorable names like
org.eclipse.ui_3.7.0.v20110928-1505.jar
for the forseeable future in
the OSGi world. This causes more cognitive work for humans (trying to
remember the name) whilst introducing more opportunity for mistakes (by
releasing the same major/minor/patch with different builds).
This is what I refer to as humans solving the tooling problem, rather than the other way around.