Skip to content

🎨 Palette: Improve CLI output formatting#217

Merged
abhimehro merged 5 commits intomainfrom
palette-improve-cli-output-formatting-43751772871382236
Feb 16, 2026
Merged

🎨 Palette: Improve CLI output formatting#217
abhimehro merged 5 commits intomainfrom
palette-improve-cli-output-formatting-43751772871382236

Conversation

@abhimehro
Copy link
Owner

Improved the CLI output by:

  1. Aligning folder names and rule counts in the dry-run plan output.
  2. Adding comma separators (e.g., 1,234) to rule counts and other large numbers in logs.
  3. Updating print_plan_details to dynamically calculate column widths.

PR created automatically by Jules for task 43751772871382236 started by @abhimehro

Added thousands separators to rule counts and aligned folder names in
`print_plan_details` for better readability. Also added comma formatting
to other log messages.

Co-authored-by: abhimehro <84992105+abhimehro@users.noreply.github.com>
@google-labs-jules
Copy link

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

Copilot AI review requested due to automatic review settings February 13, 2026 22:54
@trunk-io
Copy link

trunk-io bot commented Feb 13, 2026

😎 Merged manually by @abhimehro - details.

@github-actions
Copy link

👋 Development Partner is reviewing this PR. Will provide feedback shortly.

@gemini-code-assist
Copy link

Summary of Changes

Hello @abhimehro, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request focuses on enhancing the user experience of the CLI by refining its output formatting. The changes introduce dynamic alignment for tabular data and apply standard comma separators to large numerical values, making the information presented in dry-run plans and various log messages significantly easier to read and comprehend.

Highlights

  • CLI Output Alignment: Folder names and rule counts in the dry-run plan output are now aligned for better readability.
  • Number Formatting: Large numbers, such as rule counts and other quantities in logs, now include comma separators (e.g., '1,234') for improved clarity.
  • Dynamic Column Widths: The print_plan_details function dynamically calculates column widths to ensure consistent alignment regardless of content length.
Changelog
  • main.py
    • Implemented dynamic column width calculation for folder names and rule counts in the dry-run plan output.
    • Applied comma formatting to rule counts displayed in the dry-run plan output for improved readability.
    • Added comma separators to the total existing rules count in the log.
    • Implemented comma formatting for the total URL count during cache warm-up logging.
    • Updated log messages for rules added in batches to include comma formatting for rule counts.
    • Applied comma formatting to rule counts in folder completion messages, both for standard error and log output.
Activity
  • PR created automatically by Jules for task 43751772871382236, initiated by @abhimehro.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist 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 Review

This pull request improves the CLI output formatting by aligning columns in the plan details and adding comma separators for large numbers, which enhances readability. The changes are well-implemented. I've identified a minor bug and a performance issue in the print_plan_details function and provided a suggestion to refactor it for correctness and efficiency. The rest of the changes look good.

Comment on lines +264 to +282
# Calculate max width for alignment
max_name_len = max(
(len(sanitize_for_log(f.get("name", ""))) for f in folders), default=0
)
max_rules_len = max((len(f"{f.get('rules', 0):,}") for f in folders), default=0)

for folder in sorted(folders, key=lambda f: f.get("name", "")):
name = sanitize_for_log(folder.get("name", "Unknown"))
rules_count = folder.get("rules", 0)
formatted_rules = f"{rules_count:,}"

if USE_COLORS:
print(f" • {Colors.BOLD}{name}{Colors.ENDC}: {rules_count} rules")
print(
f" • {Colors.BOLD}{name:<{max_name_len}}{Colors.ENDC} : {formatted_rules:>{max_rules_len}} rules"
)
else:
print(f" - {name}: {rules_count} rules")
print(
f" - {name:<{max_name_len}} : {formatted_rules:>{max_rules_len}} rules"
)

Choose a reason for hiding this comment

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

high

This implementation has a subtle bug and a performance issue.

Bug: The max_name_len calculation uses f.get("name", ""), but the loop uses folder.get("name", "Unknown"). If a folder has no name, its length will be calculated based on an empty string, but it will be printed as "Unknown" (length 7), which will break the column alignment this PR aims to fix.

Performance: sanitize_for_log() and the rule count formatting are performed for each folder multiple times (once for max length calculation, and again in the printing loop).

I suggest refactoring to pre-process the folder data once. This fixes the bug, improves efficiency by avoiding redundant computations, and also makes the sorting behavior more intuitive by sorting based on the final displayed name.

    # Pre-process folders to get display values and avoid re-computation
    display_data = [
        {
            "name": sanitize_for_log(f.get("name", "Unknown")),
            "formatted_rules": f"{f.get('rules', 0):,}",
        }
        for f in folders
    ]

    # Calculate max width for alignment from pre-processed data
    max_name_len = max((len(f["name"]) for f in display_data), default=0)
    max_rules_len = max((len(f["formatted_rules"]) for f in display_data), default=0)

    for folder in sorted(display_data, key=lambda f: f["name"]):
        name = folder["name"]
        formatted_rules = folder["formatted_rules"]

        if USE_COLORS:
            print(
                f"  • {Colors.BOLD}{name:<{max_name_len}}{Colors.ENDC} : {formatted_rules:>{max_rules_len}} rules"
            )
        else:
            print(
                f"  - {name:<{max_name_len}} : {formatted_rules:>{max_rules_len}} rules"
            )

