Versioning
OK, here's the spec for how version numbers should be managed across ProgClub projects. It is highly recommended that you use svnman to help manage version numbers for ProgClub projects.
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 release version has major version one (1). Version one is the first generally available version and breaking changes are allowed. The first stable version has major version two (2). After version two any breaking changes require that 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 at one (1) and increments by two (2) upon each commit. The PATCH number is not reset after MAJOR or MINOR version bumps, its value is inherited from the value it was immediately prior to the version bump. Before a project is released the PATCH is incremented by one (1), and after a release it is again incremented by one (1). This means that the PATCH version number has the property of being odd for development builds and even for release builds (also called production builds).
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.
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.