Skip to content

🧹 Refactor print_plan_details to improve maintainability#789

Open
abhimehro wants to merge 2 commits into
mainfrom
jules-17968531501053853214-4942ccca
Open

🧹 Refactor print_plan_details to improve maintainability#789
abhimehro wants to merge 2 commits into
mainfrom
jules-17968531501053853214-4942ccca

Conversation

@abhimehro
Copy link
Copy Markdown
Owner

@abhimehro abhimehro commented May 14, 2026

🎯 What: Extracted the action text formatting logic from print_plan_details into _get_action_text and _format_action_text helper functions.\n\n💡 Why: print_plan_details was overly long and complex, mixing iteration, printing, and action-label resolution. By extracting the action-label resolution into dedicated helpers, we reduce cyclomatic complexity and improve modularity and readability.\n\n✅ Verification: Ran uv run pytest tests/ to confirm that all tests pass. Formatted and linted code with ruff.\n\n✨ Result: Improved codebase maintainability without changing behavior. The core print logic is now clean and linear.


Open in Devin Review

Copilot AI review requested due to automatic review settings May 14, 2026 13:14
@trunk-io
Copy link
Copy Markdown

trunk-io Bot commented May 14, 2026

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

@cursor
Copy link
Copy Markdown

cursor Bot commented May 14, 2026

PR Summary

Low Risk
Low risk refactor confined to dry-run/CLI output formatting; main risk is minor regression in displayed action labels/icons for mixed or default cases.

Overview
Simplifies print_plan_details by moving the Block/Allow/Mixed/(Default) action-label resolution into _get_action_text() and centralizing color/icon formatting in _format_action_text().

This reduces duplication and cyclomatic complexity in the dry-run plan output path while preserving the existing action-selection behavior (including multi-rule_groups mixed detection and default-to-block fallback).

Reviewed by Cursor Bugbot for commit c3f4b5b. Configure here.

codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 potential issues.

Open in Devin Review

Comment thread main.py Outdated
Comment thread main.py
Comment on lines +580 to +584
def _format_action_text(label: str, icon: str, color: str) -> str:
"""Format action label with appropriate color and icon based on USE_COLORS."""
if USE_COLORS:
return f"({color}{icon} {label}{Colors.ENDC})"
return f"({icon} {label})"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Formatting output is preserved correctly across all action types

Verified that the string formatting in _format_action_text (main.py:580-584) produces identical output to the old inline code for all three cases:

  • Mixed: icon "⚠️ " (emoji+space) + format {icon} {label}⚠️ Mixed (two spaces), matching the old f"(⚠️ {action_label})".
  • Block/Allow: icon "⛔" or "✅" (no trailing space) + format → ⛔ Block or ✅ Allow (one space), matching old code.

Existing tests at tests/test_plan_details.py:41 ("⚠️ Mixed") and tests/test_ux.py:576-578 confirm the expected spacing. The color wrapping logic ({color}{icon} {label}{Colors.ENDC}) also matches the old pattern.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread main.py
Comment on lines +587 to +607
def _get_action_text(folder: dict[str, Any]) -> str:
"""Determine the action label (Block/Allow/Mixed) for a given folder."""
action_val = None

# Check for multiple rule groups first
if "rule_groups" in folder and folder["rule_groups"]:
actions = {rg.get("action") for rg in folder["rule_groups"]}
if len(actions) > 1:
return _format_action_text("Mixed", "⚠️ ", Colors.WARNING)
action_val = next(iter(actions))
# Fallback to single action if not set
elif "action" in folder:
action_val = folder["action"]

if action_val == 0:
return _format_action_text("Block", "⛔", Colors.FAIL)
if action_val == 1:
return _format_action_text("Allow", "✅", Colors.GREEN)

# Default fallback
return _format_action_text("Block (Default)", "⛔", Colors.FAIL)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: New helper functions read module-level globals (USE_COLORS, Colors) same as the old inline code

Both _format_action_text and _get_action_text reference USE_COLORS and Colors as module-level globals, exactly as the old inline code within print_plan_details did. Since USE_COLORS is computed once at import time (and tests monkeypatch it), this extraction doesn't introduce any new issues with global state access. Tests in test_plan_details.py and test_ux.py that patch USE_COLORS will continue to work correctly with the extracted functions.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: elif changes fallback behavior from original sequential checks
    • Replaced the elif with a separate condition so folder-level action is applied whenever rule_groups did not produce 0 or 1, restoring the intended cascade.

Create PR

Or push these changes by commenting:

@cursor push 61cce4f48b
Preview (61cce4f48b)
diff --git a/main.py b/main.py
--- a/main.py
+++ b/main.py
@@ -594,8 +594,7 @@
         if len(actions) > 1:
             return _format_action_text("Mixed", "⚠️ ", Colors.WARNING)
         action_val = next(iter(actions))
-    # Fallback to single action if not set
-    elif "action" in folder:
+    if action_val not in (0, 1) and "action" in folder:
         action_val = folder["action"]
 
     if action_val == 0:

You can send follow-ups to the cloud agent here.

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit c3f4b5b. Configure here.

Comment thread main.py
action_val = next(iter(actions))
# Fallback to single action if not set
elif "action" in folder:
action_val = folder["action"]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

elif changes fallback behavior from original sequential checks

Low Severity

The refactored _get_action_text uses elif to check folder["action"], but the original code used separate if not action_text guards. In the original, when rule_groups existed with a single action value that was neither 0 nor 1 (e.g., None from a missing key), action_text stayed empty and the code fell back to folder["action"]. With elif, the folder["action"] fallback is now unreachable whenever rule_groups is present and truthy, potentially changing the result from the correct action label to "Block (Default)".

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c3f4b5b. Configure here.

Copy link
Copy Markdown

@codescene-delta-analysis codescene-delta-analysis Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Health Improved (1 files improve in Code Health)

Gates Passed
6 Quality Gates Passed

See analysis details in CodeScene

View Improvements
File Code Health Impact Categories Improved
main.py 1.66 → 1.69 Lines of Code in a Single File, Complex Method, Bumpy Road Ahead, Overall Code Complexity, Deep, Nested Complexity

Quality Gate Profile: Pay Down Tech Debt
Install CodeScene MCP: safeguard and uplift AI-generated code. Catch issues early with our IDE extension and CLI tool.

Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

Open in Devin Review

Comment thread main.py
Comment on lines +598 to +601
# Fallback to single top-level action if rule_groups didn't yield a
# recognized action (e.g., empty, missing, or None values).
if action_val not in (0, 1) and "action" in folder:
action_val = folder["action"]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Fallback condition action_val not in (0, 1) is logically equivalent to old if not action_text

The old code used the truthy check if not action_text to determine whether the rule_groups branch had set an action. The new code at main.py:600 uses action_val not in (0, 1) instead. This is equivalent because: (1) if rule_groups yielded action 0 or 1, those are the only values that would have set action_text in the old code; (2) if rule_groups yielded None (from rg.get("action") on a dict without an "action" key), None not in (0, 1) is True, correctly falling through to the top-level folder["action"] check; (3) if rule_groups was empty/missing, action_val stays None (initialized at main.py:589), also correctly falling through.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants