Skip to content

Commit

Permalink
feature: Add versioning support for images with prerelease identifiers (
Browse files Browse the repository at this point in the history
  • Loading branch information
balajisankar15 authored May 9, 2024
1 parent c9873bb commit 4e4b7f9
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 19 deletions.
37 changes: 23 additions & 14 deletions src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,12 @@ def _create_new_version_artifacts(args):
raise Exception()

base_patch_version = get_semver(args.base_patch_version)
if base_patch_version.prerelease:
# We don't support creating new patch/major/minor versions from a prerelease version
# Re-run the build command for the prerelease version again to pick the latest versions
# of the marquee packages
if base_patch_version.prerelease and args.pre_release_identifier:
# We support creating new patch/major/minor versions from a pre-release version.
# But We don't support passing the pre_release_identifier parameter while creating a new
# patch/major/minor versions from the pre-release version.
raise Exception()
next_version = getattr(base_patch_version, runtime_version_upgrade_func)()
next_version = _get_next_version(base_patch_version, runtime_version_upgrade_func)

if args.pre_release_identifier:
next_version = next_version.replace(prerelease=args.pre_release_identifier)
Expand Down Expand Up @@ -291,32 +291,41 @@ def _build_local_images(
return generated_image_ids, generated_image_versions


def _get_next_version(current_version: Version, upgrade_func: str) -> Version:
next_version = getattr(current_version, upgrade_func)()
if current_version.prerelease:
# Semver Ignores prerelease identifier when we do bump_{patch/minor/major}
next_version = next_version.replace(prerelease=current_version.prerelease)
return next_version


# At some point of time, let's say some patch versions exist for both 2.6 and 2.7, and we create new patch
# versions for both of them. Now, for the new 2.6.x, we can tag it as '2.6.x-cpu' and '2.6-cpu' but NOT '2-cpu' because
# there is a more recent version (i.e. 2.7.x) that should be considered '2-cpu'. So, given a patch version, the
# following function returns a list of versions for which the current patch version is latest for.
# For versions with pre-release identifier, this method will return the appropriate tags
# Example: For an version 2.0.0-beta, this method will return [2.0.0-beta, 2.0-beta, 2-beta,
# latest-beta]
def _get_version_tags(target_version: Version, env_out_file_name: str) -> list[str]:
# First, add '2.6.x' as is.
res = [str(target_version)]
# If this is a pre-release version, then don't add additional tags
if target_version.prerelease:
return res
prerelease_version_suffix = f"-{target_version.prerelease}" if target_version.prerelease else ""

# If we were to add '2.6', check if '2.6.(x+1)' is present.
if not is_exists_dir_for_version(target_version.bump_patch(), env_out_file_name):
res.append(f"{target_version.major}.{target_version.minor}")
if not is_exists_dir_for_version(_get_next_version(target_version, "bump_patch"), env_out_file_name):
res.append(f"{target_version.major}.{target_version.minor}{prerelease_version_suffix}")
else:
return res

# If we were to add '2', check if '2.7' is present.
if not is_exists_dir_for_version(target_version.bump_minor(), env_out_file_name):
res.append(str(target_version.major))
if not is_exists_dir_for_version(_get_next_version(target_version, "bump_minor"), env_out_file_name):
res.append(f"{target_version.major}{prerelease_version_suffix}")
else:
return res

# If we were to add 'latest', check if '3.0.0' is present.
if not is_exists_dir_for_version(target_version.bump_major(), env_out_file_name):
res.append("latest")
if not is_exists_dir_for_version(_get_next_version(target_version, "bump_major"), env_out_file_name):
res.append(f"latest{prerelease_version_suffix}")

return res

Expand Down
40 changes: 35 additions & 5 deletions test/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,13 +169,13 @@ def test_get_semver_version():

def test_new_version_artifacts_for_an_input_prerelease_version():
input_version = "1.23.0-beta"
args = CreateVersionArgs("patch", input_version)
args = CreateVersionArgs("patch", input_version, pre_release_identifier="new-beta")
with pytest.raises(Exception):
create_patch_version_artifacts(args)
args = CreateVersionArgs("minor", input_version)
args = CreateVersionArgs("minor", input_version, pre_release_identifier="new-beta")
with pytest.raises(Exception):
create_minor_version_artifacts(args)
args = CreateVersionArgs("major", input_version)
args = CreateVersionArgs("major", input_version, pre_release_identifier="new-beta")
with pytest.raises(Exception):
create_major_version_artifacts(args)

Expand Down Expand Up @@ -528,8 +528,38 @@ def test_get_version_tags(mock_path_exists):
# case 4.2 The patch version is not a prerelease version
mock_path_exists.side_effect = [True, True]
assert _get_version_tags(version, file_name) == ["1.124.5"]
# case 5: The given version includes a prerelease identifier
assert _get_version_tags(get_semver("1.124.5-beta"), file_name) == ["1.124.5-beta"]


@patch("os.path.exists")
def test_get_version_tags_with_prerelease_identifier(mock_path_exists):
version = get_semver("1.124.5-beta")
file_name = "cpu.env.out"
# case 1: The given version is the latest for patch, minor and major
mock_path_exists.side_effect = [False, False, False]
assert _get_version_tags(version, file_name) == ["1.124.5-beta", "1.124-beta", "1-beta", "latest-beta"]
# case 2: The given version is the latest for patch, minor but not major
# case 2.1 The major version is a different prerelease version
mock_path_exists.side_effect = [False, False, True, False]
assert _get_version_tags(version, file_name) == ["1.124.5-beta", "1.124-beta", "1-beta", "latest-beta"]
# case 2.2 The major version is not a prerelease version
mock_path_exists.side_effect = [False, False, True, True]
assert _get_version_tags(version, file_name) == ["1.124.5-beta", "1.124-beta", "1-beta"]
# case 3: The given version is the latest for patch and major but not for minor
# case 3.1 The minor version is a prerelease version (we need to mock path.exists for major
# version twice - one for the actual directory, one for the docker file)
mock_path_exists.side_effect = [False, True, False, True, True]
assert _get_version_tags(version, file_name) == ["1.124.5-beta", "1.124-beta", "1-beta"]
# case 3.2 The minor version is not a prerelease version
mock_path_exists.side_effect = [False, True, True]
assert _get_version_tags(version, file_name) == ["1.124.5-beta", "1.124-beta"]
# case 4: The given version is not the latest for patch, minor, major
# case 4.1 The patch version is a prerelease version (we need to mock path.exists for minor
# and major twice - one for the actual directory, one for the docker file)
mock_path_exists.side_effect = [True, False, True, True, True, True]
assert _get_version_tags(version, file_name) == ["1.124.5-beta", "1.124-beta"]
# case 4.2 The patch version is not a prerelease version
mock_path_exists.side_effect = [True, True]
assert _get_version_tags(version, file_name) == ["1.124.5-beta"]


def _test_push_images_upstream(mocker, repository):
Expand Down

0 comments on commit 4e4b7f9

Please sign in to comment.