So recently we've begun getting CI failures because a newer version of pip
started enforcing the standard in a strict manner. So after digging into https://peps.python.org/pep-0440/#local-version-identifiers We were able to implement the following strategy:
Main Branch
The main branch yields a package with a regular semantic version e.g: 1.2.3
.
Develop Branch
This branch gets 1.2.3.dev1
, note the 1
instead of 0
in the suffix, I'll explain that in a moment.
Feature Branch
Any feature branch coming from dev
, say feature/improve-logs
gets 1.2.3.dev0+feature.improve.logs
.
The local identifier, as stated in PEP-440:
To ensure local version identifiers can be readily incorporated as part of filenames and URLs, and to avoid formatting inconsistencies in hexadecimal hash representations, local version labels MUST be limited to the following set of permitted characters:
- ASCII letters ([a-zA-Z])
- ASCII digits ([0-9])
- periods (.)
Local version labels MUST start and end with an ASCII letter or digit.
dev1 > dev0
Any developer that wishes to use the artifact from dev
, states his requirement as follows:
my-library==1.2.3.dev1
This way, no other feature artifact ending with dev0+something
will sneak accidentally into his environment. It's not uncommon for us to have 2 features being developed at the same time.
Whereas, a developer that wants to test a specific artifact created from a feature branch will state the full name:
my-library=1.2.3.dev0+feature.improve.logs
Tagging
The whole tagging process happens in the CI, we have a plain text VERSION
file to which we append the right suffix after formatting it (replacing /
to .
etc...)