Skip to content

refactor: eliminate duplicated code patterns across command modules#429

Merged
tschm merged 2 commits intomainfrom
copilot/refactor-duplicate-code-patterns
Mar 9, 2026
Merged

refactor: eliminate duplicated code patterns across command modules#429
tschm merged 2 commits intomainfrom
copilot/refactor-duplicate-code-patterns

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 9, 2026

Five internal refactors to remove ~65 lines of duplicated code across command modules. No public API or CLI behaviour changes.

Changes

  • Centralize LOCK_FILE — removed duplicate ".rhiza/template.lock" definitions from status.py and tree.py; both now import from _sync_helpers.py

  • Extract _load_lock_or_warn(target) in _sync_helpers.py — eliminates the identical 4-line lock-load-or-warn pattern repeated in status.py and tree.py:

    def _load_lock_or_warn(target: Path) -> TemplateLock | None:
        lock_path = (target / LOCK_FILE).resolve()
        if not lock_path.exists():
            logger.warning("No template.lock found — run `rhiza sync` first")
            return None
        return TemplateLock.from_yaml(lock_path)
  • _CONFIG_FILES frozenset in summarise.py — replaces the _get_config_files() function (a constant wrapped in a function) with a module-level frozenset[str]

  • _validate_git_host() via StrEnum try/except in init.py — replaces manual _value2member_map_ lookup with idiomatic try/except ValueError on the GitHost() constructor

  • Extract _log_list(header, items) in sync.py — replaces three identical logging loops in _load_template_from_project():

    _log_list("Templates", template.templates)
    _log_list("Include paths", template.include)
    _log_list("Exclude paths", template.exclude)
Original prompt

Overview

Refactor the codebase to eliminate duplicated code patterns across several command modules. The goal is to save approximately 65+ lines of code by applying the following 5 changes:


1. Centralize the LOCK_FILE constant (~8 lines saved)

The string ".rhiza/template.lock" is defined as a module-level constant in three separate files:

  • src/rhiza/commands/status.pyLOCK_FILE = ".rhiza/template.lock"
  • src/rhiza/commands/tree.pyLOCK_FILE = ".rhiza/template.lock"
  • src/rhiza/commands/_sync_helpers.pyLOCK_FILE = ".rhiza/template.lock"

Fix: Keep the definition only in src/rhiza/commands/_sync_helpers.py (it's already there), and import it from there in status.py and tree.py. Remove the duplicate definitions.


2. Extract a shared _load_lock_or_warn(target) helper (~20 lines saved)

Both status.py and tree.py repeat the exact same pattern:

lock_path = (target / LOCK_FILE).resolve()
if not lock_path.exists():
    logger.warning("No template.lock found — run `rhiza sync` first")
    return
lock = TemplateLock.from_yaml(lock_path)

Fix: Add the following helper to src/rhiza/commands/_sync_helpers.py:

def _load_lock_or_warn(target: Path) -> "TemplateLock | None":
    """Load the template.lock file, or log a warning and return None if missing."""
    lock_path = (target / LOCK_FILE).resolve()
    if not lock_path.exists():
        logger.warning("No template.lock found — run `rhiza sync` first")
        return None
    return TemplateLock.from_yaml(lock_path)

Then update status.py and tree.py to use this helper instead of repeating the pattern inline.


3. Replace _get_config_files() with a module-level constant in summarise.py (~12 lines saved)

In src/rhiza/commands/summarise.py, the function _get_config_files() is just a constant wrapped in a function. Replace it with a module-level frozenset:

_CONFIG_FILES: frozenset[str] = frozenset({
    "Makefile",
    "ruff.toml",
    "pytest.ini",
    ".editorconfig",
    ".gitignore",
    ".pre-commit-config.yaml",
    "renovate.json",
    ".python-version",
})

Update all call sites of _get_config_files() in summarise.py to use _CONFIG_FILES directly.


4. Simplify _validate_git_host() in init.py using StrEnum (~10 lines saved)

In src/rhiza/commands/init.py, the function _validate_git_host() manually checks GitHost._value2member_map_. Since GitHost is a StrEnum, use a try/except instead:

def _validate_git_host(git_host: str | None) -> GitHost | None:
    """Validate git_host parameter.

    Args:
        git_host: Git hosting platform.

    Returns:
        Validated GitHost enum value or None.

    Raises:
        ValueError: If git_host is invalid.
    """
    if git_host is None:
        return None
    try:
        return GitHost(git_host.lower())
    except ValueError:
        logger.error(f"Invalid git-host: {git_host}. Must be 'github' or 'gitlab'")
        raise

5. Extract a _log_list() helper in sync.py (~15 lines saved)

In src/rhiza/commands/sync.py, the function _load_template_from_project() repeats the same logging pattern three times. Extract a helper:

def _log_list(header: str, items: list[str]) -> None:
    """Log a labelled list of items, if non-empty."""
    if items:
        logger.info(f"{header}:")
        for item in items:
            logger.info(f"  - {item}")

Then replace the three repeated blocks with:

_log_list("Templates", template.templates)
_log_list("Include paths", template.include)
_log_list("Exclude paths", template.exclude)

Requirements

  • All existing tests must continue to pass.
  • Do not change any public API or CLI behaviour — this is purely internal refactoring.
  • The changes should be applied across the files listed above.
  • Imports should be updated wherever the centralized constant or new helpers are used.

This pull request was created from Copilot chat.


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

@tschm tschm marked this pull request as ready for review March 9, 2026 12:03
Co-authored-by: tschm <2046079+tschm@users.noreply.github.com>
Copilot AI changed the title [WIP] Refactor codebase to eliminate duplicated code patterns refactor: eliminate duplicated code patterns across command modules Mar 9, 2026
Copilot finished work on behalf of tschm March 9, 2026 12:07
@tschm tschm merged commit 9dd5e83 into main Mar 9, 2026
15 checks passed
@tschm tschm deleted the copilot/refactor-duplicate-code-patterns branch March 9, 2026 12:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants