Tuesday, May 27, 2014

Auto Semver Patching

I typically use a technique that I call Auto Semver Patching to automate the updating of dependencies without (much) fear of breaking running applications.

When you specify the dependency version, use the tilde "~" character and the full MAJOR.MINOR.PATCH number of the most recent version of the referenced library.

In package management parlance, the tilde "~" characters means, "equal to or greater than the last digit".

In the case of "bower": "~1.2.6" it is assumed that the latest version of bower at the time the build file was created is 1.2.6.

When subsequent builds are run, the package manager can upgrade the PATCH number indefinitely, ex: bower 1.2.999; However, the MINOR number may not be incremented, ex: bower 1.3.0 would be invalid.


If you have the following, incorrect, library version in your NPM package.json file...

"grunt-contrib-requirejs": "~0.3.5",

...and try to install, then currently you will get the following message:

$ npm install
npm ERR! notarget No compatible version found: grunt-contrib-requirejs@'>=0.3.5-0 <0.4.0-0'
npm ERR! notarget Valid install targets:
npm ERR! notarget ["0.1.0","0.2.0","0.3.0","0.3.2","0.3.3","0.3.4","0.4.0","0.4.1","0.4.2","0.4.3","0.4.4","0.4.0-rc7"]
npm ERR! notarget
npm ERR! notarget This is most likely not a problem with npm itself.
npm ERR! notarget In most cases you or one of your dependencies are requesting
npm ERR! notarget a package version that doesn't exist.

Note that "~0.3.5" literally means '>=0.3.5-0 <0.4.0-0'

Auto Semver Patching Examples

Entries from NodeJS's package.json file

  "devDependencies": {
    "bower": "~1.2.6",
    "grunt": "~0.4.1",
    "grunt-bower": "~0.7.0"

Entries from Bower's .bower.json file

  "dependencies": {
    "bootstrap-sass-official": "~3.1.0",
    "modernizr": "~2.6.2",
    "jquery": "~1.11.0"

Entries in Ruby Bundler

gem 'js-routes', '~> 0.9.7'
gem 'factory_girl', '~> 4.4.0'

Semantic Versioning

Semantic versioning is a set of rules that specify how you should version your software components.

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.

Minor Version

Minor version Y (x.Y.z | x > 0) MUST be incremented if new, backwards compatible functionality is introduced to the public API. It MUST be incremented if any public API functionality is marked as deprecated. It MAY be incremented if substantial new functionality or improvements are introduced within the private code. It MAY include patch level changes. Patch version MUST be reset to 0 when minor version is incremented.

Incrementing the minor version indicates that there is new or improved functionality that does not break existing interfaces.

So, if the component vendors adhere to the rules, then you should be able to allow your package manager to automatically update components using Auto Semver Patching without anything breaking.

The advantage of using Auto Semver Patching is that the dependencies will be at the latest version possible, which should pickup most urgent security patches and performance enhancements without breaking your application.

The disadvantage of of using Auto Semver Patching is that every time you run the package manager to update the dependencies, there may be a dependency component that has a bug or does not follow the rules and ends up breaking your application.

So, should you use this Auto Semver Patching technique?

As usual, It Depends. ™

  • Will your test suite robust enough to catch any bugs from the new, possibly broken dependencies?
  • Can you stop a package update, and revert back to working dependency versions, if a bug is detected?
  • How important is is that your application keep up to date on security patches and minor enhancements?

Words to the Wise

  • It is best practice to run a full regression test anytime you update underlying components.
  • Auto Semver Patching technique can help for a while, but it won't be long before you'll need to update to the latest major version of your libraries and their dependencies.

Package Managers that support Semantic Versioning

  • Ruby Bundler
  • NPM
  • Bower
  • Composer
  • CocoaPods



No comments:

Post a Comment