Coverage for little_loops / cli / gitignore.py: 19%
36 statements
« prev ^ index » next coverage.py v7.12.0, created at 2026-03-18 16:18 -0500
« prev ^ index » next coverage.py v7.12.0, created at 2026-03-18 16:18 -0500
1"""ll-gitignore: Suggest and apply .gitignore patterns."""
3from __future__ import annotations
5import argparse
6from pathlib import Path
8from little_loops.cli_args import add_config_arg, add_dry_run_arg, add_quiet_arg
9from little_loops.git_operations import (
10 GitignorePattern,
11 add_patterns_to_gitignore,
12 suggest_gitignore_patterns,
13)
14from little_loops.logger import Logger
17def main_gitignore() -> int:
18 """Entry point for ll-gitignore command.
20 Scan for untracked files, suggest .gitignore patterns, and optionally apply them.
22 Returns:
23 Exit code (0 = success, 1 = error)
24 """
25 parser = argparse.ArgumentParser(
26 prog="ll-gitignore",
27 description="Suggest and apply .gitignore patterns based on untracked files",
28 formatter_class=argparse.RawDescriptionHelpFormatter,
29 epilog="""
30Examples:
31 %(prog)s # Show suggestions and apply approved patterns
32 %(prog)s --dry-run # Preview suggestions without modifying .gitignore
33 %(prog)s --quiet # Suppress non-essential output
34""",
35 )
37 add_dry_run_arg(parser)
38 add_quiet_arg(parser)
39 add_config_arg(parser)
41 args = parser.parse_args()
43 repo_root = args.config or Path.cwd()
44 logger = Logger(verbose=not args.quiet)
45 dry_run: bool = args.dry_run
47 if dry_run:
48 logger.info("[DRY RUN] Showing suggestions without modifying .gitignore")
50 suggestion = suggest_gitignore_patterns(repo_root=repo_root, logger=logger)
52 if not suggestion.has_suggestions:
53 logger.info("No .gitignore suggestions — your repo looks clean.")
54 return 0
56 logger.info(suggestion.summary)
58 # Display categorized suggestions
59 categories: dict[str, list[GitignorePattern]] = {}
60 for pattern in suggestion.patterns:
61 categories.setdefault(pattern.category, []).append(pattern)
63 for category, patterns in sorted(categories.items()):
64 logger.info(f"\n [{category}]")
65 for p in patterns:
66 file_count = len(p.files_matched)
67 files_label = f"{file_count} file{'s' if file_count != 1 else ''}"
68 logger.info(f" {p.pattern:<30} {p.description} ({files_label})")
70 if dry_run:
71 return 0
73 pattern_strings = [p.pattern for p in suggestion.patterns]
74 success = add_patterns_to_gitignore(pattern_strings, repo_root=repo_root, logger=logger)
76 return 0 if success else 1