From ec3cd998dfa7eaff678262163629abac73640c86 Mon Sep 17 00:00:00 2001 From: Corey Oordt Date: Thu, 25 Apr 2024 12:21:44 -0500 Subject: [PATCH 1/2] Fixed the indentation problem - Added a dedent when a file does not match the change pattern. - Fixes #181 --- bumpversion/files.py | 19 ++++--- tests/conftest.py | 3 ++ tests/test_files.py | 120 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+), 8 deletions(-) diff --git a/bumpversion/files.py b/bumpversion/files.py index a39a234c..4376cf77 100644 --- a/bumpversion/files.py +++ b/bumpversion/files.py @@ -183,15 +183,9 @@ def make_file_change( logger.dedent() return raise FileNotFoundError(f"File not found: '{self.file_change.filename}'") # pragma: no-coverage - logger.debug("Serializing the current version") - logger.indent() - context["current_version"] = self.version_config.serialize(current_version, context) - logger.dedent() + context["current_version"] = self._get_serialized_version("current_version", current_version, context) if new_version: - logger.debug("Serializing the new version") - logger.indent() - context["new_version"] = self.version_config.serialize(new_version, context) - logger.dedent() + context["new_version"] = self._get_serialized_version("new_version", new_version, context) else: logger.debug("No new version, using current version as new version") context["new_version"] = context["current_version"] @@ -200,6 +194,7 @@ def make_file_change( replace_with = self.version_config.replace.format(**context) if not self._contains_change_pattern(search_for, raw_search_pattern, current_version, context): + logger.dedent() return file_content_before = self.get_file_contents() @@ -217,6 +212,14 @@ def make_file_change( if not dry_run: # pragma: no-coverage self.write_file_contents(file_content_after) + def _get_serialized_version(self, context_key: str, version: Version, context: MutableMapping) -> str: + """Get the serialized version.""" + logger.debug("Serializing the %s", context_key.replace("_", " ")) + logger.indent() + serialized_version = self.version_config.serialize(version, context) + logger.dedent() + return serialized_version + def __str__(self) -> str: # pragma: no-coverage return self.file_change.filename diff --git a/tests/conftest.py b/tests/conftest.py index a7fcd29b..64483c77 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,9 +5,12 @@ from click.testing import CliRunner from pathlib import Path from typing import Generator +from bumpversion.ui import setup_logging import pytest +setup_logging(1) + @pytest.fixture def tests_path() -> Path: diff --git a/tests/test_files.py b/tests/test_files.py index f6bf33fd..c6946dd7 100644 --- a/tests/test_files.py +++ b/tests/test_files.py @@ -19,6 +19,126 @@ from tests.conftest import get_config_data, inside_dir +class TestConfiguredFile: + """Tests of the ConfiguredFile class.""" + + class TestGetFileContents: + """Tests of the get_file_content method.""" + + def test_returns_contents_of_existing_file(self, tmp_path: Path) -> None: + """The get_file_content method returns the contents of an existing file.""" + # Arrange + filepath = tmp_path / "file.md" + expected_data = "My current version is 1.2.3" + filepath.write_text(expected_data, encoding="utf-8") + overrides = { + "current_version": "1.2.3", + "files": [{"filename": str(filepath)}], + } + conf, version_config, current_version = get_config_data(overrides) + assert len(conf.files_to_modify) == 1 + assert conf.files_to_modify[0].filename == str(filepath) + + # Act + configured_file = files.ConfiguredFile(conf.files_to_modify[0], version_config) + + # Assert + assert configured_file.get_file_contents() == expected_data + + def test_raises_exception_if_file_not_found(self, tmp_path: Path) -> None: + """The get_file_content method raises an exception if the file does not exist.""" + filepath = tmp_path / "file.md" + overrides = { + "current_version": "1.2.3", + "files": [{"filename": str(filepath)}], + } + conf, version_config, current_version = get_config_data(overrides) + assert len(conf.files_to_modify) == 1 + assert conf.files_to_modify[0].filename == str(filepath) + configured_file = files.ConfiguredFile(conf.files_to_modify[0], version_config) + + # Act + with pytest.raises(FileNotFoundError): + configured_file.get_file_contents() + + class TestMakeFileChange: + """Tests of the make_file_change function.""" + + def test_raises_exception_if_file_not_found(self, tmp_path: Path) -> None: + """The make_file_change method raises an exception if the file does not exist.""" + # Assemble + filepath = tmp_path / "file.md" + overrides = { + "current_version": "1.2.3", + "files": [{"filename": str(filepath)}], + } + conf, version_config, current_version = get_config_data(overrides) + configured_file = files.ConfiguredFile(conf.files_to_modify[0], version_config) + new_version = current_version.bump("patch") + ctx = get_context(conf) + + # Act + with pytest.raises(FileNotFoundError): + configured_file.make_file_change(current_version, new_version, ctx, dry_run=True) + + def test_logs_missing_file_when_ignore_missing_file_set(self, tmp_path: Path, caplog) -> None: + """The make_file_change method logs missing file when ignore_missing_file set to True.""" + # Assemble + filepath = tmp_path / "file.md" + overrides = { + "current_version": "1.2.3", + "files": [{"filename": str(filepath), "ignore_missing_file": True}], + } + conf, version_config, current_version = get_config_data(overrides) + configured_file = files.ConfiguredFile(conf.files_to_modify[0], version_config) + new_version = current_version.bump("patch") + ctx = get_context(conf) + + # Act + configured_file.make_file_change(current_version, new_version, ctx, dry_run=True) + + # Assert + logs = caplog.messages + assert logs[0] == " Reading configuration" + assert logs[1] == " Configuration file not found: missing." + assert logs[2].endswith("file.md: replace `{current_version}` with `{new_version}`") + assert logs[3] == " File not found, but ignoring" + + def test_dedents_properly_when_file_does_not_contain_pattern(self, fixtures_path: Path, caplog) -> None: + """The make_file_change method dedents the logging context when it does not contain a pattern.""" + # Assemble + globs = fixtures_path / "glob" / "**/*.txt" + overrides = { + "current_version": "1.2.3", + "files": [{"glob": str(globs), "ignore_missing_file": True, "ignore_missing_version": True}], + } + conf, version_config, current_version = get_config_data(overrides) + configured_file1 = files.ConfiguredFile(conf.files_to_modify[0], version_config) + configured_file2 = files.ConfiguredFile(conf.files_to_modify[1], version_config) + configured_file3 = files.ConfiguredFile(conf.files_to_modify[2], version_config) + new_version = current_version.bump("patch") + ctx = get_context(conf) + + # Act + configured_file1.make_file_change(current_version, new_version, ctx, dry_run=True) + configured_file2.make_file_change(current_version, new_version, ctx, dry_run=True) + configured_file3.make_file_change(current_version, new_version, ctx, dry_run=True) + + # Assert + logs = caplog.messages + assert logs[0] == " Reading configuration" + assert logs[1] == " Configuration file not found: missing." + assert logs[2] == ( + f" \n File {configured_file1.file_change.filename}: replace `{{current_version}}` with `{{new_version}}`" + ) + assert logs[3] == ( + f" \n File {configured_file2.file_change.filename}: replace `{{current_version}}` with `{{new_version}}`" + ) + assert logs[4] == ( + f" \n File {configured_file3.file_change.filename}: replace `{{current_version}}` with `{{new_version}}`" + ) + + def test_single_file_processed_twice(tmp_path: Path): """ Verify that a single file "file2" can be processed twice. From 3777f2750a146a698ed0d15edd88c82f73e35354 Mon Sep 17 00:00:00 2001 From: Corey Oordt Date: Fri, 26 Apr 2024 08:40:06 -0500 Subject: [PATCH 2/2] Fixed test logging setup --- tests/conftest.py | 3 --- tests/test_files.py | 28 +++++++++++++++++++--------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 64483c77..a7fcd29b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,12 +5,9 @@ from click.testing import CliRunner from pathlib import Path from typing import Generator -from bumpversion.ui import setup_logging import pytest -setup_logging(1) - @pytest.fixture def tests_path() -> Path: diff --git a/tests/test_files.py b/tests/test_files.py index c6946dd7..ec0576b1 100644 --- a/tests/test_files.py +++ b/tests/test_files.py @@ -1,5 +1,6 @@ """File processing tests.""" +import logging import os import shutil from datetime import datetime, timezone @@ -15,6 +16,7 @@ from bumpversion.config.models import FileChange from bumpversion.context import get_context from bumpversion.exceptions import VersionNotFoundError +from bumpversion.ui import setup_logging, get_indented_logger from bumpversion.version_part import VersionConfig from tests.conftest import get_config_data, inside_dir @@ -84,6 +86,10 @@ def test_raises_exception_if_file_not_found(self, tmp_path: Path) -> None: def test_logs_missing_file_when_ignore_missing_file_set(self, tmp_path: Path, caplog) -> None: """The make_file_change method logs missing file when ignore_missing_file set to True.""" # Assemble + setup_logging(1) + caplog.set_level(logging.INFO) + logger = get_indented_logger(__name__) + logger.reset() filepath = tmp_path / "file.md" overrides = { "current_version": "1.2.3", @@ -99,14 +105,18 @@ def test_logs_missing_file_when_ignore_missing_file_set(self, tmp_path: Path, ca # Assert logs = caplog.messages - assert logs[0] == " Reading configuration" - assert logs[1] == " Configuration file not found: missing." - assert logs[2].endswith("file.md: replace `{current_version}` with `{new_version}`") - assert logs[3] == " File not found, but ignoring" + assert logs[0] == "Reading configuration" + assert logs[1] == " Configuration file not found: missing." + assert logs[2] == f"\nFile {filepath}: replace `{{current_version}}` with `{{new_version}}`" + assert logs[3] == " File not found, but ignoring" def test_dedents_properly_when_file_does_not_contain_pattern(self, fixtures_path: Path, caplog) -> None: """The make_file_change method dedents the logging context when it does not contain a pattern.""" # Assemble + setup_logging(1) + caplog.set_level(logging.INFO) + logger = get_indented_logger(__name__) + logger.reset() globs = fixtures_path / "glob" / "**/*.txt" overrides = { "current_version": "1.2.3", @@ -126,16 +136,16 @@ def test_dedents_properly_when_file_does_not_contain_pattern(self, fixtures_path # Assert logs = caplog.messages - assert logs[0] == " Reading configuration" - assert logs[1] == " Configuration file not found: missing." + assert logs[0] == "Reading configuration" + assert logs[1] == " Configuration file not found: missing." assert logs[2] == ( - f" \n File {configured_file1.file_change.filename}: replace `{{current_version}}` with `{{new_version}}`" + f"\nFile {configured_file1.file_change.filename}: replace `{{current_version}}` with `{{new_version}}`" ) assert logs[3] == ( - f" \n File {configured_file2.file_change.filename}: replace `{{current_version}}` with `{{new_version}}`" + f"\nFile {configured_file2.file_change.filename}: replace `{{current_version}}` with `{{new_version}}`" ) assert logs[4] == ( - f" \n File {configured_file3.file_change.filename}: replace `{{current_version}}` with `{{new_version}}`" + f"\nFile {configured_file3.file_change.filename}: replace `{{current_version}}` with `{{new_version}}`" )