From 5230737dd9e3ab4db0bac94d5c34eb3b306befe7 Mon Sep 17 00:00:00 2001 From: miroslavpojer Date: Thu, 21 Nov 2024 13:23:52 +0100 Subject: [PATCH 1/5] #10 - Remove support for branches - Removed all code part related to branches. - Removed input: branch - Removed input: fail-on-error - Removed output: valid - When problem found action fails. --- README.md | 32 +---------- action.yml | 14 ----- tests/test_version_tag_check_action.py | 55 ------------------- version_tag_check/github_repository.py | 1 + version_tag_check/version_tag_check_action.py | 36 ++---------- version_tag_check/version_validator.py | 47 +++++++++++++--- 6 files changed, 46 insertions(+), 139 deletions(-) diff --git a/README.md b/README.md index a7b1771..65c0365 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ A GH action for validating version tag sequences and ensuring compliance with ve ## Motivation This action is designed to help maintainers and contributors ensure that version tags are sequenced correctly and comply with versioning standards. It can be used to prevent common issues such as: +- Duplicate version tags on input - Missing version tags - Incorrect version sequences - Non-standard version formats @@ -41,21 +42,6 @@ This action is designed to help maintainers and contributors ensure that version - **Description**: The version tag to check for in the repository. Example: `v0.1.0`. - **Required**: Yes -### `branch` -- **Description**: The branch to check for the version tag. Example: `master`. -- **Required**: Yes - -### `fails-on-error` -- **Description**: Whether the action should fail if an error occurs. -- **Required**: No -- **Default**: `true` - -## Outputs - -### `valid` -- **Description**: Whether the version tag is valid. -- **Value**: `true` or `false` - ## Usage ### Adding the Action to Your Workflow @@ -73,10 +59,8 @@ See the default action step definition: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - github-repository: "{ org }/{ repo }" + github-repository: "{ org }/{ repo }" # ${{ github.repository }} version-tag: "v0.1.0" - branch: "master" - fails-on-error: "false" ``` ### Supported Version Tags Formats @@ -215,22 +199,10 @@ fi # Set necessary environment variables export INPUT_GITHUB_TOKEN="$GITHUB_TOKEN" export INPUT_VERSION_TAG="v1.2.3" -export INPUT_BRANCH="main" -export INPUT_FAILS_ON_ERROR="true" export INPUT_GITHUB_REPOSITORY="AbsaOSS/generate-release-notes" -export GITHUB_OUTPUT="output.txt" # File to capture outputs - -# Remove existing output file if it exists -if [ -f "$GITHUB_OUTPUT" ]; then - rm "$GITHUB_OUTPUT" -fi # Run the main script python main.py - -# Display the outputs -echo "Action Outputs:" -cat "$GITHUB_OUTPUT" ``` ## Contribution Guidelines diff --git a/action.yml b/action.yml index 6910bae..0aa5c01 100644 --- a/action.yml +++ b/action.yml @@ -23,18 +23,6 @@ inputs: version-tag: description: 'The version tag sequence to validate. Example: "v1.2.3".' required: true - branch: - description: 'The branch to check for the latest version tag. Example: "master".' - required: true - fails-on-error: - description: 'Set to "true" to fail the action if validation errors are found.' - required: false - default: 'true' - -outputs: - valid: - description: 'Indicates whether the version tag sequence is valid ("true" or "false").' - value: ${{ steps.version-tag-check.outputs.valid }} branding: icon: 'book' @@ -72,8 +60,6 @@ runs: INPUT_GITHUB_TOKEN: ${{ env.GITHUB_TOKEN }} INPUT_GITHUB_REPOSITORY: ${{ inputs.github-repository }} INPUT_VERSION_TAG: ${{ inputs.version-tag }} - INPUT_BRANCH: ${{ inputs.branch }} - INPUT_FAILS_ON_ERROR: ${{ inputs.fails-on-error }} run: | source .venv/bin/activate python ${{ github.action_path }}/main.py diff --git a/tests/test_version_tag_check_action.py b/tests/test_version_tag_check_action.py index b4588bc..667342d 100644 --- a/tests/test_version_tag_check_action.py +++ b/tests/test_version_tag_check_action.py @@ -28,7 +28,6 @@ ("INPUT_GITHUB_TOKEN", "Failure: GITHUB_TOKEN is not set correctly."), ("INPUT_GITHUB_REPOSITORY", "Failure: GITHUB_REPOSITORY is not set correctly."), ("INPUT_VERSION_TAG", "Failure: VERSION_TAG is not set correctly."), - ("INPUT_BRANCH", "Failure: BRANCH is not set correctly."), ]) def test_validate_inputs_missing_variables(monkeypatch, caplog, missing_var, error_message): # Set all required environment variables @@ -36,7 +35,6 @@ def test_validate_inputs_missing_variables(monkeypatch, caplog, missing_var, err "INPUT_GITHUB_TOKEN": "fake_token", "INPUT_GITHUB_REPOSITORY": "owner/repo", "INPUT_VERSION_TAG": "v1.0.0", - "INPUT_BRANCH": "main", } env_vars.pop(missing_var) # Remove the variable to test if missing_var in os.environ.keys(): @@ -65,14 +63,10 @@ def test_run_successful(mocker, tmp_path): env_vars = { "INPUT_GITHUB_TOKEN": "fake_token", "INPUT_VERSION_TAG": "v1.0.1", - "INPUT_BRANCH": "main", - "INPUT_FAILS_ON_ERROR": "true", "INPUT_GITHUB_REPOSITORY": "owner/repo", } # Update os.environ with the test environment variables os.environ.update(env_vars) - if os.path.exists("output.txt"): - os.remove("output.txt") # Mock sys.exit to prevent the test from exiting mock_exit = mocker.patch("sys.exit") @@ -92,14 +86,10 @@ def test_run_successful(mocker, tmp_path): mock_validator_instance = mock_validator_class.return_value mock_validator_instance.is_valid_increment.return_value = True - # Mock the output writing method - mock_output = mocker.patch("version_tag_check.version_tag_check_action.VersionTagCheckAction.write_output") - # Run the action action = VersionTagCheckAction() action.run() - mock_output.assert_called_once_with("true") mock_exit.assert_called_once_with(0) def test_run_invalid_version_format(mocker, tmp_path, caplog): @@ -107,13 +97,9 @@ def test_run_invalid_version_format(mocker, tmp_path, caplog): env_vars = { "INPUT_GITHUB_TOKEN": "fake_token", "INPUT_VERSION_TAG": "invalid_version", - "INPUT_BRANCH": "main", - "INPUT_FAILS_ON_ERROR": "true", "INPUT_GITHUB_REPOSITORY": "owner/repo", } os.environ.update(env_vars) - if os.path.exists("output.txt"): - os.remove("output.txt") # Mock sys.exit def mock_exit(code): @@ -126,9 +112,6 @@ def mock_exit(code): mock_version_instance = mock_version_class.return_value mock_version_instance.is_valid_format.return_value = False # Simulate invalid format - # Mock the output writing method - mock_output = mocker.patch("version_tag_check.version_tag_check_action.VersionTagCheckAction.write_output") - # Run the action caplog.set_level(logging.ERROR) action = VersionTagCheckAction() @@ -138,7 +121,6 @@ def mock_exit(code): # Assert that sys.exit was called with exit code 1 assert e.value.code == 1 - mock_output.assert_called_once_with("false") assert 'Tag does not match the required format' in caplog.text def test_run_invalid_version_increment(mocker, tmp_path): @@ -146,13 +128,9 @@ def test_run_invalid_version_increment(mocker, tmp_path): env_vars = { "INPUT_GITHUB_TOKEN": "fake_token", "INPUT_VERSION_TAG": "v1.0.2", - "INPUT_BRANCH": "main", - "INPUT_FAILS_ON_ERROR": "true", "INPUT_GITHUB_REPOSITORY": "owner/repo", } os.environ.update(env_vars) - if os.path.exists("output.txt"): - os.remove("output.txt") # Mock sys.exit mock_exit = mocker.patch("sys.exit") @@ -172,41 +150,8 @@ def test_run_invalid_version_increment(mocker, tmp_path): mock_validator_instance = mock_validator_class.return_value mock_validator_instance.is_valid_increment.return_value = False - # Mock the output writing method - mock_output = mocker.patch("version_tag_check.version_tag_check_action.VersionTagCheckAction.write_output") - # Run the action action = VersionTagCheckAction() action.run() - mock_output.assert_called_once_with("false") mock_exit.assert_called_once_with(1) - - -# handle_failure - -def test_handle_failure_fails_on_error_false(mocker): - # Set environment variables with 'INPUT_FAILS_ON_ERROR' set to 'false' - env_vars = { - "INPUT_GITHUB_TOKEN": "fake_token", - "INPUT_VERSION_TAG": "v1.0.0", - "INPUT_BRANCH": "main", - "INPUT_FAILS_ON_ERROR": "false", # Set to 'false' to test else branch - "INPUT_GITHUB_REPOSITORY": "owner/repo", - } - mocker.patch.dict(os.environ, env_vars) - - # Mock sys.exit to raise SystemExit exception - def mock_exit(code): - raise SystemExit(code) - mocker.patch("sys.exit", mock_exit) - - # Instantiate the action - action = VersionTagCheckAction() - - # Call handle_failure and expect SystemExit - with pytest.raises(SystemExit) as e: - action.handle_failure() - - # Assert that sys.exit was called with exit code 0 - assert e.value.code == 0 diff --git a/version_tag_check/github_repository.py b/version_tag_check/github_repository.py index 5d54a68..57ba321 100644 --- a/version_tag_check/github_repository.py +++ b/version_tag_check/github_repository.py @@ -45,6 +45,7 @@ def __init__(self, owner: str, repo: str, token: str) -> None: self.owner = owner self.repo = repo self.token = token + self.headers = {"Authorization": f"Bearer {self.token}", "Accept": "application/vnd.github.v3+json"} def get_all_tags(self) -> list[Version]: diff --git a/version_tag_check/version_tag_check_action.py b/version_tag_check/version_tag_check_action.py index 626d76f..8ef043c 100644 --- a/version_tag_check/version_tag_check_action.py +++ b/version_tag_check/version_tag_check_action.py @@ -41,8 +41,6 @@ def __init__(self) -> None: """ self.github_token: str = os.environ.get("INPUT_GITHUB_TOKEN", default="") self.version_tag_str: str = os.environ.get("INPUT_VERSION_TAG", default="") - self.branch: str = os.environ.get("INPUT_BRANCH", default="") - self.fails_on_error: bool = os.environ.get("INPUT_FAILS_ON_ERROR", "true").lower() == "true" self.github_repository: str = os.environ.get("INPUT_GITHUB_REPOSITORY", default="") self.__validate_inputs() @@ -58,42 +56,22 @@ def run(self) -> None: new_version = Version(self.version_tag_str) if not new_version.is_valid_format(): logger.error('Tag does not match the required format "v[0-9]+.[0-9]+.[0-9]+"') - self.handle_failure() + sys.exit(1) repository: GitHubRepository = GitHubRepository(self.owner, self.repo, self.github_token) existing_versions: list[Version] = repository.get_all_tags() + if new_version in existing_versions: + logger.error("The tag already exists in repository.") + sys.exit(1) + validator = NewVersionValidator(new_version, existing_versions) if validator.is_valid_increment(): - self.write_output("true") logger.info("New tag is valid.") sys.exit(0) else: logger.error("New tag is not valid.") - self.handle_failure() - - def write_output(self, valid_value) -> None: - """ - Write the output to the file specified by the GITHUB_OUTPUT environment variable. - - @param valid_value: The value to write to the output file. - @return: None - """ - output_file = os.environ.get("GITHUB_OUTPUT", default="output.txt") - with open(output_file, "a", encoding="utf-8") as fh: - print(f"valid={valid_value}", file=fh) - - def handle_failure(self) -> None: - """ - Handle the failure of the action. - - @return: None - """ - self.write_output("false") - if self.fails_on_error: sys.exit(1) - else: - sys.exit(0) def __validate_inputs(self) -> None: """ @@ -112,7 +90,3 @@ def __validate_inputs(self) -> None: if len(self.version_tag_str) == 0: logger.error("Failure: VERSION_TAG is not set correctly.") sys.exit(1) - - if len(self.branch) == 0: - logger.error("Failure: BRANCH is not set correctly.") - sys.exit(1) diff --git a/version_tag_check/version_validator.py b/version_tag_check/version_validator.py index df5977e..13e6000 100644 --- a/version_tag_check/version_validator.py +++ b/version_tag_check/version_validator.py @@ -52,6 +52,20 @@ def __get_latest_version(self) -> Optional[Version]: return None return max(self.__existing_versions) + def __get_filtered_versions(self, major: int, minor: Optional[int] = None) -> list[Version]: + """ + Filter the existing versions based on major and optionally minor versions. + + @param major: The major version to filter by + @param minor: The minor version to filter by (optional) + @return: A list of versions matching the criteria + """ + return [ + version + for version in self.__existing_versions + if version.major == major and (minor is None or version.minor == minor) + ] + def is_valid_increment(self) -> bool: """ Check if the new version is a valid increment from the latest version. @@ -59,20 +73,35 @@ def is_valid_increment(self) -> bool: @return: True if the new version is a valid increment, False otherwise """ latest_version: Optional[Version] = self.__get_latest_version() + logger.debug("Validator: Latest version: %s", latest_version) if not latest_version: # Any version is valid if no previous versions exist + logger.info("No previous versions exist. New version is valid.") return True - lv: Optional[Version] = latest_version nv: Version = self.__new_version - if nv.major == lv.major: - if nv.minor == lv.minor: - return nv.patch == lv.patch + 1 - if nv.minor == lv.minor + 1: - return nv.patch == 0 - elif nv.major == lv.major + 1: - return nv.minor == 0 and nv.patch == 0 + # Filter versions matching the major and minor version of the new version + filtered_versions = self.__get_filtered_versions(nv.major, nv.minor) + if filtered_versions: + latest_filtered_version = max(filtered_versions) + logger.debug("Validator: Latest filtered version: %s", latest_filtered_version) + + # Validate against the latest filtered version + if nv.major == latest_filtered_version.major and nv.minor == latest_filtered_version.minor: + if nv.patch == latest_filtered_version.patch + 1: + return True + logger.error(f"New tag {nv} is not one patch higher than the latest tag {latest_filtered_version}.") + + # Check if this is a valid minor or major bump + if nv.major == latest_version.major: + if nv.minor == latest_version.minor + 1: + if nv.patch == 0: + return True + logger.error(f"New tag {nv} is not a valid minor bump. Latest version: {latest_version}.") + elif nv.major == latest_version.major + 1: + if nv.minor == 0 and nv.patch == 0: + return True + logger.error(f"New tag {nv} is not a valid major bump. Latest version: {latest_version}.") - logger.error("New tag %s is not one version higher than the latest tag %s.", self.__new_version, latest_version) return False From 35bf5aa3ea7a07862b842a3998f97a8821b4a7d2 Mon Sep 17 00:00:00 2001 From: miroslavpojer Date: Thu, 21 Nov 2024 13:47:18 +0100 Subject: [PATCH 2/5] - Improved unit test coverage. --- tests/test_version_tag_check_action.py | 85 +++++++++++++------------- 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/tests/test_version_tag_check_action.py b/tests/test_version_tag_check_action.py index 667342d..fba71ab 100644 --- a/tests/test_version_tag_check_action.py +++ b/tests/test_version_tag_check_action.py @@ -58,14 +58,27 @@ def test_validate_inputs_missing_variables(monkeypatch, caplog, missing_var, err # run -def test_run_successful(mocker, tmp_path): +@pytest.mark.parametrize( + "version_tag, existing_tags", + [ + ("v0.0.1", []), # New version with no existing tags + ("v0.1.0", []), # New version with no existing tags + ("v1.0.0", []), # New version with no existing tags + ("v0.0.2", ["v0.0.1"]), # Patch increment + ("v1.2.0", ["v1.1.0"]), # Minor increment + ("v2.0.0", ["v1.9.9"]), # Major increment + ("v2.1.0", ["v2.0.5", "v2.0.0"]), # New Release serie + ("v3.0.1", ["v2.9.9", "v1.0.0"]), # Increment with Gaps + ("v1.5.2", ["v2.0.0", "v1.5.1"]), # Backport increment + ], +) +def test_run_successful(mocker, version_tag, existing_tags): # Set environment variables env_vars = { "INPUT_GITHUB_TOKEN": "fake_token", - "INPUT_VERSION_TAG": "v1.0.1", + "INPUT_VERSION_TAG": version_tag, "INPUT_GITHUB_REPOSITORY": "owner/repo", } - # Update os.environ with the test environment variables os.environ.update(env_vars) # Mock sys.exit to prevent the test from exiting @@ -79,7 +92,7 @@ def test_run_successful(mocker, tmp_path): # Mock the GitHubRepository class mock_repository_class = mocker.patch("version_tag_check.version_tag_check_action.GitHubRepository") mock_repository_instance = mock_repository_class.return_value - mock_repository_instance.get_all_tags.return_value = [] + mock_repository_instance.get_all_tags.return_value = existing_tags # Mock the NewVersionValidator class mock_validator_class = mocker.patch("version_tag_check.version_tag_check_action.NewVersionValidator") @@ -92,66 +105,56 @@ def test_run_successful(mocker, tmp_path): mock_exit.assert_called_once_with(0) -def test_run_invalid_version_format(mocker, tmp_path, caplog): + +@pytest.mark.parametrize( + "version_tag, existing_tags, is_valid_format, is_valid_increment, expected_exit_code, error_message", + [ + ("invalid_version", [], False, True, 1, "Tag does not match the required format"), # Invalid format + ("invalid_version", ["v1.0.0"], False, True, 1, "Tag does not match the required format"), # Invalid format + ("v1.0.3", ["v1.0.1"], True, False, 1, "New tag is not valid."), # Invalid increment + ("v1.0.0", ["v1.0.0"], True, False, 1, "New tag is not valid."), # Existing tag + ("v1.4.1", ["v2.0.0", "v1.4.2"], True, False, 1, "New tag is not valid."), # Invalid backport increment + ("1.0.0", [], False, True, 1, "Tag does not match the required format"), # Invalid format and increment + ], +) +def test_run_unsuccessful(mocker, caplog, version_tag, existing_tags, is_valid_format, is_valid_increment, expected_exit_code, error_message): # Set environment variables env_vars = { "INPUT_GITHUB_TOKEN": "fake_token", - "INPUT_VERSION_TAG": "invalid_version", + "INPUT_VERSION_TAG": version_tag, "INPUT_GITHUB_REPOSITORY": "owner/repo", } os.environ.update(env_vars) - # Mock sys.exit + # Mock sys.exit to raise a SystemExit for assertion def mock_exit(code): raise SystemExit(code) mocker.patch("sys.exit", mock_exit) - # Mock the Version class used in VersionTagCheckAction - mock_version_class = mocker.patch("version_tag_check.version_tag_check_action.Version") - mock_version_instance = mock_version_class.return_value - mock_version_instance.is_valid_format.return_value = False # Simulate invalid format - - # Run the action - caplog.set_level(logging.ERROR) - action = VersionTagCheckAction() - with pytest.raises(SystemExit) as e: - action.run() - - # Assert that sys.exit was called with exit code 1 - assert e.value.code == 1 - - assert 'Tag does not match the required format' in caplog.text - -def test_run_invalid_version_increment(mocker, tmp_path): - # Set environment variables - env_vars = { - "INPUT_GITHUB_TOKEN": "fake_token", - "INPUT_VERSION_TAG": "v1.0.2", - "INPUT_GITHUB_REPOSITORY": "owner/repo", - } - os.environ.update(env_vars) - - # Mock sys.exit - mock_exit = mocker.patch("sys.exit") - # Mock the Version class mock_version_class = mocker.patch("version_tag_check.version_tag_check_action.Version") mock_version_instance = mock_version_class.return_value - mock_version_instance.is_valid_format.return_value = True + mock_version_instance.is_valid_format.return_value = is_valid_format # Mock the GitHubRepository class mock_repository_class = mocker.patch("version_tag_check.version_tag_check_action.GitHubRepository") mock_repository_instance = mock_repository_class.return_value - mock_repository_instance.get_all_tags.return_value = [] # Simulate existing versions if needed + mock_repository_instance.get_all_tags.return_value = existing_tags - # Mock the NewVersionValidator class to return False for is_valid_increment + # Mock the NewVersionValidator class mock_validator_class = mocker.patch("version_tag_check.version_tag_check_action.NewVersionValidator") mock_validator_instance = mock_validator_class.return_value - mock_validator_instance.is_valid_increment.return_value = False + mock_validator_instance.is_valid_increment.return_value = is_valid_increment # Run the action + caplog.set_level(logging.ERROR) action = VersionTagCheckAction() - action.run() + with pytest.raises(SystemExit) as e: + action.run() + + # Assert sys.exit was called with the correct code + assert e.value.code == expected_exit_code - mock_exit.assert_called_once_with(1) + # Assert error message in logs + assert error_message in caplog.text From deadef602511b47df4970ef8214ae1b30e70883f Mon Sep 17 00:00:00 2001 From: miroslavpojer Date: Thu, 21 Nov 2024 14:21:13 +0100 Subject: [PATCH 3/5] - Version gap is no more allowed. --- tests/test_version_tag_check_action.py | 52 ++++++------------- version_tag_check/version.py | 2 +- version_tag_check/version_tag_check_action.py | 1 - 3 files changed, 18 insertions(+), 37 deletions(-) diff --git a/tests/test_version_tag_check_action.py b/tests/test_version_tag_check_action.py index fba71ab..5c17305 100644 --- a/tests/test_version_tag_check_action.py +++ b/tests/test_version_tag_check_action.py @@ -18,7 +18,9 @@ import logging import os import pytest +from botocore.handlers import VERSION_ID_SUFFIX +from version_tag_check.version import Version from version_tag_check.version_tag_check_action import VersionTagCheckAction @@ -61,15 +63,14 @@ def test_validate_inputs_missing_variables(monkeypatch, caplog, missing_var, err @pytest.mark.parametrize( "version_tag, existing_tags", [ - ("v0.0.1", []), # New version with no existing tags - ("v0.1.0", []), # New version with no existing tags - ("v1.0.0", []), # New version with no existing tags - ("v0.0.2", ["v0.0.1"]), # Patch increment - ("v1.2.0", ["v1.1.0"]), # Minor increment - ("v2.0.0", ["v1.9.9"]), # Major increment - ("v2.1.0", ["v2.0.5", "v2.0.0"]), # New Release serie - ("v3.0.1", ["v2.9.9", "v1.0.0"]), # Increment with Gaps - ("v1.5.2", ["v2.0.0", "v1.5.1"]), # Backport increment + ("v0.0.1", []), # New version with no existing tags + ("v0.1.0", []), # New version with no existing tags + ("v1.0.0", []), # New version with no existing tags + ("v0.0.2", [Version("v0.0.1")]), # Patch increment + ("v1.2.0", [Version("v1.1.0")]), # Minor increment + ("v2.0.0", [Version("v1.9.9")]), # Major increment + ("v2.1.0", [Version("v2.0.5"), Version("v2.0.0")]), # New Release serie + ("v1.5.2", [Version("v2.0.0"), Version("v1.5.1")]), # Backport increment ], ) def test_run_successful(mocker, version_tag, existing_tags): @@ -84,21 +85,11 @@ def test_run_successful(mocker, version_tag, existing_tags): # Mock sys.exit to prevent the test from exiting mock_exit = mocker.patch("sys.exit") - # Mock the Version class - mock_version_class = mocker.patch("version_tag_check.version_tag_check_action.Version") - mock_version_instance = mock_version_class.return_value - mock_version_instance.is_valid_format.return_value = True - # Mock the GitHubRepository class mock_repository_class = mocker.patch("version_tag_check.version_tag_check_action.GitHubRepository") mock_repository_instance = mock_repository_class.return_value mock_repository_instance.get_all_tags.return_value = existing_tags - # Mock the NewVersionValidator class - mock_validator_class = mocker.patch("version_tag_check.version_tag_check_action.NewVersionValidator") - mock_validator_instance = mock_validator_class.return_value - mock_validator_instance.is_valid_increment.return_value = True - # Run the action action = VersionTagCheckAction() action.run() @@ -109,12 +100,13 @@ def test_run_successful(mocker, version_tag, existing_tags): @pytest.mark.parametrize( "version_tag, existing_tags, is_valid_format, is_valid_increment, expected_exit_code, error_message", [ - ("invalid_version", [], False, True, 1, "Tag does not match the required format"), # Invalid format - ("invalid_version", ["v1.0.0"], False, True, 1, "Tag does not match the required format"), # Invalid format - ("v1.0.3", ["v1.0.1"], True, False, 1, "New tag is not valid."), # Invalid increment - ("v1.0.0", ["v1.0.0"], True, False, 1, "New tag is not valid."), # Existing tag - ("v1.4.1", ["v2.0.0", "v1.4.2"], True, False, 1, "New tag is not valid."), # Invalid backport increment - ("1.0.0", [], False, True, 1, "Tag does not match the required format"), # Invalid format and increment + ("invalid_version", [], False, True, 1, "Tag does not match the required format"), # Invalid format + ("invalid_version", [Version("v1.0.0")], False, True, 1, "Tag does not match the required format"), # Invalid format + ("v1.0.3", [Version("v1.0.1")], True, False, 1, "New tag v1.0.3 is not one patch higher than the latest tag v1.0.1."), # Invalid increment + ("v1.0.0", [Version("v1.0.0")], True, False, 1, "The tag already exists in repository"), # Existing tag + ("v1.4.1", [Version("v2.0.0"), Version("v1.4.2")], True, False, 1, "New tag v1.4.1 is not one patch higher than the latest tag v1.4.2."), # Invalid backport increment + ("1.0.0", [], False, True, 1, "Tag does not match the required format"), # Invalid format and increment + ("v3.0.1", [Version("v2.9.9"), Version("v1.0.0")], True, False, 1, "New tag v3.0.1 is not a valid major bump. Latest version: v2.9.9."), # Invalid version gap ], ) def test_run_unsuccessful(mocker, caplog, version_tag, existing_tags, is_valid_format, is_valid_increment, expected_exit_code, error_message): @@ -132,21 +124,11 @@ def mock_exit(code): mocker.patch("sys.exit", mock_exit) - # Mock the Version class - mock_version_class = mocker.patch("version_tag_check.version_tag_check_action.Version") - mock_version_instance = mock_version_class.return_value - mock_version_instance.is_valid_format.return_value = is_valid_format - # Mock the GitHubRepository class mock_repository_class = mocker.patch("version_tag_check.version_tag_check_action.GitHubRepository") mock_repository_instance = mock_repository_class.return_value mock_repository_instance.get_all_tags.return_value = existing_tags - # Mock the NewVersionValidator class - mock_validator_class = mocker.patch("version_tag_check.version_tag_check_action.NewVersionValidator") - mock_validator_instance = mock_validator_class.return_value - mock_validator_instance.is_valid_increment.return_value = is_valid_increment - # Run the action caplog.set_level(logging.ERROR) action = VersionTagCheckAction() diff --git a/version_tag_check/version.py b/version_tag_check/version.py index 6c263e8..12c3cf6 100644 --- a/version_tag_check/version.py +++ b/version_tag_check/version.py @@ -32,7 +32,7 @@ class Version: Class to represent a version and compare it to other versions. """ - VERSION_REGEX = r"^v?(\d+)\.(\d+)\.(\d+)$" + VERSION_REGEX = r"^v(\d+)\.(\d+)\.(\d+)$" def __init__(self, version_str: str, version_regex: str = VERSION_REGEX) -> None: """ diff --git a/version_tag_check/version_tag_check_action.py b/version_tag_check/version_tag_check_action.py index 8ef043c..bf434c5 100644 --- a/version_tag_check/version_tag_check_action.py +++ b/version_tag_check/version_tag_check_action.py @@ -70,7 +70,6 @@ def run(self) -> None: logger.info("New tag is valid.") sys.exit(0) else: - logger.error("New tag is not valid.") sys.exit(1) def __validate_inputs(self) -> None: From 995e8940b8922058505f3a400bdd76b14240d8ef Mon Sep 17 00:00:00 2001 From: miroslavpojer Date: Thu, 21 Nov 2024 14:24:10 +0100 Subject: [PATCH 4/5] - Removed wrong import. --- tests/test_version_tag_check_action.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_version_tag_check_action.py b/tests/test_version_tag_check_action.py index 5c17305..4ba9335 100644 --- a/tests/test_version_tag_check_action.py +++ b/tests/test_version_tag_check_action.py @@ -18,7 +18,6 @@ import logging import os import pytest -from botocore.handlers import VERSION_ID_SUFFIX from version_tag_check.version import Version from version_tag_check.version_tag_check_action import VersionTagCheckAction From e00dc5180fe130a878d25a8442c79c68bca6253e Mon Sep 17 00:00:00 2001 From: miroslavpojer Date: Mon, 25 Nov 2024 14:19:23 +0100 Subject: [PATCH 5/5] - Fix review comments. --- README.md | 2 +- version_tag_check/version_validator.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 65c0365..759429a 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ See the default action step definition: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - github-repository: "{ org }/{ repo }" # ${{ github.repository }} + github-repository: "{ org }/{ repo }" # e.g. ${{ github.repository }} version-tag: "v0.1.0" ``` diff --git a/version_tag_check/version_validator.py b/version_tag_check/version_validator.py index 13e6000..b29f1ba 100644 --- a/version_tag_check/version_validator.py +++ b/version_tag_check/version_validator.py @@ -91,17 +91,17 @@ def is_valid_increment(self) -> bool: if nv.major == latest_filtered_version.major and nv.minor == latest_filtered_version.minor: if nv.patch == latest_filtered_version.patch + 1: return True - logger.error(f"New tag {nv} is not one patch higher than the latest tag {latest_filtered_version}.") + logger.error("New tag %s is not one patch higher than the latest tag %s.", nv, latest_filtered_version) # Check if this is a valid minor or major bump if nv.major == latest_version.major: if nv.minor == latest_version.minor + 1: if nv.patch == 0: return True - logger.error(f"New tag {nv} is not a valid minor bump. Latest version: {latest_version}.") + logger.error("New tag %s is not a valid minor bump. Latest version: %s.", nv, latest_version) elif nv.major == latest_version.major + 1: if nv.minor == 0 and nv.patch == 0: return True - logger.error(f"New tag {nv} is not a valid major bump. Latest version: {latest_version}.") + logger.error("New tag %s is not a valid major bump. Latest version: %s.", nv, latest_version) return False