From 9e0670190c69ef7e04849974b48039561d684d27 Mon Sep 17 00:00:00 2001 From: Ian Tewksbury Date: Thu, 11 Nov 2021 07:51:54 -0500 Subject: [PATCH] generate-metadata.SemanticVersion - update to include 'build' portion of semvar in container image tags using '_' instead of '+' since '+' isn't supported by container image tag syntax but not having the 'build' porition of the version on the tag can cause tags to unexpectadly get overwritten/lost if major.minor.patch isn't updated by applciation devs --- .../generate_metadata/semantic_version.py | 60 ++++++++------- ...test_semantic_version_generate_metadata.py | 74 +++++++++++++++++-- 2 files changed, 103 insertions(+), 31 deletions(-) diff --git a/src/ploigos_step_runner/step_implementers/generate_metadata/semantic_version.py b/src/ploigos_step_runner/step_implementers/generate_metadata/semantic_version.py index e9f3fdcf..342f9fc0 100644 --- a/src/ploigos_step_runner/step_implementers/generate_metadata/semantic_version.py +++ b/src/ploigos_step_runner/step_implementers/generate_metadata/semantic_version.py @@ -37,30 +37,35 @@ * runtime configuration * previous step results -Configuration Key | Required? | Default | Description ---------------------------------------|-----------|---------|----------- -`app-version` | Yes | | Value to use for `version` portion of semantic version (https://semver.org/). \ - EX: `` -`is-pre-release` | Yes | `False` | If `True` then will add any relevant `pre-release` identifiers to semantic version (https://semver.org/), \ - such as the branch name. \ - If `False` then assumed to be a release build and all `pre-release` identifiers will \ - be ignored from version as per the semantic version spec (https://semver.org/). -`branch` | No | | If `is-pre-release` is `True`, value to use for a pre-release name in pre-release poriton of semantic version (https://semver.org/). \ - EX: `-` -`workflow-run-num` | No | | If `is-pre-release` is `True`, value to use for a numeric identifier of the branch `pre-release` identifier if provided. \ - Also always used in build identifier. \ - Since this can be included in the pre-release section, it should be incremental as per the sem version spec. - EX (pre-release): `-.+.`
\ - EX (release): `+.` -`sha` | No | | Value to use for sha build identifier in build portion of semantic version. \ - EX: `+` -`sha-build-identifier-length` | No | 7 | Trim the given `sha` down to this length when including as build identifier in semantic version -`additional-pre-release-identifiers` | No | | If `is-pre-release` is `True`, additional `pre-release` identifiers to add to semantic version (https://semver.org/). \ - Ignored if `is-pre-release` is `False. \ - EX (pre-release): `-.-+.` -`additional-build-identifiers` | No | | Additional `build` identifiers to add to semantic version (https://semver.org/). \ - EX (pre-release): `-.+..`
\ - EX (release): `+..` +Configuration Key | Required? | Default | Description +----------------------------------------|-----------|---------|----------- +`app-version` | Yes | | Value to use for `version` portion of semantic version (https://semver.org/). \ + EX: `` +`is-pre-release` | Yes | `False` | If `True` then will add any relevant `pre-release` identifiers to semantic version (https://semver.org/), \ + such as the branch name. \ + If `False` then assumed to be a release build and all `pre-release` identifiers will \ + be ignored from version as per the semantic version spec (https://semver.org/). +`branch` | No | | If `is-pre-release` is `True`, value to use for a pre-release name in pre-release poriton of semantic version (https://semver.org/). \ + EX: `-` +`workflow-run-num` | No | | If `is-pre-release` is `True`, value to use for a numeric identifier of the branch `pre-release` identifier if provided. \ + Also always used in build identifier. \ + Since this can be included in the pre-release section, it should be incremental as per the sem version spec. + EX (pre-release): `-.+.`
\ + EX (release): `+.` +`sha` | No | | Value to use for sha build identifier in build portion of semantic version. \ + EX: `+` +`sha-build-identifier-length` | No | 7 | Trim the given `sha` down to this length when including as build identifier in semantic version +`additional-pre-release-identifiers` | No | | If `is-pre-release` is `True`, additional `pre-release` identifiers to add to semantic version (https://semver.org/). \ + Ignored if `is-pre-release` is `False. \ + EX (pre-release): `-.-+.` +`additional-build-identifiers` | No | | Additional `build` identifiers to add to semantic version (https://semver.org/). \ + EX (pre-release): `-.+..`
\ + EX (release): `+..` +`container-image-tag-build-deliminator` | Yes | `_` | Unfortunately the container image tag spec does not allow for the `+` character which means can not follow \ + strict semver syntax when including the `build` portion of the semver in the image tag. \ + The value here is used instead of the `+` for the purposes of container image tags. \ + NOTE: the default `_` is chosen because it is otherwise not a valid character in semver syntax so if doing parsing \ + against the standard semver spec/regex it is simple enough to swap the `+` for a `_` and still get accurate results. Result Artifacts ---------------- @@ -82,12 +87,14 @@ DEFAULT_CONFIG = { 'is-pre-release': False, - 'sha-build-identifier-length': 7 + 'sha-build-identifier-length': 7, + 'container-image-tag-build-deliminator': '_' } REQUIRED_CONFIG_OR_PREVIOUS_STEP_RESULT_ARTIFACT_KEYS = [ 'app-version', - 'is-pre-release' + 'is-pre-release', + 'container-image-tag-build-deliminator' ] class SemanticVersion(StepImplementer): # pylint: disable=too-few-public-methods @@ -155,6 +162,7 @@ def _run_step(self): build = self.__get_semantic_version_build() if build: version += f'+{build}' + image_tag += f"{self.get_value('container-image-tag-build-deliminator')}{build}" # add artifacts step_result.add_artifact( diff --git a/tests/step_implementers/generate_metadata/test_semantic_version_generate_metadata.py b/tests/step_implementers/generate_metadata/test_semantic_version_generate_metadata.py index adfaf60f..54f36e80 100644 --- a/tests/step_implementers/generate_metadata/test_semantic_version_generate_metadata.py +++ b/tests/step_implementers/generate_metadata/test_semantic_version_generate_metadata.py @@ -35,7 +35,8 @@ def test_step_implementer_config_defaults(self): defaults = SemanticVersion.step_implementer_config_defaults() expected_defaults = { 'is-pre-release': False, - 'sha-build-identifier-length': 7 + 'sha-build-identifier-length': 7, + 'container-image-tag-build-deliminator': '_' } self.assertEqual(defaults, expected_defaults) @@ -43,7 +44,8 @@ def test__required_config_or_result_keys(self): required_keys = SemanticVersion._required_config_or_result_keys() expected_required_keys = [ 'app-version', - 'is-pre-release' + 'is-pre-release', + 'container-image-tag-build-deliminator' ] self.assertEqual(required_keys, expected_required_keys) @@ -139,7 +141,7 @@ def test_app_version_and_build(self, mock_build, mock_pre_release): ) expected_step_result.add_artifact( name='container-image-tag', - value='0.42.1', + value='0.42.1_mock1', description='Constructed semenatic version without build identifier' \ ' since not compatible with container image tags' ) @@ -160,7 +162,69 @@ def test_app_version_and_build(self, mock_build, mock_pre_release): ) expected_step_result.add_evidence( name='container-image-tag', + value='0.42.1_mock1', + description='semenatic version without build identifier' \ + ' since not compatible with container image tags' + ) + + self.assertEqual(actual_result, expected_step_result) + mock_pre_release.assert_not_called() + mock_build.assert_called_once() + + def test_app_version_and_build_custom_container_image_tag_build_deliminator(self, mock_build, mock_pre_release): + # setup + step_config = { + 'app-version': '0.42.1', + 'container-image-tag-build-deliminator': '_-_' + } + step_implementer = self.create_step_implementer( + step_config=step_config, + step_name='generate-metadata', + implementer='SemanticVersion' + ) + + # setup mocks + mock_build.return_value = 'mock1' + mock_pre_release.return_value = None + + # run test + actual_result= step_implementer._run_step() + + # verify results + expected_step_result = StepResult( + step_name='generate-metadata', + sub_step_name='SemanticVersion', + sub_step_implementer_name='SemanticVersion' + ) + expected_step_result.add_artifact( + name='version', + value='0.42.1+mock1', + description='Full constructured semantic version' + ) + expected_step_result.add_artifact( + name='container-image-tag', + value='0.42.1_-_mock1', + description='Constructed semenatic version without build identifier' \ + ' since not compatible with container image tags' + ) + expected_step_result.add_artifact( + name='semantic-version-core', value='0.42.1', + description='Semantic version version core portion' + ) + expected_step_result.add_artifact( + name='semantic-version-build', + value='mock1', + description='Semantic version build portion' + ) + expected_step_result.add_evidence( + name='version', + value='0.42.1+mock1', + description='Full constructured semantic version' + ) + expected_step_result.add_evidence( + name='container-image-tag', + value='0.42.1_-_mock1', description='semenatic version without build identifier' \ ' since not compatible with container image tags' ) @@ -322,7 +386,7 @@ def test_app_version_and_is_pre_release_with_given_pre_release_identifiers_and_b ) expected_step_result.add_artifact( name='container-image-tag', - value='0.42.1-feature-mock1', + value='0.42.1-feature-mock1_mock3', description='Constructed semenatic version without build identifier' \ ' since not compatible with container image tags' ) @@ -348,7 +412,7 @@ def test_app_version_and_is_pre_release_with_given_pre_release_identifiers_and_b ) expected_step_result.add_evidence( name='container-image-tag', - value='0.42.1-feature-mock1', + value='0.42.1-feature-mock1_mock3', description='semenatic version without build identifier' \ ' since not compatible with container image tags' )