Coverage for lintro / cli_utils / commands / check.py: 84%
73 statements
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2026-04-03 18:53 +0000
1"""Check command implementation for lintro CLI.
3This module provides the core logic for the 'check' command.
5Functions:
6 check_command: CLI command for checking files with various tools.
7 check: Programmatic function for backward compatibility.
8"""
10import sys
12import click
13from click.testing import CliRunner
15from lintro.utils.tool_executor import run_lint_tools_simple
17# Constants
18DEFAULT_PATHS: list[str] = ["."]
19DEFAULT_EXIT_CODE: int = 0
20DEFAULT_ACTION: str = "check"
23@click.command("check")
24@click.argument("paths", nargs=-1, type=click.Path(exists=True))
25@click.option(
26 "--tools",
27 type=str,
28 help='Comma-separated list of tools to run. Use "all" to run all available tools.',
29)
30@click.option(
31 "--tool-options",
32 type=str,
33 help="Tool-specific options in the format tool:option=value,tool:option=value",
34)
35@click.option(
36 "--exclude",
37 type=str,
38 help="Comma-separated list of patterns to exclude from processing",
39)
40@click.option(
41 "--include-venv",
42 is_flag=True,
43 help="Include virtual environment directories in processing",
44)
45@click.option(
46 "--output",
47 type=click.Path(),
48 help="Output file path for writing results",
49)
50@click.option(
51 "--output-format",
52 type=click.Choice(
53 ["plain", "grid", "markdown", "html", "json", "csv", "github", "sarif"],
54 ),
55 default="grid",
56 help="Output format for displaying results",
57)
58@click.option(
59 "--group-by",
60 type=click.Choice(["file", "code", "none", "auto"]),
61 default="file",
62 help="How to group issues in the output",
63)
64@click.option(
65 "--ignore-conflicts",
66 is_flag=True,
67 help="Ignore potential conflicts between tools",
68)
69@click.option(
70 "--verbose",
71 "-v",
72 is_flag=True,
73 help="Show verbose output",
74)
75@click.option(
76 "--no-log",
77 is_flag=True,
78 hidden=True,
79 help="Disable logging to file (not yet implemented)",
80)
81@click.option(
82 "--raw-output",
83 is_flag=True,
84 help="Show raw tool output instead of formatted output",
85)
86@click.option(
87 "--incremental",
88 is_flag=True,
89 help="Only check files that have changed since the last run",
90)
91@click.option(
92 "--no-cache",
93 is_flag=True,
94 help="Clear incremental cache before running (forces full check)",
95)
96@click.option(
97 "--stream/--no-stream",
98 default=False,
99 hidden=True,
100 help="Stream tool output in real-time (not yet implemented)",
101)
102@click.option(
103 "--debug",
104 is_flag=True,
105 help="Enable debug output on console",
106)
107@click.option(
108 "--auto-install",
109 is_flag=True,
110 help="Auto-install Node.js dependencies if node_modules is missing",
111)
112@click.option(
113 "--yes",
114 "-y",
115 is_flag=True,
116 help="Skip confirmation prompt and proceed immediately",
117)
118@click.option(
119 "--fix",
120 "ai_fix",
121 is_flag=True,
122 help="Generate AI fix suggestions (safe fixes auto-apply in CI)",
123)
124def check_command(
125 paths: tuple[str, ...],
126 tools: str | None,
127 tool_options: str | None,
128 exclude: str | None,
129 include_venv: bool,
130 output: str | None,
131 output_format: str,
132 group_by: str,
133 ignore_conflicts: bool,
134 verbose: bool,
135 no_log: bool,
136 raw_output: bool,
137 incremental: bool,
138 no_cache: bool,
139 stream: bool,
140 debug: bool,
141 auto_install: bool,
142 yes: bool,
143 ai_fix: bool,
144) -> None:
145 """Check files for issues using the specified tools.
147 Args:
148 paths: tuple: List of file/directory paths to check.
149 tools: str | None: Comma-separated list of tool names to run.
150 tool_options: str | None: Tool-specific configuration options.
151 exclude: str | None: Comma-separated patterns of files/dirs to exclude.
152 include_venv: bool: Whether to include virtual environment directories.
153 output: str | None: Path to output file for results.
154 output_format: str: Format for displaying results (table, json, etc).
155 group_by: str: How to group issues in output (tool, file, etc).
156 ignore_conflicts: bool: Whether to ignore tool configuration conflicts.
157 verbose: bool: Whether to show verbose output during execution.
158 no_log: bool: Whether to disable logging to file.
159 raw_output: bool: Whether to show raw tool output instead of formatted output.
160 incremental: bool: Whether to only check files changed since last run.
161 no_cache: bool: Whether to clear the incremental cache before running.
162 stream: bool: Whether to stream tool output in real-time.
163 debug: bool: Whether to enable debug output on console.
164 auto_install: bool: Whether to auto-install Node.js deps if missing.
165 yes: bool: Skip confirmation prompt and proceed immediately.
166 ai_fix: bool: Generate AI fix suggestions with interactive review.
168 Raises:
169 SystemExit: Process exit with the aggregated exit code from tools.
170 """
171 # Handle cache clearing
172 if no_cache:
173 from lintro.utils.file_cache import clear_all_caches
175 clear_all_caches()
177 # Add default paths if none provided
178 path_list: list[str] = list(paths) if paths else list(DEFAULT_PATHS)
180 # Build tool-specific options string
181 tool_option_parts: list[str] = []
182 if tool_options:
183 tool_option_parts.append(tool_options)
185 combined_tool_options: str | None = (
186 ",".join(tool_option_parts) if tool_option_parts else None
187 )
189 # Run with simplified approach
190 exit_code: int = run_lint_tools_simple(
191 action=DEFAULT_ACTION,
192 paths=path_list,
193 tools=tools,
194 tool_options=combined_tool_options,
195 exclude=exclude,
196 include_venv=include_venv,
197 group_by=group_by,
198 output_format=output_format,
199 verbose=verbose,
200 raw_output=raw_output,
201 output_file=output,
202 incremental=incremental,
203 debug=debug,
204 stream=stream,
205 no_log=no_log,
206 auto_install=auto_install,
207 yes=yes,
208 ai_fix=ai_fix,
209 ignore_conflicts=ignore_conflicts,
210 )
212 # Exit with code only; CLI uses this as process exit code and avoids any
213 # additional trailing output after the logger's ASCII art.
214 raise SystemExit(exit_code)
217def check(
218 paths: tuple[str, ...],
219 tools: str | None,
220 tool_options: str | None,
221 exclude: str | None,
222 include_venv: bool,
223 output: str | None,
224 output_format: str,
225 group_by: str,
226 ignore_conflicts: bool,
227 verbose: bool,
228 no_log: bool,
229 auto_install: bool = False,
230 yes: bool = False,
231 ai_fix: bool = False,
232) -> None:
233 """Programmatic check function for backward compatibility.
235 Args:
236 paths: tuple: List of file/directory paths to check.
237 tools: str | None: Comma-separated list of tool names to run.
238 tool_options: str | None: Tool-specific configuration options.
239 exclude: str | None: Comma-separated patterns of files/dirs to exclude.
240 include_venv: bool: Whether to include virtual environment directories.
241 output: str | None: Path to output file for results.
242 output_format: str: Format for displaying results (table, json, etc).
243 group_by: str: How to group issues in output (tool, file, etc).
244 ignore_conflicts: bool: Whether to ignore tool configuration conflicts.
245 verbose: bool: Whether to show verbose output during execution.
246 no_log: bool: Whether to disable logging to file.
247 auto_install: bool: Whether to auto-install Node.js deps if missing.
248 yes: bool: Skip confirmation prompt and proceed immediately.
249 ai_fix: bool: Generate AI fix suggestions with interactive review.
251 Returns:
252 None: This function does not return a value.
253 """
254 # Build arguments for the click command
255 args: list[str] = []
256 if paths:
257 args.extend(list(paths))
258 if tools:
259 args.extend(["--tools", tools])
260 if tool_options:
261 args.extend(["--tool-options", tool_options])
262 if exclude:
263 args.extend(["--exclude", exclude])
264 if include_venv:
265 args.append("--include-venv")
266 if output:
267 args.extend(["--output", output])
268 if output_format:
269 args.extend(["--output-format", output_format])
270 if group_by:
271 args.extend(["--group-by", group_by])
272 if ignore_conflicts:
273 args.append("--ignore-conflicts")
274 if verbose:
275 args.append("--verbose")
276 if no_log:
277 args.append("--no-log")
278 if auto_install:
279 args.append("--auto-install")
280 if yes:
281 args.append("--yes")
282 if ai_fix:
283 args.append("--fix")
285 runner = CliRunner()
286 result = runner.invoke(check_command, args)
288 if result.exit_code != DEFAULT_EXIT_CODE:
289 sys.exit(result.exit_code)
290 return None