diff --git a/src/vcspull/cli/add.py b/src/vcspull/cli/add.py index 40dfc454..b501172e 100644 --- a/src/vcspull/cli/add.py +++ b/src/vcspull/cli/add.py @@ -7,7 +7,6 @@ import logging import pathlib import subprocess -import traceback import typing as t from colorama import Fore, Style @@ -408,8 +407,6 @@ def add_repo( "Error loading YAML from %s. Aborting.", PrivatePath(config_file_path), ) - if log.isEnabledFor(logging.DEBUG): - traceback.print_exc() return else: raw_config = {} @@ -589,8 +586,6 @@ def _prepare_no_merge_items( "Error saving config to %s", PrivatePath(config_file_path), ) - if log.isEnabledFor(logging.DEBUG): - traceback.print_exc() elif (duplicate_merge_changes > 0 or config_was_relabelled) and dry_run: log.info( "%s→%s Would save workspace label adjustments to %s%s%s.", @@ -648,8 +643,6 @@ def _prepare_no_merge_items( "Error saving config to %s", PrivatePath(config_file_path), ) - if log.isEnabledFor(logging.DEBUG): - traceback.print_exc() return ordered_items = _build_ordered_items(top_level_items, raw_config) @@ -735,8 +728,6 @@ def _prepare_no_merge_items( "Error saving config to %s", PrivatePath(config_file_path), ) - if log.isEnabledFor(logging.DEBUG): - traceback.print_exc() return target_section = ordered_items[target_index]["section"] @@ -797,5 +788,3 @@ def _prepare_no_merge_items( "Error saving config to %s", PrivatePath(config_file_path), ) - if log.isEnabledFor(logging.DEBUG): - traceback.print_exc() diff --git a/src/vcspull/cli/discover.py b/src/vcspull/cli/discover.py index 4902b1f9..d376afed 100644 --- a/src/vcspull/cli/discover.py +++ b/src/vcspull/cli/discover.py @@ -7,7 +7,6 @@ import os import pathlib import subprocess -import traceback import typing as t from colorama import Fore, Style @@ -331,8 +330,6 @@ def discover_repos( "Error loading YAML from %s. Aborting.", PrivatePath(config_file_path), ) - if log.isEnabledFor(logging.DEBUG): - traceback.print_exc() return if raw_config is None: raw_config = {} @@ -609,8 +606,6 @@ def discover_repos( "Error saving config to %s", PrivatePath(config_file_path), ) - if log.isEnabledFor(logging.DEBUG): - traceback.print_exc() return return @@ -710,8 +705,6 @@ def discover_repos( "Error saving config to %s", PrivatePath(config_file_path), ) - if log.isEnabledFor(logging.DEBUG): - traceback.print_exc() return else: log.info( diff --git a/src/vcspull/cli/fmt.py b/src/vcspull/cli/fmt.py index 719f2bf4..cc801dfd 100644 --- a/src/vcspull/cli/fmt.py +++ b/src/vcspull/cli/fmt.py @@ -6,7 +6,6 @@ import copy import logging import pathlib -import traceback import typing as t from colorama import Fore, Style @@ -188,8 +187,6 @@ def format_single_config( "Error loading config from %s", PrivatePath(config_file_path), ) - if log.isEnabledFor(logging.DEBUG): - traceback.print_exc() return False # Format the configuration @@ -371,8 +368,6 @@ def format_single_config( "Error saving formatted config to %s", PrivatePath(config_file_path), ) - if log.isEnabledFor(logging.DEBUG): - traceback.print_exc() return False else: log.info( diff --git a/src/vcspull/cli/sync.py b/src/vcspull/cli/sync.py index fadf6e93..808f7c49 100644 --- a/src/vcspull/cli/sync.py +++ b/src/vcspull/cli/sync.py @@ -869,10 +869,7 @@ def silent_progress(output: str, timestamp: datetime) -> None: "Failed syncing %s", repo_name, ) - if log.isEnabledFor(logging.DEBUG): - import traceback - - traceback.print_exc() + log.debug("Traceback for %s", repo_name, exc_info=True) formatter.emit_text( f"{colors.error('āœ—')} Failed syncing {colors.info(repo_name)}: " f"{colors.error(str(e))}", diff --git a/tests/cli/conftest.py b/tests/cli/conftest.py new file mode 100644 index 00000000..c8f74a2b --- /dev/null +++ b/tests/cli/conftest.py @@ -0,0 +1,56 @@ +"""Shared test helpers for vcspull CLI tests.""" + +from __future__ import annotations + +import typing as t + +from vcspull._internal.remotes import ( + ImportOptions, + RemoteRepo, +) + + +class MockImporter: + """Reusable mock importer for tests.""" + + def __init__( + self, + *, + service_name: str = "MockService", + repos: list[RemoteRepo] | None = None, + error: Exception | None = None, + ) -> None: + self.service_name = service_name + self._repos = repos or [] + self._error = error + + def fetch_repos( + self, + options: ImportOptions, + ) -> t.Iterator[RemoteRepo]: + """Yield mock repos or raise a mock error.""" + if self._error: + raise self._error + yield from self._repos + + +class CapturingMockImporter: + """Mock importer that captures the ImportOptions passed to fetch_repos.""" + + def __init__( + self, + *, + service_name: str = "MockService", + repos: list[RemoteRepo] | None = None, + ) -> None: + self.service_name = service_name + self._repos = repos or [] + self.captured_options: ImportOptions | None = None + + def fetch_repos( + self, + options: ImportOptions, + ) -> t.Iterator[RemoteRepo]: + """Capture options and yield repos.""" + self.captured_options = options + yield from self._repos diff --git a/tests/cli/test_import_repos.py b/tests/cli/test_import_repos.py index 0df5ebdc..14d09c2c 100644 --- a/tests/cli/test_import_repos.py +++ b/tests/cli/test_import_repos.py @@ -10,6 +10,7 @@ import pytest +from tests.cli.conftest import CapturingMockImporter, MockImporter from vcspull._internal.remotes import ( AuthenticationError, ConfigurationError, @@ -55,52 +56,6 @@ def _make_repo( ) -class MockImporter: - """Reusable mock importer for tests.""" - - def __init__( - self, - *, - service_name: str = "MockService", - repos: list[RemoteRepo] | None = None, - error: Exception | None = None, - ) -> None: - self.service_name = service_name - self._repos = repos or [] - self._error = error - - def fetch_repos( - self, - options: ImportOptions, - ) -> t.Iterator[RemoteRepo]: - """Yield mock repos or raise a mock error.""" - if self._error: - raise self._error - yield from self._repos - - -class CapturingMockImporter: - """Mock importer that captures the ImportOptions passed to fetch_repos.""" - - def __init__( - self, - *, - service_name: str = "MockService", - repos: list[RemoteRepo] | None = None, - ) -> None: - self.service_name = service_name - self._repos = repos or [] - self.captured_options: ImportOptions | None = None - - def fetch_repos( - self, - options: ImportOptions, - ) -> t.Iterator[RemoteRepo]: - """Capture options and yield repos.""" - self.captured_options = options - yield from self._repos - - class ResolveConfigFixture(t.NamedTuple): """Fixture for _resolve_config_file test cases."""