diff --git a/CLAUDE.md b/CLAUDE.md index 8c775e8..13ba42f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -192,6 +192,67 @@ mypy toady/ This guide ensures elegant, maintainable, and well-tested development of toady-cli. +## Click CLI Help Text Formatting Best Practices + +### Key Principles +1. **Use `\b` for preserved formatting** - Prevents Click from rewrapping specific sections +2. **Structure with clear sections** - Use consistent headings like "Examples:", "Options:", "Behavior:" +3. **Provide concrete examples** - Show real command usage, not abstract descriptions +4. **Use consistent indentation** - 2 spaces for section content, 4 spaces for nested items +5. **Keep sections focused** - Each `\b` block should be a logical unit + +### Formatting Template +```python +@click.command() +def example(): + """Brief command description. + + Longer explanation of what the command does and its purpose. + + \b + Behavior: + • Key behavior point 1 + • Key behavior point 2 + • Key behavior point 3 + + \b + Examples: + Basic usage: + command --option value + + Advanced usage: + command --option1 value1 --option2 value2 + + \b + Error codes: + • error_type_1: Description of when this occurs + • error_type_2: Description of when this occurs + """ +``` + +### Key Formatting Rules +- **Use `\b` before each major section** to preserve formatting +- **Use bullet points (•)** for lists instead of dashes or asterisks +- **Indent consistently**: 2 spaces for section headers, 4 spaces for content +- **Separate code examples** with proper indentation (4-6 spaces) +- **Use quotes consistently**: Single quotes for command names, double quotes for strings +- **Keep lines under 80 characters** when possible for terminal compatibility + +### Section Order +1. Brief description (1-2 sentences) +2. Detailed explanation +3. Behavior/Operation modes +4. Examples (most important section) +5. Agent usage patterns (for automation) +6. Validation/Safety notes +7. Error codes + +### Common Issues and Solutions +- **Text wrapping problems**: Use `\b` before each section that needs preserved formatting +- **Inconsistent indentation**: Use 2 spaces for headers, 4+ spaces for code blocks +- **Poor readability**: Break large sections into smaller focused blocks with `\b` +- **Example clarity**: Always show complete, runnable command examples + ## Git Commit and PR Guidelines ### Commit Messages and PR Descriptions diff --git a/README.md b/README.md index aa17cae..564a295 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,19 @@ toady resolve --thread-id abc123def --undo toady resolve --all --pr 123 ``` +### Smart PR Detection + +```bash +# Toady automatically detects your PR context: +# - Single PR: fetches automatically +# - Multiple PRs: shows interactive selection +# - No PRs: displays helpful message +toady fetch + +# Override auto-detection for specific PR +toady fetch --pr 123 +``` + ### Schema Validation ```bash @@ -243,6 +256,38 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file For more detailed documentation, visit our [GitHub Wiki](https://github.com/tonyblank/toady-cli/wiki). +## 🛮️ Troubleshooting + +### Authentication Issues + +- **Run:** `gh auth login` +- **Verify:** `gh auth status` +- **Ensure repo scope:** `gh auth login --scopes repo` + +### Common Errors + +- **"authentication_required":** GitHub CLI not logged in +- **"pr_not_found":** PR doesn't exist or no repository access +- **"rate_limit_exceeded":** Too many API calls, wait and retry +- **"thread_not_found":** Invalid thread ID or thread was deleted + +### Debug Mode + +- **Set TOADY_DEBUG=1** or use `--debug` flag for detailed error info +- **Use `--format pretty`** for human-readable output during testing + +### ID Issues + +- **Always use thread IDs** from `toady fetch` output +- **Use `toady reply --help-ids`** for complete ID documentation +- **Thread IDs** (PRRT_, PRT_, RT_) are more reliable than comment IDs + +### Rate Limiting + +- **Use `--limit` option** to reduce API calls +- **Add delays** between operations in scripts +- **Check limits:** `gh api rate_limit` + ## 🐛 Bug Reports Found a bug? Please [open an issue](https://github.com/tonyblank/toady-cli/issues/new) with a clear description and steps to reproduce. diff --git a/src/toady/cli.py b/src/toady/cli.py index fc31748..b832726 100644 --- a/src/toady/cli.py +++ b/src/toady/cli.py @@ -24,66 +24,68 @@ def cli(ctx: click.Context, debug: bool) -> None: """Toady - GitHub PR review management tool. Efficiently manage GitHub pull request code reviews from the command line. - Integrates with GitHub CLI (`gh`) to fetch, reply to, and resolve review threads. - - PREREQUISITES: - • GitHub CLI (`gh`) must be installed and authenticated - • Run `gh auth login` if not already authenticated - • Ensure you have access to the target repository - - CORE WORKFLOW: - 1. Fetch review threads: `toady fetch --pr 123` - 2. Reply to comments: `toady reply --id --body "Fixed!"` - 3. Resolve threads: `toady resolve --thread-id ` - - AGENT-FRIENDLY USAGE: - • All commands output JSON by default for easy parsing - • Use `--format pretty` for human-readable output - • Thread and comment IDs are consistently formatted - • Error responses include structured error codes - - COMMON PATTERNS: - Interactive workflow: - toady fetch # Select PR interactively - toady reply --id --body "Response" - toady resolve --thread-id - - Automated workflow: - toady fetch --pr 123 --format json | jq '.[] | .thread_id' - toady reply --id --body "Automated response" - toady resolve --all --pr 123 --yes - - For detailed command help: toady --help - For examples and patterns: see examples.md in project repository - - TROUBLESHOOTING: - - Authentication Issues: + Integrates with GitHub CLI (gh) to fetch, reply to, and resolve review threads. + + \b + Prerequisites: + • GitHub CLI (gh) must be installed and authenticated + • Run 'gh auth login' if not already authenticated + • Ensure you have access to the target repository + + \b + Core workflow: + 1. Fetch review threads: toady fetch + 2. Reply to comments: toady reply --id --body "Fixed!" + 3. Resolve threads: toady resolve --thread-id + + \b + Agent-friendly usage: + • All commands output JSON by default for easy parsing + • Use --format pretty for human-readable output + • Thread and comment IDs are consistently formatted + • Error responses include structured error codes + + \b + Common patterns: + \b + Interactive workflow: + toady fetch # Auto-detect PR + toady reply --id --body "Response" + toady resolve --thread-id + \b + Automated workflow: + toady fetch | jq '.[] | .thread_id' + toady reply --id --body "Automated response" + toady resolve --all --pr 123 --yes + \b + Troubleshooting: + \b + Authentication issues: • Run: gh auth login • Verify: gh auth status • Ensure repo scope: gh auth login --scopes repo - - Common Errors: + \b + Common errors: • "authentication_required": GitHub CLI not logged in • "pr_not_found": PR doesn't exist or no repository access • "rate_limit_exceeded": Too many API calls, wait and retry • "thread_not_found": Invalid thread ID or thread was deleted - - Debug Mode: + \b + Debug mode: • Set TOADY_DEBUG=1 or use --debug flag for detailed error info • Use --format pretty for human-readable output during testing - - ID Issues: - • Always use thread IDs from `toady fetch` output - • Use `toady reply --help-ids` for complete ID documentation + \b + ID issues: + • Always use thread IDs from 'toady fetch' output + • Use 'toady reply --help-ids' for complete ID documentation • Thread IDs (PRRT_, PRT_, RT_) are more reliable than comment IDs - - Rate Limiting: + \b + Rate limiting: • Use --limit option to reduce API calls • Add delays between operations in scripts • Check limits: gh api rate_limit - For comprehensive examples: see examples.md + For detailed command help: toady --help """ ctx.ensure_object(dict) ctx.obj["debug"] = debug diff --git a/src/toady/commands/fetch.py b/src/toady/commands/fetch.py index f4c28c4..0d66318 100644 --- a/src/toady/commands/fetch.py +++ b/src/toady/commands/fetch.py @@ -54,69 +54,73 @@ def fetch( ) -> None: """Fetch review threads from a GitHub pull request. - Retrieves review threads (comments that require responses) from GitHub PRs. - Returns structured data containing thread IDs, comment content, authors, and - metadata. - - BEHAVIOR: - • Without --pr: Shows interactive PR selection menu - • With --pr: Fetches from specified pull request number - • Default: Only unresolved threads (threads needing responses) - • With --resolved: Includes both resolved and unresolved threads - - OUTPUT STRUCTURE (JSON): - [ - { - "thread_id": "PRRT_kwDOO3WQIc5Rv3_r", # Use for replies/resolve - "comment_id": "IC_kwDOABcD12MAAAABcDE3fg", # Alternative ID - "body": "Please fix this issue", - "author": "reviewer-username", - "created_at": "2023-01-01T12:00:00Z", - "is_resolved": false, - "pr_number": 123, - "file_path": "src/main.py", - "line_number": 42 - } - ] - - AGENT USAGE PATTERNS: - # Get unresolved threads for processing + Automatically detects and fetches review threads from GitHub PRs. When run + without arguments, intelligently selects the appropriate PR or prompts for + selection when multiple PRs exist. + + \b + Behavior: + • Default: Auto-detects PR (single PR: fetches automatically, multiple: prompts) + • With --pr: Fetches from specified pull request number + • Default: Only unresolved threads (threads needing responses) + • With --resolved: Includes both resolved and unresolved threads + + \b + Output structure (JSON): + [ + { + "thread_id": "PRRT_kwDOO3WQIc5Rv3_r", # Use for replies/resolve + "comment_id": "IC_kwDOABcD12MAAAABcDE3fg", # Alternative ID + "body": "Please fix this issue", + "author": "reviewer-username", + "created_at": "2023-01-01T12:00:00Z", + "is_resolved": false, + "pr_number": 123, + "file_path": "src/main.py", + "line_number": 42 + } + ] + + \b + Examples: + Auto-detect PR (recommended): + toady fetch + + Human-readable output: + toady fetch --format pretty + + Specific PR: toady fetch --pr 123 - # Get all thread IDs for bulk operations - toady fetch --pr 123 | jq '.[].thread_id' + Include resolved threads: + toady fetch --resolved - # Find threads by author - toady fetch --pr 123 | jq '.[] | select(.author == "reviewer")' + Limit results: + toady fetch --limit 50 - INTERACTIVE USAGE: - toady fetch --format pretty # Human-readable output with colors + Pipeline with other tools: + toady fetch | jq '.[].thread_id' | xargs -I {} toady resolve --thread-id {} - EXAMPLES: - Basic fetch (JSON output): - toady fetch --pr 123 + \b + Agent usage patterns: + # Get unresolved threads for processing + toady fetch - Human-readable output: - toady fetch --pr 123 --format pretty + # Get all thread IDs for bulk operations + toady fetch | jq '.[].thread_id' - Include resolved threads: - toady fetch --pr 123 --resolved + # Find threads by author + toady fetch | jq '.[] | select(.author == "reviewer")' - Limit results: - toady fetch --pr 123 --limit 50 + # Target specific PR when multiple exist + toady fetch --pr 123 - Interactive PR selection: - toady fetch - - Pipeline with other tools: - toady fetch --pr 123 | jq '.[].thread_id' | \\ - xargs -I {} toady resolve --thread-id {} - - ERROR CODES: - • authentication_required: GitHub CLI not authenticated - • pr_not_found: Pull request doesn't exist or no access - • no_threads_found: PR has no review threads - • api_rate_limit: GitHub API rate limit exceeded + \b + Error codes: + • authentication_required: GitHub CLI not authenticated + • pr_not_found: Pull request doesn't exist or no access + • no_threads_found: PR has no review threads + • api_rate_limit: GitHub API rate limit exceeded """ # Validate input parameters if pr_number is not None: diff --git a/src/toady/commands/reply.py b/src/toady/commands/reply.py index a29669e..ebc06b9 100644 --- a/src/toady/commands/reply.py +++ b/src/toady/commands/reply.py @@ -53,7 +53,7 @@ def _show_id_help(ctx: click.Context) -> None: 🔍 HOW TO FIND THE RIGHT ID: 1. Use the fetch command: - toady fetch --pr --pretty + toady fetch --format pretty 2. Look for: • "Thread ID:" for thread-level replies (recommended) @@ -82,7 +82,7 @@ def _show_id_help(ctx: click.Context) -> None: 🆘 TROUBLESHOOTING: If you get an error about PRRC_ IDs: -1. Run: toady fetch --pr --pretty +1. Run: toady fetch --format pretty 2. Find the "Thread ID" for that comment 3. Use the thread ID instead @@ -124,7 +124,7 @@ def validate_reply_target_id(reply_to_id: str) -> str: "Individual comment IDs from submitted reviews (PRRC_) " "cannot be replied to directly.\n" "\n💡 Use the thread ID instead:\n" - " • Run: toady fetch --pr --pretty\n" + " • Run: toady fetch --format pretty\n" " • Look for the thread ID (starts with PRRT_, PRT_, or RT_)\n" " • Use that thread ID with --id\n" "\n📖 For more help with ID types, use: toady reply --help-ids", @@ -145,7 +145,7 @@ def validate_reply_target_id(reply_to_id: str) -> str: " • Comment IDs: IC_, RP_ (individual comments)\n" " • Numeric IDs: 123456789 (legacy format)\n\n" "🔍 To find the correct ID:\n" - " • Run: toady fetch --pr --pretty\n" + " • Run: toady fetch --format pretty\n" " • Look for 'Thread ID' or 'Comment ID' in the output\n\n" "📖 For detailed ID help: toady reply --help-ids" ) @@ -508,68 +508,74 @@ def reply( Creates a new comment in response to an existing review thread or comment. Supports various ID formats and provides structured response data. - ID TYPES SUPPORTED: - • Thread IDs: PRRT_, PRT_, RT_ (recommended - most reliable) - • Comment IDs: IC_, RP_ (for individual comments) - • Numeric IDs: 123456789 (legacy GitHub comment IDs) - - IMPORTANT RESTRICTIONS: - • PRRC_ IDs (individual review comments) cannot be replied to directly - • For submitted reviews, always use thread IDs (PRRT_, PRT_, RT_) - • Use thread IDs from `toady fetch` output for best compatibility - - OUTPUT STRUCTURE (JSON): - { - "id": "PRRT_kwDOO3WQIc5Rv3_r", # Original target ID - "success": true, - "reply_posted": true, - "reply_id": "IC_kwDOABcD12MAAAABcDE3fg", # New reply ID - "reply_url": "https://github.com/owner/repo/pull/123#discussion_r987654321", - "created_at": "2023-01-01T12:00:00Z", - "author": "your-username" - } - - AGENT USAGE PATTERNS: - # Standard reply to thread - toady reply --id "PRRT_kwDOO3WQIc5Rv3_r" --body "Fixed in commit abc123" - - # Automated responses - cat responses.txt | while read line; do - toady reply --id "$thread_id" --body "$line" - done - - # Bulk replies with error handling - toady reply --id "$id" --body "$response" || echo "Failed: $id" - - VALIDATION: - • Body: 3-65536 characters, non-empty after trimming - • ID: Must match supported format patterns - • Authentication: Requires GitHub CLI (`gh`) authentication - • Permissions: Must have write access to repository - - EXAMPLES: - Basic reply: - toady reply --id "123456789" --body "Fixed in latest commit" - - Reply to thread (recommended): - toady reply --id "PRRT_kwDOO3WQIc5Rv3_r" --body "Thanks for the review!" - - Reply with verbose output: - toady reply --id "IC_kwDOABcD12MAAAABcDE3fg" --body "Good catch!" --verbose - - Human-readable output: - toady reply --id "PRT_kwDOABcD12MAAAABcDE3fg" \\ - --body "Updated" --format pretty - - Get help with ID types: - toady reply --help-ids - - ERROR CODES: - • comment_not_found: Target comment/thread doesn't exist - • authentication_failed: GitHub CLI not authenticated - • permission_denied: No write access to repository - • validation_error: Invalid ID format or body content - • rate_limit_exceeded: GitHub API rate limit hit + \b + ID types supported: + • Thread IDs: PRRT_, PRT_, RT_ (recommended - most reliable) + • Comment IDs: IC_, RP_ (for individual comments) + • Numeric IDs: 123456789 (legacy GitHub comment IDs) + + \b + Important restrictions: + • PRRC_ IDs (individual review comments) cannot be replied to directly + • For submitted reviews, always use thread IDs (PRRT_, PRT_, RT_) + • Use thread IDs from 'toady fetch' output for best compatibility + + \b + Output structure (JSON): + { + "id": "PRRT_kwDOO3WQIc5Rv3_r", # Original target ID + "success": true, + "reply_posted": true, + "reply_id": "IC_kwDOABcD12MAAAABcDE3fg", # New reply ID + "reply_url": "https://github.com/owner/repo/pull/123#discussion_r987654321", + "created_at": "2023-01-01T12:00:00Z", + "author": "your-username" + } + + \b + Examples: + Basic reply: + toady reply --id "123456789" --body "Fixed in latest commit" + + Reply to thread (recommended): + toady reply --id "PRRT_kwDOO3WQIc5Rv3_r" --body "Thanks for the review!" + + Reply with verbose output: + toady reply --id "IC_kwDOABcD12MAAAABcDE3fg" --body "Good catch!" --verbose + + Human-readable output: + toady reply --id "PRT_kwDOABcD12MAAAABcDE3fg" --body "Updated" --format pretty + + Get help with ID types: + toady reply --help-ids + + \b + Agent usage patterns: + # Standard reply to thread + toady reply --id "PRRT_kwDOO3WQIc5Rv3_r" --body "Fixed in commit abc123" + + # Automated responses + cat responses.txt | while read line; do + toady reply --id "$thread_id" --body "$line" + done + + # Bulk replies with error handling + toady reply --id "$id" --body "$response" || echo "Failed: $id" + + \b + Validation: + • Body: 3-65536 characters, non-empty after trimming + • ID: Must match supported format patterns + • Authentication: Requires GitHub CLI (gh) authentication + • Permissions: Must have write access to repository + + \b + Error codes: + • comment_not_found: Target comment/thread doesn't exist + • authentication_failed: GitHub CLI not authenticated + • permission_denied: No write access to repository + • validation_error: Invalid ID format or body content + • rate_limit_exceeded: GitHub API rate limit hit """ # Show ID help if requested if help_ids: diff --git a/src/toady/commands/resolve.py b/src/toady/commands/resolve.py index 6146a12..ea02e51 100644 --- a/src/toady/commands/resolve.py +++ b/src/toady/commands/resolve.py @@ -634,18 +634,22 @@ def resolve( Changes the resolution status of GitHub review threads, indicating whether the discussion has been addressed. Essential for completing code reviews. - OPERATION MODES: - • Single thread: Use --thread-id to resolve/unresolve one thread - • Bulk operation: Use --all --pr to process all threads in a PR - • Unresolve: Add --undo flag to unresolve instead of resolve - - THREAD ID TYPES: - • Thread IDs: PRT_, PRRT_, RT_ (from `toady fetch` output) - • Numeric IDs: 123456789 (legacy GitHub thread IDs) - • Get IDs from: `toady fetch --pr | jq '.[].thread_id'` - - OUTPUT STRUCTURE (JSON): - Single thread: + \b + Operation modes: + • Single thread: Use --thread-id to resolve/unresolve one thread + • Bulk operation: Use --all --pr to process all threads in a PR + • Unresolve: Add --undo flag to unresolve instead of resolve + + \b + Thread ID types: + • Thread IDs: PRT_, PRRT_, RT_ (from 'toady fetch' output) + • Numeric IDs: 123456789 (legacy GitHub thread IDs) + • Get IDs from: toady fetch | jq '.[].thread_id' + + \b + Output structure (JSON): + + Single thread: { "thread_id": "PRRT_kwDOO3WQIc5RvXMO", "action": "resolve", @@ -654,7 +658,7 @@ def resolve( "thread_url": "https://github.com/owner/repo/pull/123#discussion_r123456" } - Bulk operation: + Bulk operation: { "pr_number": 123, "action": "resolve", @@ -665,53 +669,57 @@ def resolve( "failed_threads": ["RT_kwDOABcD12MAAAABcDE3fg"] } - AGENT USAGE PATTERNS: - # Resolve specific thread - toady resolve --thread-id "PRRT_kwDOO3WQIc5RvXMO" - - # Bulk resolve with error handling - toady resolve --all --pr 123 --yes || echo "Some threads failed" - - # Pipeline: fetch then resolve all - toady fetch --pr 123 | jq -r '.[].thread_id' | while read id; do - toady resolve --thread-id "$id" - done - - VALIDATION & SAFETY: - • Single operations: No confirmation required - • Bulk operations: Confirmation prompt unless --yes flag used - • Thread ID validation: Must match supported format patterns - • Permissions: Requires write access to repository - - EXAMPLES: - Resolve single thread: - toady resolve --thread-id "123456789" - - Resolve with thread node ID: - toady resolve --thread-id "PRRT_kwDOO3WQIc5RvXMO" + \b + Examples: + Resolve single thread: + toady resolve --thread-id "123456789" - Unresolve thread: - toady resolve --thread-id "PRT_kwDOABcD12MAAAABcDE3fg" --undo - - Resolve all threads in PR: - toady resolve --all --pr 123 - - Bulk resolve without confirmation: - toady resolve --all --pr 123 --yes - - Human-readable output: - toady resolve --thread-id "RT_kwDOABcD12MAAAABcDE3fg" --format pretty - - Limited bulk operation: - toady resolve --all --pr 123 --limit 50 + Resolve with thread node ID: + toady resolve --thread-id "PRRT_kwDOO3WQIc5RvXMO" - ERROR CODES: - • thread_not_found: Thread ID doesn't exist or no access - • authentication_failed: GitHub CLI not authenticated - • permission_denied: No write access to repository - • pr_not_found: Pull request doesn't exist (for --all) - • validation_error: Invalid thread ID format - • bulk_operation_partial: Some threads failed in bulk operation + Unresolve thread: + toady resolve --thread-id "PRT_kwDOABcD12MAAAABcDE3fg" --undo + + Resolve all threads in PR: + toady resolve --all --pr 123 + + Bulk resolve without confirmation: + toady resolve --all --pr 123 --yes + + Human-readable output: + toady resolve --thread-id "RT_kwDOABcD12MAAAABcDE3fg" --format pretty + + Limited bulk operation: + toady resolve --all --pr 123 --limit 50 + + \b + Agent usage patterns: + # Resolve specific thread + toady resolve --thread-id "PRRT_kwDOO3WQIc5RvXMO" + + # Bulk resolve with error handling + toady resolve --all --pr 123 --yes || echo "Some threads failed" + + # Pipeline: fetch then resolve all + toady fetch | jq -r '.[].thread_id' | while read id; do + toady resolve --thread-id "$id" + done + + \b + Validation & safety: + • Single operations: No confirmation required + • Bulk operations: Confirmation prompt unless --yes flag used + • Thread ID validation: Must match supported format patterns + • Permissions: Requires write access to repository + + \b + Error codes: + • thread_not_found: Thread ID doesn't exist or no access + • authentication_failed: GitHub CLI not authenticated + • permission_denied: No write access to repository + • pr_not_found: Pull request doesn't exist (for --all) + • validation_error: Invalid thread ID format + • bulk_operation_partial: Some threads failed in bulk operation """ # Resolve format from options try: diff --git a/tests/integration/cli/test_fetch_cli.py b/tests/integration/cli/test_fetch_cli.py index 0e97980..1896283 100644 --- a/tests/integration/cli/test_fetch_cli.py +++ b/tests/integration/cli/test_fetch_cli.py @@ -132,7 +132,7 @@ def test_fetch_help(self, runner: CliRunner) -> None: result = runner.invoke(cli, ["fetch", "--help"]) assert result.exit_code == 0 assert "Fetch review threads from a GitHub pull request" in result.output - assert "EXAMPLES:" in result.output + assert "Examples:" in result.output def test_fetch_pr_parameter_type_validation(self, runner: CliRunner) -> None: """Test that --pr parameter only accepts integers.""" diff --git a/tests/integration/cli/test_reply_cli.py b/tests/integration/cli/test_reply_cli.py index 7023a4c..c2e8e7e 100644 --- a/tests/integration/cli/test_reply_cli.py +++ b/tests/integration/cli/test_reply_cli.py @@ -277,7 +277,7 @@ def test_reply_help_content(self, runner: CliRunner) -> None: result = runner.invoke(cli, ["reply", "--help"]) assert result.exit_code == 0 assert "Post a reply to a specific review comment" in result.output - assert "EXAMPLES:" in result.output + assert "Examples:" in result.output assert "--id" in result.output assert "--body" in result.output @@ -558,7 +558,7 @@ def test_reply_help_ids_flag(self, runner: CliRunner) -> None: assert "NOT SUPPORTED:" in result.output assert "PRRC_kwDOABcD12MAAAABcDE3fg" in result.output assert "HOW TO FIND THE RIGHT ID:" in result.output - assert "toady fetch --pr --pretty" in result.output + assert "toady fetch --format pretty" in result.output assert "TROUBLESHOOTING:" in result.output def test_reply_prrc_id_error_handling(self, runner: CliRunner) -> None: @@ -570,7 +570,7 @@ def test_reply_prrc_id_error_handling(self, runner: CliRunner) -> None: assert result.exit_code == 2 assert "Individual comment IDs from submitted reviews (PRRC_)" in result.output assert "Use the thread ID instead" in result.output - assert "Run: toady fetch --pr --pretty" in result.output + assert "Run: toady fetch --format pretty" in result.output assert ( "Look for the thread ID (starts with PRRT_, PRT_, or RT_)" in result.output ) diff --git a/tests/integration/cli/test_resolve_cli.py b/tests/integration/cli/test_resolve_cli.py index 9c07811..12743c2 100644 --- a/tests/integration/cli/test_resolve_cli.py +++ b/tests/integration/cli/test_resolve_cli.py @@ -368,7 +368,7 @@ def test_resolve_help_content(self, runner: CliRunner) -> None: result = runner.invoke(cli, ["resolve", "--help"]) assert result.exit_code == 0 assert "Mark review threads as resolved or unresolved" in result.output - assert "EXAMPLES:" in result.output + assert "Examples:" in result.output assert "--thread-id" in result.output assert "--undo" in result.output diff --git a/tests/integration/real_api/test_end_to_end_workflows.py b/tests/integration/real_api/test_end_to_end_workflows.py index 18e0a74..6e6885c 100644 --- a/tests/integration/real_api/test_end_to_end_workflows.py +++ b/tests/integration/real_api/test_end_to_end_workflows.py @@ -331,15 +331,16 @@ def test_interactive_workflow_with_multiple_prs( # Should either work with available PRs or skip gracefully if result.exit_code == 0: - # Verify we got valid thread data + # Verify we got valid thread data, or empty output (user cancelled/no PRs) # For JSON format, check stdout only (stderr contains interactive messages) - try: - raw_out = getattr(result, "stdout", result.output) - threads_data = json.loads(raw_out) - assert isinstance(threads_data, list) - except json.JSONDecodeError: - raw_out = getattr(result, "stdout", result.output) - pytest.fail(f"Invalid JSON response in output: {raw_out}") + raw_out = getattr(result, "stdout", result.output) + if raw_out.strip(): # Only parse if there's actual output + try: + threads_data = json.loads(raw_out) + assert isinstance(threads_data, list) + except json.JSONDecodeError: + pytest.fail(f"Invalid JSON response in output: {raw_out}") + # Empty output is valid when user cancels or no PRs available else: # Interactive mode might fail if no PRs available - that's okay assert ( diff --git a/tests/unit/commands/test_reply.py b/tests/unit/commands/test_reply.py index 122c397..60f3795 100644 --- a/tests/unit/commands/test_reply.py +++ b/tests/unit/commands/test_reply.py @@ -502,9 +502,9 @@ def test_id_help_content(self, capsys): assert "NOT SUPPORTED:" in captured.out assert "PRRC_kwDOABcD12MAAAABcDE3fg" in captured.out assert "HOW TO FIND THE RIGHT ID:" in captured.out - assert "toady fetch --pr --pretty" in captured.out + assert "toady fetch --format pretty" in captured.out assert "BEST PRACTICES:" in captured.out - assert "EXAMPLES:" in captured.out + assert "📚 EXAMPLES:" in captured.out assert "TROUBLESHOOTING:" in captured.out ctx.exit.assert_called_once_with(0) diff --git a/tests/unit/test_cli.py b/tests/unit/test_cli.py index 130b9fd..f7beb22 100644 --- a/tests/unit/test_cli.py +++ b/tests/unit/test_cli.py @@ -60,9 +60,9 @@ def test_cli_docstring_present(self): """Test that CLI has comprehensive help documentation.""" assert cli.help is not None assert "Toady - GitHub PR review management tool" in cli.help - assert "PREREQUISITES:" in cli.help - assert "CORE WORKFLOW:" in cli.help - assert "TROUBLESHOOTING:" in cli.help + assert "Prerequisites:" in cli.help + assert "Core workflow:" in cli.help + assert "Troubleshooting:" in cli.help class TestCLIGroupFunctionality: @@ -373,10 +373,10 @@ def test_cli_help_structure(self, runner): "Usage:", "Options:", "Commands:", - "PREREQUISITES:", - "CORE WORKFLOW:", - "AGENT-FRIENDLY USAGE:", - "TROUBLESHOOTING:", + "Prerequisites:", + "Core workflow:", + "Agent-friendly usage:", + "Troubleshooting:", ] for section in expected_sections: