Coverage for lintro / utils / execution / exit_codes.py: 97%

32 statements  

« prev     ^ index     » next       coverage.py v7.13.0, created at 2026-04-03 18:53 +0000

1"""Exit code determination and result aggregation utilities. 

2 

3This module provides functions for determining exit codes and aggregating 

4tool results from linting operations. 

5""" 

6 

7from __future__ import annotations 

8 

9from lintro.enums.action import Action 

10from lintro.models.core.tool_result import ToolResult 

11 

12# Constants 

13DEFAULT_EXIT_CODE_SUCCESS: int = 0 

14DEFAULT_EXIT_CODE_FAILURE: int = 1 

15DEFAULT_REMAINING_COUNT: str = "?" 

16 

17 

18def determine_exit_code( 

19 action: Action, 

20 all_results: list[ToolResult], 

21 total_issues: int, 

22 total_remaining: int, 

23 main_phase_empty_due_to_filter: bool, 

24) -> int: 

25 """Determine final exit code based on results. 

26 

27 Args: 

28 action: The action performed (check/fix/test). 

29 all_results: List of all tool results. 

30 total_issues: Total issues found. 

31 total_remaining: Remaining issues after fix. 

32 main_phase_empty_due_to_filter: Whether main phase was empty due to filtering. 

33 

34 Returns: 

35 Exit code (0=success, 1=failure). 

36 """ 

37 exit_code = DEFAULT_EXIT_CODE_SUCCESS 

38 

39 # Check for tool failures first (applies to all actions) 

40 # Exclude skipped tools — they didn't fail, they just didn't run 

41 if any( 

42 not getattr(r, "success", True) 

43 for r in all_results 

44 if not getattr(r, "skipped", False) 

45 ): 

46 exit_code = DEFAULT_EXIT_CODE_FAILURE 

47 

48 # Then check for issues based on action 

49 if action == Action.FIX: 

50 if total_remaining > 0: 

51 exit_code = DEFAULT_EXIT_CODE_FAILURE 

52 else: # check 

53 if total_issues > 0: 

54 exit_code = DEFAULT_EXIT_CODE_FAILURE 

55 

56 # If all tools were filtered to post-checks but nothing ran, return failure 

57 if main_phase_empty_due_to_filter and not all_results: 

58 exit_code = DEFAULT_EXIT_CODE_FAILURE 

59 

60 return exit_code 

61 

62 

63def aggregate_tool_results( 

64 results: list[ToolResult], 

65 action: Action, 

66) -> tuple[int, int, int]: 

67 """Aggregate results and compute totals. 

68 

69 Args: 

70 results: List of tool results to aggregate. 

71 action: The action performed (determines which counts to aggregate). 

72 

73 Returns: 

74 Tuple of (total_issues, total_fixed, total_remaining). 

75 """ 

76 total_issues = 0 

77 total_fixed = 0 

78 total_remaining = 0 

79 

80 for result in results: 

81 # Exclude skipped tools from totals 

82 if getattr(result, "skipped", False): 

83 continue 

84 total_issues += getattr(result, "issues_count", 0) 

85 

86 if action == Action.FIX: 

87 fixed = getattr(result, "fixed_issues_count", None) 

88 total_fixed += fixed if fixed is not None else 0 

89 remaining = getattr(result, "remaining_issues_count", None) 

90 total_remaining += remaining if remaining is not None else 0 

91 

92 return total_issues, total_fixed, total_remaining