Versioning

Python packaging tools do not enforce a specific versioning pattern. The version field can be any string. This freedom became a problem, because projects followed their own versioning schemes and, sometimes, they were not compatible with installers and tools.

To understand a versioning scheme, an installer needs to know how to sort and compare versions. The installer needs to be able to parse the string, and know if a version is older than another one.

Early software used schemes based on the date of release, like 20170101 if your software is released on 1st January 2017. But that scheme won't work anymore if you do branch releases. For instance, if your software has a version 2, which is backward incompatible, you might start to release updates for version 1 in parallel of releases for version 2. In that case, using dates will make some of your version 1 releases appear as if they were more recent than some version 2 release.

Some software combine incremental versions and dates for that reason, but it became obvious that using dates was not the best way to handle branches.

And then, there's the problem of beta, alpha, release candidates, and dev versions. Developers want to have the ability to mark releases as being pre-releases.

For instance, when Python is about to ship a new version, it will ship release candidates using a rcX marker so that the community can try it before the final release is shipped. For example 3.6.0rc1, 3.6.0rc2, and so on.

For a microservice that you are not releasing to the community, using such markers is often an overkill--but when you start to have people from outside your organization using your software, it may become useful.

Release candidates can be useful, for example, if you are about to ship a backward incompatible version of a project. It's always a good idea to have your users try it out before it's published. For the usual release though, using candidate releases is probably an overkill, as publishing a new release when a problem is found is cheap.

PIP does a fairly good job at figuring out most patterns, ultimately falling back to some alphanumeric sorting, but the world would be a better place if all projects were using the same versioning scheme.

PEP 386, and then 440, were written to try to come up with a versioning scheme for the Python community. It's derived from the standard MAJOR.MINOR[.PATCH] scheme, which's widely adopted among developers, with some specific rules for pre- and post- versions.

The Semantic Versioning (SemVer) (http://semver.org/) scheme is another standard that emerged in the community, which is used in many places outside Python. If you use SemVer, you will be compatible with PEP 440 and the PIP installer as long as you don't use pre-release markers. For instance, ;3.6.0rc2 translates to 3.6.0-rc2 in SemVer.

Unlike PEP 440, SemVer asks that you always provide the three version numbers. For instance, ;1.0 should be 1.0.0.

Adopting SemVer is a good idea as long as you remove the dash it uses to separate the version from a marker.

Here's an example of a sorted list of versions for a project that will work in Python, and which will be close to SemVer:

  • 9.0
  • 0.0a1
  • 0.0a2
  • 0.0b1
  • 0.0rc1
  • 0.0
  • 1.0

For your microservice project, or any Python project for that matter, you should start with the 0.1.0 version, make it clear that it's still an unstable project, and that backward compatibility is not guaranteed. From there, you can increment the MINOR number at will until you feel the software is mature enough.

Once maturity has been reached, a common pattern is to release 1.0.0, and then start to following these rules:

  • MAJOR is incremented when you introduce a backward incompatible change for the existing API
  • MINOR is incremented when you add new features that don't break the existing API
  • PATCH is incremented just for bug fixes

Being strict about this scheme with the 0.x.x series when the software is in its early phase does not make much sense, because you will do a lot of backward incompatible changes, and your MAJOR version would reach a high number in no time.

The 1.0.0 release is often emotionally charged for developers.
They want it to be the first stable release they'll give to the world--that's why it's frequent to use the 0.x.x versions and bump to 1.0.0 when the software is deemed stable.

For a library, what we call the API are all the public and documented functions and classes one may import and use.

For a microservice, there's a distinction between the code API and the HTTP API. You may completely change the whole implementation in a microservice project and still implement the exact same HTTP API. You need to treat those two versions distinctly.

Both versions can follow the pattern described here, but one version will be on your setup.py (the code) and one may be published in your Swagger specification file, or wherever you document your HTTP API. The two versions will have a different release cycle.

Now that we know how to deal with version number, let's do some releasing.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset