Skip to content

🎨 Palette: UX improvements for CLI dry-run and help text#388

Merged
abhimehro merged 3 commits intomainfrom
palette-ux-improvements-5033950765328649422
Feb 20, 2026
Merged

🎨 Palette: UX improvements for CLI dry-run and help text#388
abhimehro merged 3 commits intomainfrom
palette-ux-improvements-5033950765328649422

Conversation

@abhimehro
Copy link
Owner

💡 What:

  • Added a helpful "Next Steps" section to the dry-run summary table that provides the exact command to run for a live sync.
  • Updated the CLI help message to be more descriptive and friendly.
  • Fixed a bug in validate_hostname where it could return None (implicitly) instead of True.
  • Fixed broken/flaky tests in the test suite to ensure clean verification.

🎯 Why:

  • Users running a dry-run often want to know "what now?". Providing the command reduces friction.
  • A friendly help message aligns with the "Palette" persona of adding delight.
  • Fixing the bug and tests ensures the application is robust and reliable.

📸 Before/After:
Before: Dry run ended with just a summary table (or error logs).
After: Dry run ends with "👉 Ready to sync? Run: python main.py ..."

♿ Accessibility:

  • Used standard ANSI colors safely.
  • Clearer instructions reduce cognitive load.

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

- Add "Next Steps" footer to dry-run output with copy-pasteable command
- Enhance `argparse` help text with friendly description and examples
- Fix logic error in `validate_hostname` (missing return True, unreachable code)
- Fix flaky and broken tests in `tests/`

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 19, 2026 23:03
@trunk-io
Copy link

trunk-io bot commented Feb 19, 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 significantly improves the user experience of the CLI tool and enhances its overall reliability. It introduces a clear 'Next Steps' guide after a dry-run to streamline the process of transitioning to live synchronization, refines the CLI's help text for better clarity and user-friendliness, and addresses a critical bug in hostname validation. Additionally, several test suite issues were resolved to ensure consistent and reliable verification of the application's functionality.

Highlights

  • UX Improvement: Dry-Run Next Steps: Enhanced the dry-run output to include a 'Next Steps' section, providing users with the exact command to execute for a live synchronization, reducing friction and improving usability.
  • CLI Help Text Refinement: Updated the command-line interface's help message to be more descriptive, friendly, and aligned with the 'Palette' persona, adding delight for users.
  • Bug Fix: Hostname Validation: Resolved a bug in the validate_hostname function where it could implicitly return None instead of explicitly True upon successful validation, ensuring correct behavior.
  • Test Suite Reliability: Fixed several broken and flaky tests within the test suite, ensuring consistent and reliable verification of the application's functionality.
Changelog
  • main.py
    • Corrected validate_hostname to explicitly return True when a hostname is successfully validated, preventing implicit None returns.
    • Modified argparse.ArgumentParser to include a more descriptive description and an epilog for enhanced user guidance in the CLI help output.
    • Implemented a new 'Dry Run Next Steps' section that suggests the command to run for live sync, dynamically constructing it based on provided arguments and applying conditional color formatting.
  • tests/test_push_rules_perf.py
    • Removed the self.main = main assignment in the setUp method as it was an unused and unnecessary reference.
  • tests/test_rate_limit.py
    • Applied a @patch decorator to test_429_without_retry_after_uses_exponential_backoff to mock random.random, ensuring deterministic behavior for exponential backoff tests.
  • tests/test_retry_jitter.py
    • Ensured response.headers is initialized as an empty dictionary within test_429_rate_limit_retries_with_jitter to prevent AttributeError when accessing headers in test mocks.
Activity
  • PR created automatically by Jules for task 5033950765328649422, 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

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’s user experience by enhancing dry-run output with a “Next Steps” hint, refreshing the help text messaging, and tightening correctness around hostname validation while stabilizing parts of the test suite.

Changes:

  • Add a dry-run “Next Steps” section that prints a suggested live-run command.
  • Update argparse help description/epilog text to be more user-friendly.
  • Fix validate_hostname to always return a boolean, and adjust tests for rate-limit/jitter behavior.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
main.py Adds dry-run “Next Steps” command suggestion, updates CLI help text, and fixes validate_hostname boolean return.
tests/test_retry_jitter.py Ensures mocked 429 responses include headers dict to match production expectations.
tests/test_rate_limit.py Makes jitter deterministic in a 429 backoff test by patching random.random.
tests/test_push_rules_perf.py Removes an unnecessary self.main assignment in setUp.

main.py Outdated
Comment on lines +2692 to +2707
# Construct command suggestion
cmd_parts = ["python", "main.py"]
if profile_ids:
# Join multiple profiles if needed
p_str = ",".join(profile_ids)
cmd_parts.append(f"--profiles {p_str}")
else:
cmd_parts.append("--profiles <your-profile-id>")

# Reconstruct other args if they were used (optional but helpful)
if args.folder_url:
for url in args.folder_url:
cmd_parts.append(f"--folder-url {url}")

cmd_str = " ".join(cmd_parts)
print(f" {Colors.CYAN}{cmd_str}{Colors.ENDC}")
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

The suggested dry-run command is built by concatenating raw user-provided values (profile IDs / folder URLs) into a single string without shell-quoting or sanitization. This can produce a copy/paste command that breaks for URLs containing special characters/spaces and also risks echoing secrets (e.g., basic-auth or token query params) and terminal control characters into logs/CI output. Consider constructing the command as a list of discrete args (e.g., ['--profiles', p_str], repeated ['--folder-url', url]) and rendering it with shlex.join/shlex.quote; additionally, avoid printing sensitive URL components (or detect/redact and warn when redaction occurs).

Copilot uses AI. Check for mistakes.
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 introduces several nice UX improvements for the CLI, such as a more friendly help message and a 'Next Steps' guide after a dry run. It also includes important bug fixes for hostname validation and flaky tests. The changes are well-implemented. I've left one suggestion to refactor the new dry-run command construction to fix a minor bug and reduce code duplication. Overall, great work on improving the user experience and robustness of the tool.

Comment on lines +2688 to +2718
if all_success:
if USE_COLORS:
print(f"{Colors.BOLD}👉 Ready to sync? Run the following command:{Colors.ENDC}")

# Construct command suggestion
cmd_parts = ["python", "main.py"]
if profile_ids:
# Join multiple profiles if needed
p_str = ",".join(profile_ids)
cmd_parts.append(f"--profiles {p_str}")
else:
cmd_parts.append("--profiles <your-profile-id>")

# Reconstruct other args if they were used (optional but helpful)
if args.folder_url:
for url in args.folder_url:
cmd_parts.append(f"--folder-url {url}")

cmd_str = " ".join(cmd_parts)
print(f" {Colors.CYAN}{cmd_str}{Colors.ENDC}")
else:
print("👉 Ready to sync? Run the following command:")
p_str = ",".join(profile_ids) if profile_ids else "<your-profile-id>"
print(f" python main.py --profiles {p_str}")
else:
if USE_COLORS:
print(
f"{Colors.FAIL}⚠️ Dry run encountered errors. Please check the logs above.{Colors.ENDC}"
)
else:
print("⚠️ Dry run encountered errors. Please check the logs above.")

Choose a reason for hiding this comment

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

medium

There's a bit of duplicated logic for constructing the command suggestion, and a bug in the else block for when USE_COLORS is false. The command suggestion for the no-color case is missing the --folder-url arguments that might have been passed.

You can refactor this block to build the command string first, and then print it with or without colors. This will fix the bug and make the code DRY (Don't Repeat Yourself).

        if all_success:
            # Construct command suggestion
            cmd_parts = ["python", "main.py"]
            if profile_ids:
                p_str = ",".join(profile_ids)
                cmd_parts.append(f"--profiles {p_str}")
            else:
                cmd_parts.append("--profiles <your-profile-id>")

            # Reconstruct other args if they were used (optional but helpful)
            if args.folder_url:
                for url in args.folder_url:
                    cmd_parts.append(f"--folder-url {url}")
            
            cmd_str = " ".join(cmd_parts)

            if USE_COLORS:
                print(f"{Colors.BOLD}👉 Ready to sync? Run the following command:{Colors.ENDC}")
                print(f"   {Colors.CYAN}{cmd_str}{Colors.ENDC}")
            else:
                print("👉 Ready to sync? Run the following command:")
                print(f"   {cmd_str}")
        else:
            if USE_COLORS:
                print(
                    f"{Colors.FAIL}⚠️  Dry run encountered errors. Please check the logs above.{Colors.ENDC}"
                )
            else:
                print("⚠️  Dry run encountered errors. Please check the logs above.")

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

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


def test_429_without_retry_after_uses_exponential_backoff(self):
@patch("random.random", return_value=0.5)
def test_429_without_retry_after_uses_exponential_backoff(self, mock_random):

Check warning

Code scanning / Prospector (reported by Codacy)

Unused argument 'mock_random' (unused-argument) Warning test

Unused argument 'mock_random' (unused-argument)
main.py Outdated

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Line too long (104/100) Warning

Line too long (104/100)
main.py Outdated

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Line too long (109/100) Warning

Line too long (109/100)

def test_429_without_retry_after_uses_exponential_backoff(self):
@patch("random.random", return_value=0.5)
def test_429_without_retry_after_uses_exponential_backoff(self, mock_random):

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Method could be a function Warning test

Method could be a function

def test_429_without_retry_after_uses_exponential_backoff(self):
@patch("random.random", return_value=0.5)
def test_429_without_retry_after_uses_exponential_backoff(self, mock_random):

Check notice

Code scanning / Pylintpython3 (reported by Codacy)

Unused argument 'mock_random' Note test

Unused argument 'mock_random'
main.py Outdated

Check warning

Code scanning / Pylint (reported by Codacy)

Line too long (104/100) Warning

Line too long (104/100)
main.py Outdated

Check warning

Code scanning / Pylint (reported by Codacy)

Line too long (109/100) Warning

Line too long (109/100)

def test_429_without_retry_after_uses_exponential_backoff(self):
@patch("random.random", return_value=0.5)
def test_429_without_retry_after_uses_exponential_backoff(self, mock_random):

Check warning

Code scanning / Pylint (reported by Codacy)

Method could be a function Warning test

Method could be a function

def test_429_without_retry_after_uses_exponential_backoff(self):
@patch("random.random", return_value=0.5)
def test_429_without_retry_after_uses_exponential_backoff(self, mock_random):

Check notice

Code scanning / Pylint (reported by Codacy)

Unused argument 'mock_random' Note test

Unused argument 'mock_random'
@github-actions
Copy link

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

@abhimehro abhimehro merged commit 717998b into main Feb 20, 2026
14 checks passed
@abhimehro abhimehro deleted the palette-ux-improvements-5033950765328649422 branch February 20, 2026 03:00
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