Versioning

From ProgClub
Jump to: navigation, search

OK, here's the spec for how version numbers should be managed across ProgClub projects (from now on).

Semantic versioning

We will endeavour to be compatible with Semantic Versioning (v2.0.0 at time of writing). Thus, this specification is a superset of the SemVer spec.

Specification

So our semantic versioning format is: MAJOR.MINOR.PATCH[-BUILD.REVISION]

For information about how to model/store version information in your code see software constants below.

MAJOR version

The first MAJOR version number is zero (0). Version zero is a development version and breaking changes are allowed. The first stable version has major version one (1). After a breaking change the MAJOR version number increments. So major versions are: 0, 1, 2, 3, and so on.

MINOR version

The first MINOR version number is one (1). So 0.1 is the first version. There is no 0.0 version.

When the MAJOR version is incremented the MINOR version is reset to 0, so the new version would be e.g. 1.0, and so on.

Please don't use leading zeros on the MINOR version.

PATCH number

Our PATCH number begins and zero (0) and increments for each non-breaking change for software maintenance (generally a security patch). The PATCH number is reset to zero (0) when the MINOR version increments.

BUILD indicator

Our BUILD is one of, e.g. 'dev', 'test', 'alpha', 'beta', 'prod', etc. The BUILD is specified in the config file, not in the software. If the BUILD is unspecified the BUILD.REVISION component of the version number is omitted. When there is no BUILD.REVISION the software is an officially released version.

Build codes

OK, so at the moment supported build codes are:

dev software is under development
test software is running unit tests
alpha pre-release software (never actually used it!)
beta initial release for testing
rc-1 release candidate one
rc-2 release candidate two (and so on)
prod software is running in production but interface might not be stable
N/A when there is no build type the software is released at the indicated version

REVISION number

Our REVISION is the Subversion revision number of the software. The REVISION is calculated by running 'svn info' and retrieving the 'Revision:' value. The 'svn info' command can be run at install time with the REVISION stored in the config file, or if there is no setting in the config file then 'svn info' can be run at runtime. If the REVISION cannot be determined it is zero.

Implementation

Subversion integration

Our MAJOR.MINOR component will be resident in the Subversion path, e.g. project/branches/3.0 for MAJOR.MINOR version 3.0. For a release we will indicate a PATCH number for the release script (note: as of Feb 2017 the release script calls the 'patch' number a 'revision' number, because it's a carry over from an old process).

So the MAJOR, MINOR, and PATCH numbers are in Subversion. BUILD and RELEASE numbers are not in Subversion, they must be provided in configuration files shipped with a release (or not, in which case it becomes the responsibility of the system administrator to make sure the software is properly configured to indicate its BUILD/REVISION). Note: if the BUILD/REVISION are not specified they are assumed to be irrelevant, and for production/stable releases this is what we want. So only development and testing versions need to configure BUILD and REVISION...

Software constants

So minimally we'd have:

define( 'VERSION_MAJOR', 3 );
define( 'VERSION_MINOR', 0 );
define( 'VERSION_PATCH', 0 );
define( 'VERSION_BASE', VERSION_MAJOR . '.' . VERSION_MINOR . '.' . VERSION_PATCH );

The above four constants are "hard coded" into the software by the developer. It's the developer's responsibility to ensure that the values are correct and in sync with the project branch name in the repository.

Then we'd need to load our config file, which may have a BUILD type, e.g.:

define( 'VERSION_BUILD', 'dev' );

There might also be a REVISION in the config file, e.g.:

define( 'VERSION_REVISION', 1234 );

After loading the config file the full version must be calculated. E.g.:

if ( defined( 'VERSION_BUILD' ) ) {

  if ( ! defined( 'VERSION_REVISION' ) ) {

    // note: parse_svn_info_revision() returns zero on error
    define( 'VERSION_REVISION', parse_svn_info_revision() );

  }

  define( 'VERSION', VERSION_BASE . '-' . VERSION_BUILD . '.' . VERSION_REVISION );

}
else {

  define( 'VERSION', VERSION_BASE );

}

Conclusion

Happy days!

p.s. If your program is just an application you can use constants such as VERSION_MAJOR, VERSION, etc. If your program is a library you should scope your constants, e.g. PHPBOM_VERSION_MAJOR, PHPBOM_VERSION, etc.

p.p.s. If your programming language doesn't allow for generation of constants at runtime, you will need to model the BUILD and REVISION values some other way. E.g. as global variables, static variables in accessor functions, etc.