Copy link

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.

Pull request overview

This PR improves the CLI output formatting by enhancing the visual presentation of the dry-run plan output and adding comma separators to large numbers throughout the logging system.

Changes:

  • Enhanced print_plan_details to dynamically calculate column widths for aligned folder names and rule counts
  • Added comma thousand-separators to rule counts and URL counts in logs for better readability
  • Improved spacing around colons in the plan output (changed from : to :)

Comment on lines +264 to +282
# Calculate max width for alignment
max_name_len = max(
(len(sanitize_for_log(f.get("name", ""))) for f in folders), default=0
)
max_rules_len = max((len(f"{f.get('rules', 0):,}") for f in folders), default=0)

for folder in sorted(folders, key=lambda f: f.get("name", "")):
name = sanitize_for_log(folder.get("name", "Unknown"))
rules_count = folder.get("rules", 0)
formatted_rules = f"{rules_count:,}"

if USE_COLORS:
print(f" • {Colors.BOLD}{name}{Colors.ENDC}: {rules_count} rules")
print(
f" • {Colors.BOLD}{name:<{max_name_len}}{Colors.ENDC} : {formatted_rules:>{max_rules_len}} rules"
)
else:
print(f" - {name}: {rules_count} rules")
print(
f" - {name:<{max_name_len}} : {formatted_rules:>{max_rules_len}} rules"
)
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

The output format changes in print_plan_details will break existing tests. The test assertions in tests/test_plan_details.py (lines 31-32) check for the old format without spaces around the colon (e.g., "Folder A: 10 rules") but the new format has spaces around the colon (e.g., "Folder A : 10 rules"). Additionally, the tests don't account for comma formatting of numbers. The tests need to be updated to match the new format.

Copilot uses AI. Check for mistakes.
- Split `get_validated_input` into `get_validated_input` (public) and `get_password` (sensitive).
- Aligned folder names and rule counts in the dry-run plan output.
- Added thousands separators to rule counts and other large numbers in logs.
- Updated tests to cover new input handling logic.

Co-authored-by: abhimehro <84992105+abhimehro@users.noreply.github.com>
@github-actions
Copy link

👋 Development Partner is reviewing this PR. Will provide feedback shortly.

m.get_password("Prompt: ", lambda x: True, "Error")

# Check exit code is 130
assert e.value.code == 130

Check notice

Code scanning / Bandit

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.

# Check friendly message
captured = capsys.readouterr()
assert "Input cancelled" in captured.out

Check notice

Code scanning / Bandit

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
@pytest.mark.parametrize("exception", [KeyboardInterrupt, EOFError])
def test_get_validated_input_graceful_exit(monkeypatch, capsys, exception):
"""Test graceful exit on user cancellation (Ctrl+C/Ctrl+D) for regular inputs."""
m = reload_main_with_env(monkeypatch)

Check notice

Code scanning / Bandit

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.

# Check friendly cancellation message is displayed
captured = capsys.readouterr()
assert "Input cancelled" in captured.out

Check notice

Code scanning / Bandit

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings February 13, 2026 23:38
@github-actions
Copy link

👋 Development Partner is reviewing this PR. Will provide feedback shortly.

Copy link

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.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment on lines +498 to 510
# Case 12: get_password works with getpass
def test_get_password(monkeypatch):
m = reload_main_with_env(monkeypatch)

getpass_mock = MagicMock(return_value="secret")
monkeypatch.setattr("getpass.getpass", getpass_mock)

validator = lambda x: True

result = m.get_validated_input("Password: ", validator, "Error", is_password=True)
result = m.get_password("Password: ", validator, "Error")

assert result == "secret"
getpass_mock.assert_called_once()
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

The test test_get_password only covers the happy path where the validator returns True. Consider adding a test similar to test_get_validated_input_retry that tests the retry logic for get_password, including:

  • Empty password input (should show "Value cannot be empty")
  • Invalid password that fails validation (should show the error message)
  • Valid password on subsequent retry

This would ensure both functions have equivalent test coverage.

Copilot uses AI. Check for mistakes.
@github-actions
Copy link

👋 Development Partner is reviewing this PR. Will provide feedback shortly.

@github-actions
Copy link

👋 Development Partner is reviewing this PR. Will provide feedback shortly.

@abhimehro abhimehro merged commit 04cb887 into main Feb 16, 2026
14 checks passed
@abhimehro abhimehro deleted the palette-improve-cli-output-formatting-43751772871382236 branch February 16, 2026 02:43
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.

3 participants