Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automating transplanting version in code #437

Merged
merged 58 commits into from Sep 21, 2020

Conversation

Hedingber
Copy link
Contributor

@Hedingber Hedingber commented Sep 12, 2020

Background:
We don't want users to have to change their code with each new version of MLRun, therefore we let them set their jobs images untagged (e.g. mlrun/mlrun), and MLRun API enrich the image with tag (e.g. mlrun/mlrun:0.5.2).
For this to work MLRun code need to be aware of its version.
So far this version was hard coded so we had to change it when we release.
Also between releases we were hard coding it to unstable so that it will be possible to work with the "unstable version".

Requirements we had:

  1. Hard coding this whole thing is a lot of mess, it requires a bump commit before releasing, and setting back to unstable after releasing, we would prefer something less manual and more automated.
  2. We wanted to start using per-commit builds, e.g. unstable-<commit-hash> (currently this is for the system tests), in order for a commit builds to be a "version" the code inside the API need to be aware of that, we can't do manual bump commit per commit.
  3. Currently those per-commit builds will be pushed only to Github Container registry - we need to add logic to the API to enrich the docker registry (in addition to the tag) + we need a way to configure that registry on runtime
  4. It would be nice if beside of the version we will have info about the specific commit

Decisions & Solution:

  • Moved the version info outside of the code to a version.json file - currently looks like:
{
  "git_commit": "889e8bca5472cefa3290fed4218d0e8ad53fd6c7",
  "version": "unstable"
}
  • Removed some duplications with images enrichment + added registry enrichment
  • Added a script that override this file, some usage examples:
# can run with no inputs, this will just update the git commit and use defaults for the rest
python ./automation/version/run.py run 
make update-version-file
# with inputs
python ./automation/version/run.py run 0.5.2 
MLRUN_VERSION=0.5.2 make update-version-file
  • Added the update-version-file makefile target as a dependency of each targets that builds something, i.e. all images targets + package building target
  • The only exceptional case (I can think of) in which the version won't be set correctly is when a user (probably a developer) doing something like:
    pip install git+https://github.com/mlrun/mlrun@development - The problem here is that this is basically installing an un-built version - straight from the source code, I tried to play a little bit with git hooks and stuff to check maybe we can make sure the version.json is getting automatically updated in every commit, but this is a bit of chicken and egg - the commit id is based on some checksum of the contents, and putting the id in the version.json file changing the contents...
    so I decided that by default (sitting in two places, setup.py and version.py I'll return these values:
{
  "git_commit": "unknown",
  "version": "unstable"
}

Copy link
Member

@quaark quaark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, just a couple of things

with:
python-version: 3.7
- name: Install automation scripts dependencies
run: pip install click
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is now an automation directory, and scripts there have their own independent requirements, maybe we should have a requirements.txt in that dir and install it here with -r instead of adding another requirement here every time we'll need too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

definitely

with:
python-version: 3.7
- name: Install automation scripts dependencies
run: pip install click
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same ^

setup.py Outdated
Comment on lines 22 to 26
with open("version.json") as version_file:
for line in version_file:
if '"version"' in line:
# ' "version": "<version>",' -> [' ', 'version', ': ', '<version>', ',']
return line.split('"')[3]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think doing this here will be safer code:

with open("version.json") as version_file:
    try:
        version_metadata = json.load(version_file)
        return version_metadata['version']
    except (ValueError, KeyError):
        return None

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is json. parse it as such
Also if possible (without circular import issues) to bring in a logger here and output something in case of error inferring the version - it might be very useful, otherwise missing version information will be hard to debug

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tl;dr - json yes, logger no
I was thinking that it is impossible to import stuff in setup.py cause it's running before installation (before installing the requirements) but apparently it is possible using the pyproject.toml file (https://www.python.org/dev/peps/pep-0518/#build-system-table), also I wasn't aware but apparently anyway json is part of the standard library so need to pre-install anything. w.r.t. logger, it is impossible, I can't use the package here, because it is not installed yet

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logger is python standard library :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, thought you meant MLRun logger, added

version.json Outdated
@@ -0,0 +1,5 @@
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you added this file to .gitignore yet it is still tracked here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably added it by accident before putting it in .gitignore

Copy link
Contributor Author

@Hedingber Hedingber Sep 15, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did it purposely, from the PR description:

and also the file will be committed to git but added to .gitignore.

why ?
I want to commit the file so it will have some sane defaults, I add it to git ignore so people won't have un-comitted changed everytime they do make api (or any other build)

Copy link
Contributor Author

@Hedingber Hedingber Sep 20, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apparently this does not behave as I thought, as soon as the file is in the tree, git will track its changes even if its in .gitignore.
Removing from .gitignore for now

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Hedingber - As per the purpose of this file - it should not be tracked from a correctness point of view. I'm not sure what you mean by sane defaults but they can be in the parsing code, in the absence of this file if you must

@Hedingber
Copy link
Contributor Author

Talked offline with @omesser and decided to remove the docker registry from the version file.
MLRun-wise it's easy to override the registry on runtime, simply adding the MLRUN_IMAGES_REGISTRY env var.
Iguazio-wise (also CI-wise) I will introduce some changes in the helm chart so we will be able to easily set that on a system

Copy link
Member

@quaark quaark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Only a couple of styling and grammar issues in comments/doc strings. Otherwise, the code looks good.

mlrun/config.py Outdated
@@ -166,6 +186,11 @@ def _do_populate(env=None):
if data:
config.update(data)

# HACK to enable kfp_image property to both have dynamic default and to have use the value from dict/env like
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# HACK to enable kfp_image property to both have dynamic default and to have use the value from dict/env like
# HACK to enable kfp_image property to both have dynamic default and to use the value from dict/env like

mlrun/config.py Outdated
Comment on lines 142 to 146
"""
When this configuration is not set we want to set it to mlrun/mlrun but we need to use the enrich_image method
The problem is that the mlrun.utils.helpers module is importing the config (this) module, so we must calculate
this property value here (and not initalization) and import inside
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"""
When this configuration is not set we want to set it to mlrun/mlrun but we need to use the enrich_image method
The problem is that the mlrun.utils.helpers module is importing the config (this) module, so we must calculate
this property value here (and not initalization) and import inside
"""
"""
When this configuration is not set we want to set it to mlrun/mlrun, but we need to use the enrich_image method.
The problem is that the mlrun.utils.helpers module is importing the config (this) module, so we must import the module inside this function (and not on initalization), and then calculate this property value here.
"""

mlrun/config.py Show resolved Hide resolved
mlrun/config.py Show resolved Hide resolved
mlrun/utils/version/version.py Show resolved Hide resolved
setup.py Show resolved Hide resolved
@Hedingber Hedingber merged commit 33aef35 into mlrun:development Sep 21, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants