I am developing a Python package that I want to continuously deliver to artifactory. I also have a certain number of machines (my customers) with an automatized scheduled job using this package, as follows:
pip install --upgrade foo # Make sure to use the latest version delivered to artifactory
foo do_something # Then use the package
Let's say I discover that the latest version I delivered to artifactory contains a bug. Is there a way to perform a fallback seamlessly, i.e without having to intervene on the machines nor on the scheduled jobs to tell them which version of the package to use?
I was thinking of working with a 'latest'-tag-solution:
My customer would automatically use the latest working version without noticing that it has changed.
Unfortunately, I haven't found a way to use pip directly to target a specific version of a package based on a custom property like "latest" in JFrog Artifactory.
I can not think of one true blessed way to do this, but I can think of some ways you can probably get close enough (not knowing what the truth of the requirements of the project)...
One way could be to let pip install from a git branch. For example you could make it so that pip installs from a stable
branch, which you you would be free to move to any commit you want at any time.
Another possible solution I can think of, is to use some kind of dummy pip-installable package distributed on your package index server that would serve as some kind of indirection pointing to the true package. In this scenario the indirection package would contain no code but would declare one and only one pinned dependency on the true package. It could be that the true package follows semantic versioning, but I would recommend the indirection package to follow some kind of calendar-based versioning. You would be free to upload a new version of the indirection package at any time. For example bar 2023.01.01
(the indirection package) currently depends on foo==3.2.1
(the true package). A bug is discovered in foo 3.2.1
and you decide customers should fall back on foo 3.2.0
until you can fix the bug, in this case you could immediately distribute bar 2023.06.05
that depends on foo==3.2.0
, and pip install --upgrade bar && foo do_something
will do what you expect. One month later when foo 3.2.2
is ready with the bug fix, you could publish bar 2023.07.05
that depends on foo==3.2.2
.
Having a pinned dependency would give full control, but it is most likely not necessary. The indirection package could also declare a dependency such as foo >=3.2.0, !=3.2.1
, so that the 3.2.2
bugfix release would be automatically included.