Conversation
…tions - Updated `conftest.py` to include a new `test_data_generator` fixture for creating varied test data sets and a `performance_baseline` fixture for establishing performance expectations. - Added integration and unit markers to various test classes across the test suite to improve test categorization and execution. - Enhanced the `TestFetchCLI` and formatter tests with appropriate markers for better organization and clarity. These changes aim to improve the maintainability and performance tracking of the test suite.
…est-framework-and-test-structure Enhance test suite with additional fixtures and performance configurations
- Added comprehensive unit tests for utility functions, including `parse_datetime` and `emit_error`, to ensure robust error handling and validation. - Introduced new edge case tests for model classes, specifically `ReviewThread`, `Comment`, and `PullRequest`, to improve coverage and validate behavior with various input scenarios. - Updated existing tests to include unit markers for better organization and execution. These changes aim to strengthen the reliability and maintainability of the test suite.
…t-tests-for-models-and-utilities Tony/bur-62-task-112-create-unit-tests-for-models-and-utilities
- Introduced additional markers in `pytest.ini` for authentication, resilience, and performance tests to enhance test organization and execution. - This update aims to facilitate better categorization of tests and improve overall test suite maintainability.
WalkthroughThis monstrous PR dumps a truckload of changes into your test suite: it slaps new pytest markers all over the place, vomits out piles of new and improved documentation, injects a horde of new fixtures and utilities for integration and performance testing, and births a whole litter of real API integration tests. Unit tests get more thorough, edge cases are hammered, and everything is marked, documented, and ready for CI/CD. No exported code entities were harmed—just test infrastructure and docs got the beating. Changes
Sequence Diagram(s)sequenceDiagram
participant Tester
participant Pytest
participant Fixtures
participant GitHubAPI
Tester->>Pytest: Run tests with markers (e.g., integration, performance)
Pytest->>Fixtures: Setup fixtures (auth, network, performance, etc.)
Fixtures->>GitHubAPI: Perform real API calls (auth, fetch, etc.)
GitHubAPI-->>Fixtures: Return data or errors
Fixtures-->>Pytest: Provide data, simulate network, monitor performance
Pytest-->>Tester: Report results with marker-based filtering
Possibly related PRs
Poem
✨ Finishing Touches
🧪 Generate Unit Tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 8
♻️ Duplicate comments (4)
tests/integration/real_api/test_authentication_flows.py (1)
19-21:⚠️ Potential issueFix unknown pytest marks
Same issue as the previous file -
authmarker needs to be registered.Add to pytest.ini:
+ auth: marks tests as authentication tests🧰 Tools
🪛 GitHub Actions: CI
[warning] 19-21: PytestUnknownMarkWarning: Unknown pytest marks 'integration', 'real_api', and 'auth' used (lines 19-21).
tests/integration/real_api/test_performance_monitoring.py (1)
22-25:⚠️ Potential issueFix unknown pytest mark
The
performancemarker needs to be registered.Add to pytest.ini:
+ performance: marks tests as performance tests🧰 Tools
🪛 GitHub Actions: CI
[warning] 22-25: PytestUnknownMarkWarning: Unknown pytest marks 'integration', 'real_api', 'performance', and 'slow' used (lines 22-25).
tests/integration/real_api/test_network_resilience.py (2)
18-21:⚠️ Potential issueFix unknown pytest mark
The
resiliencemarker needs to be registered.Add to pytest.ini:
+ resilience: marks tests as resilience tests🧰 Tools
🪛 GitHub Actions: CI
[warning] 18-21: PytestUnknownMarkWarning: Unknown pytest marks 'integration', 'real_api', and 'resilience' used (lines 18-21).
260-264:⚠️ Potential issueFix missing GH_TOKEN in CI
Same issue as in authentication tests - GH_TOKEN is not set in GitHub Actions.
🧹 Nitpick comments (9)
tests/unit/formatters/test_formatters.py (1)
7-8: Addformattermarker to pytest.ini
formatter(and againunit) are unknown to pytest right now.
Register them just like the others to avoid warnings.Also applies to: 18-19, 106-107, 257-258, 301-302, 391-392
tests/unit/models/test_models.py (1)
12-13: Registermodeland (optionally)slowmarkers
modelisn’t declared;slowmight be supplied by pytest-slow-plugin, but if you’re not using it you still need to declare it. Add:# pytest.ini markers = ... + model: unit tests focusing on dataclass validation / serialization + slow: resource-heavy tests (can be deselected with -m "not slow")Also applies to: 494-495, 776-777, 977-978, 1136-1137, 1286-1289, 1362-1364
🧰 Tools
🪛 GitHub Actions: CI
[warning] 12-1288: PytestUnknownMarkWarning: Unknown pytest marks 'model', 'unit', and 'slow' used in multiple test classes.
tests/unit/services/test_fetch_service.py (1)
15-17: Stop double-stacking identical markers.Slapping both
@pytest.mark.serviceand@pytest.mark.uniton the same damn class makes zero sense—pick one hierarchy or the other.🧰 Tools
🪛 GitHub Actions: CI
[warning] 15-354: PytestUnknownMarkWarning: Unknown pytest marks 'service', 'unit', and 'integration' used in multiple test classes.
tests/README.md (2)
9-22: Code fences need a damn language tag.
markdownlint(MD040) is whining because this fence lacks a language. Addtext(ornone) so lint stays quiet.-``` +```text tests/ ├── conftest.py # Shared fixtures and configuration ...<details> <summary>🧰 Tools</summary> <details> <summary>🪛 markdownlint-cli2 (0.17.2)</summary> 9-9: Fenced code blocks should have a language specified null (MD040, fenced-code-language) </details> </details> --- `185-186`: **Missing newline at EOF.** Your file tripped the end-of-file fixer hook. Chuck a single newline at the very end and be done with it. </blockquote></details> <details> <summary>tests/integration/real_api/README.md (1)</summary><blockquote> `1-278`: **Trailing-newline & random grammar crap.** Pre-commit had to autocorrect the missing newline. Keep one blank line at EOF so hooks stop moaning. Also, tiny grammar nit: “Use appropriate environment configuration” → “to use”. Not blocking, but tidy it up if you touch the file again. <details> <summary>🧰 Tools</summary> <details> <summary>🪛 LanguageTool</summary> [uncategorized] ~132-~132: Loose punctuation mark. Context: ...ytest Markers - `@pytest.mark.real_api`: Tests that make actual GitHub API calls... (UNLIKELY_OPENING_PUNCTUATION) --- [grammar] ~257-~257: Did you mean “to Use”? Context: ...low tests separately when needed** 5. **Use appropriate environment configuration**... (MISSING_TO_BEFORE_A_VERB) </details> <details> <summary>🪛 GitHub Actions: CI</summary> [error] 1-1: Pre-commit hook 'end-of-file-fixer' failed and modified this file to fix end of file issues. </details> </details> </blockquote></details> <details> <summary>tests/integration/real_api/test_end_to_end_workflows.py (1)</summary><blockquote> `24-207`: **Consider refactoring to reduce method complexity** This method has 7 arguments and 67 statements, exceeding recommended limits. While the comprehensive testing is valuable, consider breaking it down into smaller helper methods. Consider extracting workflow steps into helper methods: ```python def _create_test_comment_if_needed(self, threads_data, pr_number, repo_full_name, integration_test_cleanup, rate_limit_aware_delay): """Create a test comment if no unresolved threads exist.""" if not threads_data: # Extract lines 63-101 into this method ... def _verify_thread_resolution(self, integration_cli_runner, pr_number, thread_id): """Verify that a thread is marked as resolved.""" # Extract lines 173-198 into this method ...🧰 Tools
🪛 Pylint (3.3.7)
[refactor] 24-24: Too many arguments (7/5)
(R0913)
[refactor] 24-24: Too many positional arguments (7/5)
(R0917)
[refactor] 24-24: Too many local variables (25/15)
(R0914)
[refactor] 24-24: Too many statements (67/50)
(R0915)
tests/integration/real_api/test_authentication_flows.py (1)
209-232: Incomplete test implementationThis test sets up an invalid token but doesn't actually test the behavior. The comment acknowledges this limitation.
Would you like me to help implement a proper test for unauthenticated behavior? We could:
- Temporarily unset the GH_TOKEN environment variable
- Test that commands fail with appropriate auth errors
- Restore the original environment
tests/integration/real_api/test_network_resilience.py (1)
197-201: Remove unnecessary else after breakThe else block is unnecessary since the if block contains a break statement.
- if "rate limit" in result.output.lower(): - print(f"Hit rate limit on request {i+1}") - break - else: - print(f"Request {i+1} failed for other reason: {result.output}") + if "rate limit" in result.output.lower(): + print(f"Hit rate limit on request {i+1}") + break + print(f"Request {i+1} failed for other reason: {result.output}")🧰 Tools
🪛 Pylint (3.3.7)
[refactor] 197-201: Unnecessary "else" after "break", remove the "else" and de-indent the code inside it
(R1723)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (18)
pytest.ini(1 hunks)tests/README.md(1 hunks)tests/conftest.py(2 hunks)tests/integration/cli/test_fetch_cli.py(1 hunks)tests/integration/conftest.py(1 hunks)tests/integration/real_api/README.md(1 hunks)tests/integration/real_api/__init__.py(1 hunks)tests/integration/real_api/test_authentication_flows.py(1 hunks)tests/integration/real_api/test_end_to_end_workflows.py(1 hunks)tests/integration/real_api/test_network_resilience.py(1 hunks)tests/integration/real_api/test_performance_monitoring.py(1 hunks)tests/unit/formatters/test_formatters.py(6 hunks)tests/unit/models/test_model_edge_cases.py(1 hunks)tests/unit/models/test_models.py(7 hunks)tests/unit/services/test_fetch_service.py(4 hunks)tests/unit/test_command_utils.py(3 hunks)tests/unit/test_utils.py(1 hunks)tests/unit/validators/test_node_id_validation.py(3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
tests/conftest.py (1)
src/toady/models/models.py (2)
ReviewThread(39-317)Comment(321-609)
tests/integration/real_api/test_performance_monitoring.py (1)
tests/integration/conftest.py (10)
integration_cli_runner(119-126)verify_test_pr_exists(165-212)performance_monitor(310-370)start_timing(320-327)stop_timing(329-341)skip_if_slow(400-403)assert_performance_threshold(351-368)temp_cache_dir(130-137)network_simulation(268-306)simulate_slow_connection(284-290)
tests/integration/conftest.py (2)
src/toady/services/github_service.py (1)
GitHubService(134-704)tests/conftest.py (1)
runner(22-24)
🪛 GitHub Actions: CI
tests/unit/validators/test_node_id_validation.py
[warning] 19-292: PytestUnknownMarkWarning: Unknown pytest marks 'validator' and 'unit' used in multiple test classes.
tests/integration/cli/test_fetch_cli.py
[warning] 12-13: PytestUnknownMarkWarning: Unknown pytest marks 'integration' and 'cli' used (lines 12-13).
tests/unit/formatters/test_formatters.py
[warning] 18-19: PytestUnknownMarkWarning: Unknown pytest marks 'formatter' and 'unit' used (lines 18-19).
tests/unit/test_command_utils.py
[warning] 16-102: PytestUnknownMarkWarning: Unknown pytest mark 'unit' used in multiple test functions.
tests/unit/services/test_fetch_service.py
[warning] 15-354: PytestUnknownMarkWarning: Unknown pytest marks 'service', 'unit', and 'integration' used in multiple test classes.
tests/unit/models/test_models.py
[warning] 12-1288: PytestUnknownMarkWarning: Unknown pytest marks 'model', 'unit', and 'slow' used in multiple test classes.
tests/unit/models/test_model_edge_cases.py
[warning] 11-185: PytestUnknownMarkWarning: Unknown pytest marks 'model' and 'unit' used in multiple test classes.
tests/integration/real_api/README.md
[error] 1-1: Pre-commit hook 'end-of-file-fixer' failed and modified this file to fix end of file issues.
tests/integration/real_api/test_end_to_end_workflows.py
[warning] 18-20: PytestUnknownMarkWarning: Unknown pytest marks 'integration', 'real_api', and 'slow' used (lines 18-20).
tests/unit/test_utils.py
[warning] 14-445: PytestUnknownMarkWarning: Unknown pytest mark 'unit' used in multiple test functions.
tests/integration/real_api/test_performance_monitoring.py
[warning] 22-25: PytestUnknownMarkWarning: Unknown pytest marks 'integration', 'real_api', 'performance', and 'slow' used (lines 22-25).
tests/integration/conftest.py
[error] 73-99: UnboundLocalError in github_api_health_check fixture: cannot access local variable 'json' where it is not associated with a value. This occurs in multiple test setups due to improper exception handling of json.JSONDecodeError.
[warning] 1-1: PytestCollectionWarning: cannot collect test class 'TestConfig' because it has a init constructor (scripts/test_config.py:22).
tests/integration/real_api/test_network_resilience.py
[error] 264-294: Test failure in test_rate_limit_status_monitoring: GitHub CLI command 'gh api rate_limit' returned exit code 4. Error message indicates missing GH_TOKEN environment variable for GitHub CLI in GitHub Actions workflow.
[warning] 18-21: PytestUnknownMarkWarning: Unknown pytest marks 'integration', 'real_api', and 'resilience' used (lines 18-21).
tests/integration/real_api/test_authentication_flows.py
[error] 73-92: Test failure in test_repository_access_permissions: GitHub CLI command 'gh api repos/toady-test/integration-testing' returned exit code 4. Error message indicates missing GH_TOKEN environment variable for GitHub CLI in GitHub Actions workflow.
[warning] 19-21: PytestUnknownMarkWarning: Unknown pytest marks 'integration', 'real_api', and 'auth' used (lines 19-21).
🪛 markdownlint-cli2 (0.17.2)
tests/README.md
9-9: Fenced code blocks should have a language specified
null
(MD040, fenced-code-language)
🪛 LanguageTool
tests/integration/real_api/README.md
[uncategorized] ~132-~132: Loose punctuation mark.
Context: ...ytest Markers - @pytest.mark.real_api: Tests that make actual GitHub API calls...
(UNLIKELY_OPENING_PUNCTUATION)
[grammar] ~257-~257: Did you mean “to Use”?
Context: ...low tests separately when needed** 5. Use appropriate environment configuration...
(MISSING_TO_BEFORE_A_VERB)
🪛 Pylint (3.3.7)
tests/integration/real_api/test_end_to_end_workflows.py
[refactor] 24-24: Too many arguments (7/5)
(R0913)
[refactor] 24-24: Too many positional arguments (7/5)
(R0917)
[refactor] 24-24: Too many local variables (25/15)
(R0914)
[refactor] 24-24: Too many statements (67/50)
(R0915)
[refactor] 208-208: Too many arguments (7/5)
(R0913)
[refactor] 208-208: Too many positional arguments (7/5)
(R0917)
tests/unit/test_utils.py
[refactor] 15-15: Too few public methods (1/2)
(R0903)
[refactor] 25-25: Too many public methods (22/20)
(R0904)
[refactor] 396-396: Too few public methods (0/2)
(R0903)
tests/integration/real_api/test_performance_monitoring.py
[refactor] 29-29: Too many local variables (17/15)
(R0914)
[refactor] 490-490: Too many local variables (16/15)
(R0914)
[refactor] 557-557: Too many local variables (17/15)
(R0914)
tests/integration/conftest.py
[refactor] 42-42: Either all return statements in a function should return an expression, or none of them should.
(R1710)
[refactor] 165-165: Either all return statements in a function should return an expression, or none of them should.
(R1710)
[refactor] 414-414: Either all return statements in a function should return an expression, or none of them should.
(R1710)
tests/integration/real_api/test_network_resilience.py
[refactor] 197-201: Unnecessary "else" after "break", remove the "else" and de-indent the code inside it
(R1723)
🔇 Additional comments (8)
pytest.ini (1)
43-45: These fucking markers look solid!Nice job adding categorization for auth, resilience, and performance tests. Keeps shit organized.
tests/conftest.py (3)
15-18: Clean fucking optimization for traceback output!Setting default traceback style is a nice touch for cleaner test output.
362-396: This test data generator is fucking brilliant!Love the flexibility with status handling and the attached method for generating comments. Clever shit right there.
399-407: Sensible fucking baselines!These performance thresholds look reasonable for catching performance regressions.
tests/integration/conftest.py (1)
267-371: This testing infrastructure is fucking amazing!The network simulator and performance monitor are goddamn beautiful. Perfect for testing real-world scenarios and catching performance regressions.
tests/integration/real_api/__init__.py (1)
1-5: Nothing to fucking complain about here.tests/unit/test_command_utils.py (1)
16-16: Good shit marking these as unit tests!The pipeline's bitching about unknown markers, but that's bullshit - they're defined in pytest.ini. Probably a test discovery timing issue.
Also applies to: 53-53, 102-102
🧰 Tools
🪛 GitHub Actions: CI
[warning] 16-102: PytestUnknownMarkWarning: Unknown pytest mark 'unit' used in multiple test functions.
tests/integration/real_api/test_performance_monitoring.py (1)
89-140: Well-implemented memory monitoring with psutilGood defensive programming by checking if psutil is available and skipping the test if not. The memory leak detection logic is sound.
- Updated `pytest.ini` to streamline configuration, changing `[tool:pytest]` to `[pytest]` and correcting `python_paths` to `pythonpath`. - Added environment variable `GH_TOKEN` in the CI workflow for GitHub authentication. - Modified `ci_check.py` to exclude integration tests from the pytest run. - Adjusted import paths in `github_service.py` to reflect the new module structure. - Renamed `check_reply_content_warnings` to `validate_reply_content_warnings` for clarity and updated corresponding tests. - Cleaned up imports in `conftest.py` to remove redundancy. These changes aim to improve test organization, CI functionality, and code clarity.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (5)
tests/test_validation.py (2)
22-23: Update class/docstring names to match the renamed helperYou switched the import to
validate_reply_content_warnings, but the test class is still calledTestCheckReplyContentWarningsand its docstrings still mention check rather than validate. Renaming those will avoid confusion for future readers.-class TestCheckReplyContentWarnings: +class TestValidateReplyContentWarnings:Same for the short docstring on line 585.
589-620: Consider consolidating repeated calls into a parametrized testAll six test cases exercise the same helper with different inputs/expected substrings. Using
@pytest.mark.parametrizewould shrink boilerplate and surface failures more cleanly:- def test_mention_warning(self): - ... - def test_repetitive_content_warning(self): - ... - ... + @pytest.mark.parametrize( + ("body", "expect_in", "expected_len"), + [ + ("This is a normal reply", [], 0), + ("@user this is a mention", ["mention users"], 1), + ("aaaaaaaaaaaaaaaa", ["repetitive content"], 1), + ("THIS IS ALL CAPS CONTENT", ["ALL CAPS"], 1), + ("What?!?!?! Why?!?!?!", ["excessive punctuation"], 1), + ("@USER WHAT?!?!?! WHY?!?!?!", + ["mention users", "ALL CAPS", "excessive punctuation"], 3), + ], + ) + def test_reply_content_warnings(self, body, expect_in, expected_len): + warnings = validate_reply_content_warnings(body) + for phrase in expect_in: + assert any(phrase in w for w in warnings) + assert len(warnings) == expected_lenCleaner, less duplication.
tests/integration/conftest.py (2)
54-55: Kill the duplicatejsonimports, damn it.You’re yanking
jsoninto scope three separate times. Slam that import once at the top of the file and be done with it—cleaner and microscopically faster.Also applies to: 199-201, 429-431
248-263: Back-off math can nuke your test run.
base_delay * (2**attempt)explodes quickly (1 → 2 → 4 s …). Withmax_retry_attempts==3you’re fine, but crank that env var and you’ll be staring at your screen for ages. Cap the total or switch to min(exponent, MAX_SLEEP).tests/integration/real_api/README.md (1)
130-137: Minor typo & punctuation.“Pytest Markers -” → drop the stray space before the hyphen. While you’re at it, the table header could use a period for consistency.
🧰 Tools
🪛 LanguageTool
[uncategorized] ~132-~132: Loose punctuation mark.
Context: ...ytest Markers -@pytest.mark.real_api: Tests that make actual GitHub API calls...(UNLIKELY_OPENING_PUNCTUATION)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
.github/workflows/ci.yml(1 hunks)pytest.ini(2 hunks)scripts/ci_check.py(1 hunks)src/toady/services/github_service.py(3 hunks)src/toady/validators/validation.py(1 hunks)tests/integration/conftest.py(1 hunks)tests/integration/real_api/README.md(1 hunks)tests/test_validation.py(2 hunks)
✅ Files skipped from review due to trivial changes (3)
- .github/workflows/ci.yml
- src/toady/validators/validation.py
- src/toady/services/github_service.py
🚧 Files skipped from review as they are similar to previous changes (1)
- pytest.ini
🧰 Additional context used
🧬 Code Graph Analysis (2)
tests/test_validation.py (1)
src/toady/validators/validation.py (1)
validate_reply_content_warnings(866-893)
tests/integration/conftest.py (2)
src/toady/services/github_service.py (1)
GitHubService(134-704)tests/conftest.py (1)
runner(22-24)
🪛 LanguageTool
tests/integration/real_api/README.md
[uncategorized] ~132-~132: Loose punctuation mark.
Context: ...ytest Markers - @pytest.mark.real_api: Tests that make actual GitHub API calls...
(UNLIKELY_OPENING_PUNCTUATION)
[grammar] ~257-~257: Did you mean “to Use”?
Context: ...low tests separately when needed** 5. Use appropriate environment configuration...
(MISSING_TO_BEFORE_A_VERB)
🪛 Pylint (3.3.7)
tests/integration/conftest.py
[refactor] 42-42: Either all return statements in a function should return an expression, or none of them should.
(R1710)
[refactor] 165-165: Either all return statements in a function should return an expression, or none of them should.
(R1710)
[refactor] 414-414: Either all return statements in a function should return an expression, or none of them should.
(R1710)
⏰ Context from checks skipped due to timeout of 90000ms (13)
- GitHub Check: test (macos-latest, 3.10)
- GitHub Check: test (macos-latest, 3.12)
- GitHub Check: test (macos-latest, 3.11)
- GitHub Check: test (macos-latest, 3.9)
- GitHub Check: test (windows-latest, 3.11)
- GitHub Check: test (windows-latest, 3.12)
- GitHub Check: test (windows-latest, 3.8)
- GitHub Check: test (ubuntu-latest, 3.11)
- GitHub Check: test (windows-latest, 3.9)
- GitHub Check: test (windows-latest, 3.10)
- GitHub Check: test (ubuntu-latest, 3.12)
- GitHub Check: test (ubuntu-latest, 3.10)
- GitHub Check: test (ubuntu-latest, 3.9)
🔇 Additional comments (1)
scripts/ci_check.py (1)
204-206: Exclude the right crap.You skip
integrationtests, but the new suite is taggedreal_api,auth, etc. Consider-m "not integration and not real_api"(or similar) so the CI doesn’t choke on live-API calls.
- Updated `.env.example` to include new test-related environment variables for integration testing. - Added `python-dotenv` dependency in `requirements-dev.txt` for loading environment variables. - Modified CI workflow to utilize new environment variables for testing configuration. - Refactored `fetch.py` and `pr_selector.py` to support output format options for better user experience. - Improved error handling in `pr_selector.py` for JSON mode to prevent interactive prompts. These changes aim to streamline the testing process and improve the flexibility of the CI setup.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (4)
src/toady/services/pr_selector.py (3)
18-28: Lower-case once, reuse everywhere
output_format == "json"will fail when the CLI receives"JSON"/"Json". Call.lower()once in the ctor and store the normalised value; all later checks then work.
48-58: ReturningNonesilently loses contextIn JSON mode with multiple PRs you write an error message then return
None, causing the caller to treat it as a user cancel. That swallows the “this is actually an error” signal. Consider raising a dedicated exception (e.g.InteractiveSelectionNotSupported) so the command can exit with a non-zero code in CI.
74-80: Redundant blank echoes
click.echo(err=self.is_json_mode)prints empty lines to stderr. Not harmful, but costs a pointless write. Replace withif not self.is_json_mode: click.echo()for clarity.tests/integration/real_api/test_end_to_end_workflows.py (1)
208-246:skip_if_slowfixture unusedThe fixture is requested but never referenced, so PyTest will still execute the heavy test when
TOADY_SKIP_SLOW_TESTS=true. Addskip_if_slowearly in the body or drop the parameter.🧰 Tools
🪛 Pylint (3.3.7)
[refactor] 208-208: Too many arguments (7/5)
(R0913)
[refactor] 208-208: Too many positional arguments (7/5)
(R0917)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
.env.example(1 hunks).github/workflows/ci.yml(1 hunks)requirements-dev.txt(1 hunks)scripts/ci_check.py(1 hunks)src/toady/commands/fetch.py(1 hunks)src/toady/services/fetch_service.py(1 hunks)src/toady/services/pr_selector.py(5 hunks)tests/integration/conftest.py(1 hunks)tests/integration/real_api/test_end_to_end_workflows.py(1 hunks)
✅ Files skipped from review due to trivial changes (2)
- requirements-dev.txt
- .env.example
🚧 Files skipped from review as they are similar to previous changes (2)
- scripts/ci_check.py
- .github/workflows/ci.yml
🧰 Additional context used
🧠 Learnings (1)
tests/integration/real_api/test_end_to_end_workflows.py (2)
Learnt from: tonyblank
PR: tonyblank/toady-cli#54
File: tests/unit/services/test_fetch_service.py:15-17
Timestamp: 2025-06-12T01:25:15.100Z
Learning: pytest.ini now uses the correct “[pytest]” section header and registers markers `unit`, `service`, `integration`, `model`, `auth`, `resilience`, and `performance`, preventing PytestUnknownMarkWarning in this repository.
Learnt from: tonyblank
PR: tonyblank/toady-cli#54
File: tests/integration/real_api/test_end_to_end_workflows.py:18-20
Timestamp: 2025-06-12T01:25:37.839Z
Learning: pytest.ini now correctly uses the “[pytest]” section header and registers all markers: unit, service, integration, model, auth, resilience, performance, real_api, and slow, eliminating PytestUnknownMarkWarning across the repository.
🧬 Code Graph Analysis (2)
src/toady/commands/fetch.py (1)
src/toady/services/fetch_service.py (1)
FetchService(21-354)
tests/integration/conftest.py (2)
src/toady/services/github_service.py (1)
GitHubService(134-704)tests/conftest.py (1)
runner(22-24)
🪛 Pylint (3.3.7)
tests/integration/real_api/test_end_to_end_workflows.py
[refactor] 24-24: Too many arguments (7/5)
(R0913)
[refactor] 24-24: Too many positional arguments (7/5)
(R0917)
[refactor] 24-24: Too many local variables (25/15)
(R0914)
[refactor] 24-24: Too many statements (67/50)
(R0915)
[refactor] 208-208: Too many arguments (7/5)
(R0913)
[refactor] 208-208: Too many positional arguments (7/5)
(R0917)
tests/integration/conftest.py
[refactor] 51-51: Either all return statements in a function should return an expression, or none of them should.
(R1710)
[refactor] 196-196: Either all return statements in a function should return an expression, or none of them should.
(R1710)
[refactor] 445-445: Either all return statements in a function should return an expression, or none of them should.
(R1710)
⏰ Context from checks skipped due to timeout of 90000ms (12)
- GitHub Check: test (macos-latest, 3.11)
- GitHub Check: test (windows-latest, 3.11)
- GitHub Check: test (ubuntu-latest, 3.12)
- GitHub Check: test (macos-latest, 3.10)
- GitHub Check: test (windows-latest, 3.12)
- GitHub Check: test (macos-latest, 3.9)
- GitHub Check: test (macos-latest, 3.12)
- GitHub Check: test (windows-latest, 3.10)
- GitHub Check: test (windows-latest, 3.9)
- GitHub Check: test (ubuntu-latest, 3.9)
- GitHub Check: test (ubuntu-latest, 3.11)
- GitHub Check: test (ubuntu-latest, 3.10)
🔇 Additional comments (2)
src/toady/commands/fetch.py (1)
138-142: Pass-through ofoutput_formatlooks fine but watch other call sites
FetchServicenow expects anoutput_formatparam. This call site was updated, but double-check other instantiations (e.g. tests, utilities) to avoid silent fallback to"pretty"when JSON was intended.tests/integration/conftest.py (1)
51-111: Mixed return / skip paths trigger Pylint R1710
github_api_health_checksometimes returnsTrue, otherwise always raisespytest.skip, satisfying control-flow expectations. The diagnostic can safely be ignored or silenced with# pylint: disable=R1710.🧰 Tools
🪛 Pylint (3.3.7)
[refactor] 51-51: Either all return statements in a function should return an expression, or none of them should.
(R1710)
- Added validation for the `output_format` parameter in `FetchService` to ensure only supported formats ("json" or "pretty") are accepted, raising a ValueError for unsupported formats.
- Updated `PRSelector` to suppress output in JSON mode, preventing compatibility issues and ensuring cleaner output handling.
- Adjusted test cases in `test_end_to_end_workflows.py` to accommodate changes in output handling and improve error reporting for JSON decoding.
These changes aim to enhance user experience and maintain output integrity across different modes.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
tests/integration/real_api/test_end_to_end_workflows.py (2)
24-41: This test is a god-damn monolith – break it the hell up.
test_complete_review_cycle_workflowcrams fetching, commenting, replying, resolving, verification and perf timing into one 200-line beast. When it fails, you’ll be spelunking through a mountain of shit to see which step blew up.Extract helper funcs (e.g.
fetch_threads,post_reply,resolve_thread,assert_resolved) or split into smaller tests. Your future self will thank you, and pylint will stop whining about “too many statements / locals”.🧰 Tools
🪛 Pylint (3.3.7)
[refactor] 24-24: Too many arguments (7/5)
(R0913)
[refactor] 24-24: Too many positional arguments (7/5)
(R0917)
[refactor] 24-24: Too many local variables (25/15)
(R0914)
[refactor] 24-24: Too many statements (67/50)
(R0915)
208-216: Fixtureskip_if_slowis hauled in but never used – dead weight.If the fixture’s sole purpose is to skip inside itself, cool, but if not, drop it from the arg list to shut up the “unused argument” noise.
🧰 Tools
🪛 Pylint (3.3.7)
[refactor] 208-208: Too many arguments (7/5)
(R0913)
[refactor] 208-208: Too many positional arguments (7/5)
(R0917)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/toady/services/fetch_service.py(1 hunks)src/toady/services/pr_selector.py(6 hunks)tests/integration/real_api/test_end_to_end_workflows.py(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- src/toady/services/fetch_service.py
- src/toady/services/pr_selector.py
🧰 Additional context used
🧠 Learnings (1)
tests/integration/real_api/test_end_to_end_workflows.py (2)
Learnt from: tonyblank
PR: tonyblank/toady-cli#54
File: tests/unit/services/test_fetch_service.py:15-17
Timestamp: 2025-06-12T01:25:15.100Z
Learning: pytest.ini now uses the correct “[pytest]” section header and registers markers `unit`, `service`, `integration`, `model`, `auth`, `resilience`, and `performance`, preventing PytestUnknownMarkWarning in this repository.
Learnt from: tonyblank
PR: tonyblank/toady-cli#54
File: tests/integration/real_api/test_end_to_end_workflows.py:18-20
Timestamp: 2025-06-12T01:25:37.839Z
Learning: pytest.ini now correctly uses the “[pytest]” section header and registers all markers: unit, service, integration, model, auth, resilience, performance, real_api, and slow, eliminating PytestUnknownMarkWarning across the repository.
🪛 Pylint (3.3.7)
tests/integration/real_api/test_end_to_end_workflows.py
[refactor] 24-24: Too many arguments (7/5)
(R0913)
[refactor] 24-24: Too many positional arguments (7/5)
(R0917)
[refactor] 24-24: Too many local variables (25/15)
(R0914)
[refactor] 24-24: Too many statements (67/50)
(R0915)
[refactor] 208-208: Too many arguments (7/5)
(R0913)
[refactor] 208-208: Too many positional arguments (7/5)
(R0917)
⏰ Context from checks skipped due to timeout of 90000ms (12)
- GitHub Check: test (macos-latest, 3.12)
- GitHub Check: test (windows-latest, 3.9)
- GitHub Check: test (macos-latest, 3.11)
- GitHub Check: test (windows-latest, 3.10)
- GitHub Check: test (macos-latest, 3.9)
- GitHub Check: test (windows-latest, 3.11)
- GitHub Check: test (macos-latest, 3.10)
- GitHub Check: test (ubuntu-latest, 3.11)
- GitHub Check: test (windows-latest, 3.12)
- GitHub Check: test (ubuntu-latest, 3.9)
- GitHub Check: test (ubuntu-latest, 3.12)
- GitHub Check: test (ubuntu-latest, 3.10)
🔇 Additional comments (3)
tests/integration/real_api/test_end_to_end_workflows.py (3)
65-82: Double-check the comment-creation output or you’ll delete the wrong damn thing.
gh pr comment …is assumed to spit the comment URL on stdout, and you shove that straight into cleanup. Depending on the user’s gh-CLI version and locale, stdout might be a friendly sentence (“Created comment https://…”) instead of a clean URL.At minimum, parse the JSON output:
- create_result = subprocess.run( - ["gh", "pr", "comment", str(pr_number), "--repo", repo_full_name, "--body", test_comment_body], - capture_output=True, text=True, timeout=30, - ) + create_result = subprocess.run( + [ + "gh", "pr", "comment", + str(pr_number), + "--repo", repo_full_name, + "--body", test_comment_body, + "--json", "url", # guarantees machine-readable output + "--jq", ".url" + ], + capture_output=True, + text=True, + timeout=30, + )Then hand the parsed URL to your cleanup job.
333-337: Nice guard against Click-7 vs 8 – solid.Using
getattr(result, "stdout", result.output)prevents that nastyAttributeError. No complaints here.
403-411:gh api DELETEmight puke on a full URL – slice the endpoint, champ.
gh apiexpects a path like/repos/owner/repo/pulls/comments/123456. Feeding it the rawhttps://github.com/...can 404. Consider:- subprocess.run( - ["gh", "api", "--method", "DELETE", comment_url], + endpoint=${comment_url#https://api.github.com} + subprocess.run( + ["gh", "api", "--method", "DELETE", endpoint],or just call
gh pr comment --deletewith the ID. Verify this before the cleanup silently fails and leaves test litter.
- Introduced a new test suite for the CLI module, covering group setup, version display, command registration, context handling, and error handling. - Added unit tests for command modules including `fetch`, `reply`, `resolve`, and `schema`, focusing on core logic, parameter validation, error handling, and service integration. - Enhanced test coverage with edge cases and boundary conditions to ensure robust functionality across various scenarios. - Updated documentation for command unit tests to reflect the new structure and coverage details. These changes aim to improve the reliability and maintainability of the CLI and command modules, ensuring a solid foundation for future development.
|
@coderabbitai review |
- Transitioned development dependencies from `requirements-dev.txt` to `pyproject.toml` for improved management and clarity. - Updated CI workflow to install dependencies using the new `pyproject.toml` format, enhancing compatibility and streamlining the installation process. - Removed deprecated entries from `requirements-dev.txt`, marking it for backward compatibility only. - Adjusted caching keys in CI to reflect changes in dependency management. These changes aim to modernize the project structure and improve the efficiency of the CI pipeline.
There was a problem hiding this comment.
Actionable comments posted: 4
🔭 Outside diff range comments (1)
pyproject.toml (1)
166-167:⚠️ Potential issuepytest-timeout is gone – these damn options will explode
You nuked the
pytest-timeoutplugin from dependencies, yet thetimeoutkeys stay while--strict-configis enabled. Pytest will puke with “unknown config option” and fail the whole suite.Either yank the lines or add the plugin back.
🧹 Nitpick comments (7)
.github/workflows/ci.yml (1)
102-104: Stop sweeping test failures under the rug
continue-on-error: truelets busted integration tests quietly pass. If these real-API checks matter, make the pipeline fail so we actually catch the fuck-ups; otherwise run them as a separate, optional workflow.tests/unit/commands/README.md (1)
3-4: Drop the redundant crap“CLI interface” – the “I” already stands for interface, genius. Trim to “CLI”.
🧰 Tools
🪛 LanguageTool
[style] ~3-~3: This phrase is redundant (‘I’ stands for ‘interface’). Use simply “CLI”.
Context: ... core command logic without testing the CLI interface directly. ## Structure - `init.py...(ACRONYM_TAUTOLOGY)
tests/unit/commands/test_reply.py (3)
75-78: Don’t return a bloodyMockwhen a plain string will do, mate.
mock_validator.validate_id.return_value = Mock(value="numeric")is pointless. The production code only cares about the return value itself, not a.valueattr. Just make it return"numeric"and keep the mocking simple (and faster).
494-506: Mock the damnclick.Contextwith a spec, not a shapeless blob.
ctx = Mock()gives you a formless mock that may silently swallow bad attribute access. UseMock(spec=click.Context)so the test blows up if_show_id_helptries to touch some non-existent attribute. Keeps the suite honest.
927-930: Stop copy-pasting this runner fixture all over the place.You’ve got the exact same
runner()factory littered across multiple test modules. Chuck it intotests/conftest.pyonce and let pytest handle the damn sharing. Less duplication, fewer headaches.tests/unit/commands/test_fetch.py (2)
204-206: This assertion is fragile as hell.
assert_called_once_with(pr_number=456, include_resolved=True, threads_limit=50)assumes the fetch command never forwardsinclude_draftsor any future kwarg. One extra parameter and this test explodes for no good reason. Stick toassert_called_once()then inspectcall_args[1]for the few keys you actually care about.
730-733: Again with the runner clone-army…Same rant as in
test_reply.py: centralize thisCliRunnerfixture intests/conftest.pyand quit duplicating it like rabbits.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
.github/workflows/ci.yml(2 hunks)pyproject.toml(1 hunks)requirements-dev.txt(1 hunks)tests/unit/commands/README.md(1 hunks)tests/unit/commands/__init__.py(1 hunks)tests/unit/commands/test_fetch.py(1 hunks)tests/unit/commands/test_reply.py(1 hunks)tests/unit/commands/test_resolve.py(1 hunks)tests/unit/commands/test_schema.py(1 hunks)tests/unit/test_cli.py(1 hunks)tests/unit/validators/test_validation.py(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- tests/unit/commands/init.py
🧰 Additional context used
🧬 Code Graph Analysis (4)
tests/unit/commands/test_fetch.py (5)
src/toady/cli.py (1)
cli(23-89)tests/unit/test_cli.py (1)
runner(477-479)tests/unit/commands/test_reply.py (1)
runner(927-929)tests/unit/commands/test_resolve.py (1)
runner(1003-1005)src/toady/services/fetch_service.py (1)
fetch_review_threads_with_pr_selection(296-362)
tests/unit/commands/test_reply.py (7)
src/toady/commands/reply.py (9)
reply(497-615)_build_json_reply(250-292)_handle_reply_error(333-461)_print_pretty_reply(211-247)_show_id_help(28-92)_show_progress(320-330)_show_warnings(295-317)_validate_reply_args(160-208)validate_reply_target_id(95-157)src/toady/services/reply_service.py (1)
ReplyRequest(23-29)src/toady/validators/node_id_validation.py (1)
validate_id(181-209)tests/unit/validators/test_validation.py (2)
test_repetitive_content_warning(1397-1408)test_no_warnings_for_normal_content(1358-1369)tests/unit/test_cli.py (1)
runner(477-479)tests/unit/commands/test_fetch.py (1)
runner(731-733)tests/unit/commands/test_resolve.py (1)
runner(1003-1005)
tests/unit/commands/test_schema.py (4)
src/toady/commands/schema.py (6)
schema(25-28)_display_query_validation_results(404-459)_display_summary_report(322-401)_has_critical_errors(462-509)check(240-319)validate(48-138)src/toady/exceptions.py (1)
ToadyError(71-120)src/toady/validators/schema_validator.py (4)
SchemaValidationError(22-40)fetch_schema(142-193)generate_compatibility_report(558-588)validate_query(219-273)tests/unit/test_cli.py (1)
runner(477-479)
tests/unit/test_cli.py (5)
src/toady/cli.py (1)
cli(23-89)src/toady/exceptions.py (1)
ToadyError(71-120)tests/unit/commands/test_fetch.py (1)
runner(731-733)tests/unit/commands/test_reply.py (1)
runner(927-929)tests/unit/commands/test_resolve.py (1)
runner(1003-1005)
🪛 Pylint (3.3.7)
tests/unit/commands/test_fetch.py
[refactor] 61-61: Too many arguments (6/5)
(R0913)
[refactor] 61-61: Too many positional arguments (6/5)
(R0917)
[refactor] 87-87: Too many arguments (6/5)
(R0913)
[refactor] 87-87: Too many positional arguments (6/5)
(R0917)
tests/unit/commands/test_reply.py
[refactor] 489-489: Too few public methods (1/2)
(R0903)
🪛 LanguageTool
tests/unit/commands/README.md
[style] ~3-~3: This phrase is redundant (‘I’ stands for ‘interface’). Use simply “CLI”.
Context: ... core command logic without testing the CLI interface directly. ## Structure - `init.py...
(ACRONYM_TAUTOLOGY)
[uncategorized] ~14-~14: Possible missing comma found.
Context: ...c/toady/commands/fetch.py`) with 95.71% coverage including: #### Test Classes: 1. **Te...
(AI_HYDRA_LEO_MISSING_COMMA)
🪛 markdownlint-cli2 (0.17.2)
tests/unit/commands/README.md
16-16: Trailing punctuation in heading
Punctuation: ':'
(MD026, no-trailing-punctuation)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: test (windows-latest, 3.12)
🔇 Additional comments (2)
requirements-dev.txt (1)
1-8: All good – just a legacy noteFile is deprecated, message is clear.
tests/unit/validators/test_validation.py (1)
1-10: Monstrous test suite looks solidThe gargantuan validator tests read fine – nothing obvious to bitch about.
- Updated `pyproject.toml` to adjust `python-dotenv` and `types-click` versions for better compatibility. - Removed the deprecated `requirements-dev.txt` file, consolidating dependency management within `pyproject.toml`. - Added new checks in `ci_check.py` for trailing whitespace and proper end-of-file formatting to improve code quality. - Updated tests to reflect the removal of `requirements-dev.txt` and improved error messages in schema validation tests. These changes aim to streamline dependency management and enhance code quality checks in the CI pipeline.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
tests/unit/commands/test_schema.py (1)
221-221: Line length exceeds Ruff default (E501)These literal-string assertions run 90 chars and trigger E501. If E501 isn’t globally disabled for tests, wrap the string or split it to keep ≤ 88 chars, or add
# noqa: E501locally.Also applies to: 374-374, 530-530, 704-704
🧰 Tools
🪛 Ruff (0.11.9)
221-221: Line too long (90 > 88)
(E501)
tests/unit/commands/README.md (1)
3-3: Minor wording nit“CLI interface” is tautological; consider dropping “interface” to read “testing the CLI directly.”
🧰 Tools
🪛 LanguageTool
[style] ~3-~3: This phrase is redundant (‘I’ stands for ‘interface’). Use simply “CLI”.
Context: ... core command logic without testing the CLI interface directly. ## Structure - `init.py...(ACRONYM_TAUTOLOGY)
tests/unit/test_cli.py (1)
254-259: Readability of combined context managers
with patch.dict(...), pytest.raises(...):is valid but easy to misread. Consider nesting or using a singlewithper context manager for clarity.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
pyproject.toml(1 hunks)requirements-dev.txt(0 hunks)scripts/ci_check.py(3 hunks)tests/test_setup.py(0 hunks)tests/unit/commands/README.md(1 hunks)tests/unit/commands/test_schema.py(1 hunks)tests/unit/test_cli.py(1 hunks)
💤 Files with no reviewable changes (2)
- tests/test_setup.py
- requirements-dev.txt
🚧 Files skipped from review as they are similar to previous changes (1)
- pyproject.toml
🧰 Additional context used
🧬 Code Graph Analysis (1)
tests/unit/test_cli.py (5)
src/toady/cli.py (1)
cli(23-89)src/toady/exceptions.py (1)
ToadyError(71-120)tests/unit/commands/test_fetch.py (1)
runner(731-733)tests/unit/commands/test_reply.py (1)
runner(927-929)tests/unit/commands/test_resolve.py (1)
runner(1003-1005)
🪛 Ruff (0.11.9)
tests/unit/commands/test_schema.py
221-221: Line too long (90 > 88)
(E501)
374-374: Line too long (90 > 88)
(E501)
530-530: Line too long (90 > 88)
(E501)
704-704: Line too long (90 > 88)
(E501)
🪛 LanguageTool
tests/unit/commands/README.md
[style] ~3-~3: This phrase is redundant (‘I’ stands for ‘interface’). Use simply “CLI”.
Context: ... core command logic without testing the CLI interface directly. ## Structure - `init.py...
(ACRONYM_TAUTOLOGY)
[uncategorized] ~14-~14: Possible missing comma found.
Context: ...c/toady/commands/fetch.py`) with 95.71% coverage including: #### Test Classes: 1. **Te...
(AI_HYDRA_LEO_MISSING_COMMA)
🪛 markdownlint-cli2 (0.17.2)
tests/unit/commands/README.md
16-16: Trailing punctuation in heading
Punctuation: ':'
(MD026, no-trailing-punctuation)
🔇 Additional comments (1)
scripts/ci_check.py (1)
236-269: Verify local availability of the dedicated pre-commit hooks
pre-commit run trailing-whitespace …andend-of-file-fixer …will error out if those hooks aren’t installed locally (e.g., dev machine withoutpre-commit install). Becauserun_pre_commit_hooksis omitted from the fast pipeline, the fast path has no installation step. Please confirm the hooks are guaranteed to exist or add an install/update step before running them.Also applies to: 400-401
- Fixed 9 failing unit tests with updated error message expectations - Updated parser tests to match actual behavior (empty comment handling, datetime validation) - Fixed service tests with correct exception types - Reinstalled pre-commit hooks with proper uv integration - Auto-formatted files with black pre-commit hook 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Removed Python 3.8 from the CI matrix in `.github/workflows/ci-uv.yml` and `.github/workflows/ci.yml` to streamline testing environments. - Adjusted `envlist` in `pyproject.toml` to reflect the updated Python versions. - Enhanced the `TestRateLimitHandling` class in `test_network_resilience.py` to skip tests if GitHub CLI is not authenticated, improving test reliability in CI environments. These changes aim to modernize the CI setup and ensure more robust testing practices.
- Eliminated the conditional statement that restricted the integration test job to specific events, simplifying the CI configuration. - This change aims to ensure that integration tests run consistently without being tied to specific GitHub events, enhancing the reliability of the CI process.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 13
🔭 Outside diff range comments (3)
src/toady/validators/node_id_validation.py (1)
1-10: 🛠️ Refactor suggestion
⚠️ Potential issueFix your damn generics – this explodes on Python 3.8
list[str]andset[GitHubEntityType]only resolve without puking starting in 3.9.
Your CI matrix still drags along 3.8, so importing this module will raiseTypeError: 'type' object is not subscriptable.Shove in the future-annotations import (or back-pedal to
List/Set) before the rest of the file:+from __future__ import annotationsDump it right after the docstring to shut 3.8 up and keep the rest of the modern typing candy.
Also applies to: 69-80
pyproject.toml (1)
276-283: 🛠️ Refactor suggestiontox matrix contradicts supported Python
requires-python = ">=3.9"but tox still listspy38.
Drop 3.8 or lower the minimum version to avoid CI failures.src/toady/commands/schema.py (1)
110-118:⚠️ Potential issueUsing
sys.exitinside library-ish code? Yikes.Bailing out right here means this function can’t be unit-tested without monkey-patching
sys.exit. Return an exit-code or raise a customCommandAbortedinstead, then let the CLI entry-point handle the actual exit.
♻️ Duplicate comments (4)
pyproject.toml (1)
57-58:⚠️ Potential issueStub version now mismatches Click again
click>=8.1.7pairs withtypes-click>=8.1.0.
Downgrading stubs to7.1.8will bring back mypy incompatibility.- "types-click>=7.1.8", + "types-click>=8.1.0",tests/unit/commands/test_resolve.py (1)
117-122:⚠️ Potential issueIncorrect patch target re-introduced
_validate_resolve_parameters()importsvalidate_limitfromtoady.commands.resolve, not fromtoady.command_utils.
Patching the wrong symbol means the real function isn’t mocked and the test may blow up withModuleNotFoundError.-@patch("toady.command_utils.validate_limit") +@patch("toady.commands.resolve.validate_limit")tests/integration/conftest.py (1)
64-113: 🛠️ Refactor suggestionMove
jsonimport outside the try-block
json.JSONDecodeErroris caught in theexcept, butjsonis only imported inside thetry.
If anything fails before that import runs (e.g.subprocess.TimeoutExpired), you’ll hitUnboundLocalError.- import json - - try: + import json + try: # … rest of code …Then drop the inner
import jsonat line 231/461 as well to avoid duplicate imports.
This was flagged in a prior review—let’s kill it everywhere.tests/integration/real_api/test_end_to_end_workflows.py (1)
190-199: Same bloody mistake – use the guarded stdoutYou fixed it once, but lines 192-199 still assume
result.output.
Wrap it with thegetattrguard or expect CI to punch you in the gut again.
🧹 Nitpick comments (16)
.github/workflows/ci-uv.yml (1)
41-44: Codecov action v3 is a crusty fossil
codecov/codecov-action@v3can choke on the latest runners (see actionlint gripe).
Bump to@v4before it embarrasses your pipeline.- uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4🧰 Tools
🪛 actionlint (1.7.7)
42-42: the runner of "codecov/codecov-action@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue
(action)
tests/unit/parsers/test_parsers.py (1)
4-5: Redundant import
from typing import Anyis the only name imported and is still required after switching todict[str, Any], but if no othertypingsymbols are used in this file consider narrowing to:from typing import Any(or drop the import entirely if
Anyis no longer referenced).tests/unit/services/test_resolve_service.py (1)
820-834: Pathological response still triggersKeyErrorearlyYou craft a response missing the
threadkey to provoke the “no thread data returned” path, butResolveService.resolve_threaddereferences["thread"]only after ensuring the mutation key exists.
If future implementation details shift, this test might instead raiseKeyErrorand fail.
Consider using the public helper (_handle_mutation_responseor similar) or asserting generically onResolveServiceErrorwithout the exact message to keep the test resilient to refactors.tests/unit/services/test_reply_service.py (1)
333-345: Coupling tests to private fallback implementationPatching
_post_reply_fallback_restties the test to a private helper that could be renamed or inlined.
A more future-proof approach is to assert thatgithub_service.post_replywas not called when a numeric ID is supplied and that the publicpost_replyreturns the expected result.
This keeps the test focused on observable behaviour, not internals.tests/unit/test_utils.py (1)
193-208: Patch path brittle
patch("toady.utils.datetime")replaces the importeddatetimeclass.
Ifutils.parse_datetimeever starts doingimport datetime as dtthe patch will silently miss. Consider patching the specificstrptimeattribute instead:-with patch("toady.utils.datetime") as mock_datetime: - mock_datetime.strptime.side_effect = ValueError("test parsing error") +with patch("toady.utils.datetime.strptime", side_effect=ValueError("test parsing error")): ...tests/unit/commands/test_reply.py (1)
674-742: Minor readability tipDecorator order already correct, but adding a short comment avoids head-scratching:
# param order: mock_resolve_format, mock_service_class, runner @patch("toady.commands.reply.ReplyService") @patch("toady.commands.reply.resolve_format_from_options")src/toady/formatters/format_interfaces.py (1)
158-163: Repeated import inside hot path
jsonis imported on every fallback; move it to module level to avoid tiny but needless overhead:-from typing import Any, Optional, Union +from typing import Any, Optional, Union +import json ... - try: - import json + try:src/toady/formatters/pretty_formatter.py (1)
561-578: Pylint is right—this helper is ballooning
_format_tablecracks the 20-local-vars and 13-branch thresholds. Readability is already strained.Consider extracting:
- header/width calculation
- row rendering
into private helpers to keep the cyclomatic complexity sane.Not urgent for functionality but future maintainers will thank you.
🧰 Tools
🪛 Pylint (3.3.7)
[refactor] 561-561: Too many local variables (20/15)
(R0914)
[refactor] 561-561: Too many branches (13/12)
(R0912)
tests/unit/test_cli.py (1)
473-476: Duplicaterunnerfixture – drop it to avoid confusion
tests/conftest.pyalready exports an identically-namedrunnerfixture.
Redefining it here shadows the global one and risks diverging behaviour later.
Delete these lines and import the shared fixture instead.src/toady/parsers/parsers.py (1)
559-577: Redundant error branch – simplify to a single raiseLines 571-576 raise the same validation error already handled at 577-582, inflating cyclomatic complexity for no gain.
Delete the inner block and keep one definitiveraise create_validation_error(...).src/toady/error_handling.py (1)
9-10: Tiny import nit
sysnow sits between std-enum and typing. It’s harmless, but the import order looks like a drunk octopus arranged it. Chucksysup top with the other stdlib junk or runisortand be done with it.src/toady/commands/schema.py (1)
60-72: Copy-pasted try/except hell – DRY this shitEvery damn block re-wraps
GitHubSchemaValidator(...)with the same FileOperation/ConfigurationError boilerplate. Factor that into a helper so we don’t scroll past the same 10 lines six times. Your future self will thank you instead of cursing you.tests/unit/test_format_selection.py (1)
49-52: Dead code makes the test smell like assInside the
with patch.dict(..., clear=True)block the env is already nuked; the manualdel os.environ[...]dance is pointless noise. Axe it.src/toady/formatters/formatters.py (1)
22-35: Missing type guard means None will crash hard
OutputFormatter.format_threadsassumesthreadsis a list, then punts to JSON/Pretty. If someone passesNoneyou’ll get a blow-up later. Do a cheapif not threads:early and return"[]"or"No review threads found."instead of a face-plant.tests/integration/real_api/test_authentication_flows.py (1)
49-53: Pointless class attribute – nuke it
self.current_user_loginis set but never read anywhere.
Dead code = dead weight. Drop the assignment or wire it into another test.Makefile (1)
1-3: Missing.PHONY: allLots of targets, but the traditional
allphony is MIA, tripping checkmake.
Add it or silence the linter warnings.🧰 Tools
🪛 checkmake (0.2.2)
[warning] 3-3: Missing required phony target "all"
(minphony)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
uv.lockis excluded by!**/*.lock
📒 Files selected for processing (60)
.github/workflows/ci-uv.yml(1 hunks)Makefile(4 hunks)pyproject.toml(3 hunks)scripts/ci_check.py(7 hunks)scripts/test_config.py(3 hunks)src/toady/cli.py(1 hunks)src/toady/commands/reply.py(5 hunks)src/toady/commands/resolve.py(8 hunks)src/toady/commands/schema.py(18 hunks)src/toady/error_handling.py(3 hunks)src/toady/exceptions.py(3 hunks)src/toady/formatters/format_interfaces.py(16 hunks)src/toady/formatters/format_selection.py(6 hunks)src/toady/formatters/formatters.py(5 hunks)src/toady/formatters/json_formatter.py(19 hunks)src/toady/formatters/pretty_formatter.py(15 hunks)src/toady/models/models.py(13 hunks)src/toady/parsers/graphql_parser.py(12 hunks)src/toady/parsers/graphql_queries.py(5 hunks)src/toady/parsers/parsers.py(23 hunks)src/toady/services/fetch_service.py(9 hunks)src/toady/services/github_service.py(11 hunks)src/toady/services/pr_selection.py(5 hunks)src/toady/services/pr_selector.py(7 hunks)src/toady/services/reply_service.py(9 hunks)src/toady/services/resolve_service.py(18 hunks)src/toady/utils.py(4 hunks)src/toady/validators/node_id_validation.py(3 hunks)src/toady/validators/schema_validator.py(21 hunks)src/toady/validators/validation.py(8 hunks)tests/conftest.py(2 hunks)tests/integration/cli/test_fetch_cli.py(1 hunks)tests/integration/cli/test_reply_cli.py(1 hunks)tests/integration/cli/test_resolve_cli.py(1 hunks)tests/integration/conftest.py(1 hunks)tests/integration/real_api/test_authentication_flows.py(1 hunks)tests/integration/real_api/test_end_to_end_workflows.py(1 hunks)tests/integration/real_api/test_network_resilience.py(1 hunks)tests/integration/real_api/test_performance_monitoring.py(1 hunks)tests/integration/test_schema_validation_integration.py(1 hunks)tests/unit/commands/test_fetch.py(1 hunks)tests/unit/commands/test_reply.py(1 hunks)tests/unit/commands/test_resolve.py(1 hunks)tests/unit/commands/test_schema.py(1 hunks)tests/unit/formatters/test_color_and_terminal.py(2 hunks)tests/unit/formatters/test_comprehensive_formatting.py(1 hunks)tests/unit/formatters/test_format_interfaces.py(2 hunks)tests/unit/formatters/test_formatters.py(7 hunks)tests/unit/formatters/test_json_formatter.py(2 hunks)tests/unit/formatters/test_performance_and_memory.py(1 hunks)tests/unit/models/test_models.py(9 hunks)tests/unit/parsers/test_parsers.py(5 hunks)tests/unit/services/test_github_service.py(3 hunks)tests/unit/services/test_reply_service.py(1 hunks)tests/unit/services/test_resolve_service.py(1 hunks)tests/unit/test_cli.py(1 hunks)tests/unit/test_command_utils.py(3 hunks)tests/unit/test_format_selection.py(2 hunks)tests/unit/test_utils.py(1 hunks)tests/unit/validators/test_schema_validator.py(2 hunks)
✅ Files skipped from review due to trivial changes (17)
- tests/unit/formatters/test_performance_and_memory.py
- src/toady/cli.py
- tests/integration/cli/test_reply_cli.py
- tests/integration/test_schema_validation_integration.py
- tests/integration/cli/test_resolve_cli.py
- tests/unit/formatters/test_comprehensive_formatting.py
- scripts/test_config.py
- tests/unit/formatters/test_format_interfaces.py
- src/toady/validators/schema_validator.py
- src/toady/services/pr_selection.py
- src/toady/exceptions.py
- src/toady/formatters/format_selection.py
- src/toady/commands/resolve.py
- src/toady/parsers/graphql_parser.py
- src/toady/commands/reply.py
- src/toady/services/reply_service.py
- src/toady/formatters/json_formatter.py
🚧 Files skipped from review as they are similar to previous changes (10)
- tests/unit/test_command_utils.py
- tests/integration/cli/test_fetch_cli.py
- tests/conftest.py
- scripts/ci_check.py
- tests/unit/models/test_models.py
- tests/unit/formatters/test_formatters.py
- src/toady/services/fetch_service.py
- src/toady/services/pr_selector.py
- src/toady/validators/validation.py
- src/toady/services/github_service.py
👮 Files not reviewed due to content moderation or server errors (1)
- tests/unit/commands/test_fetch.py
🧰 Additional context used
🧠 Learnings (4)
tests/integration/real_api/test_authentication_flows.py (1)
Learnt from: tonyblank
PR: tonyblank/toady-cli#54
File: tests/integration/real_api/test_authentication_flows.py:66-73
Timestamp: 2025-06-12T01:25:58.548Z
Learning: Real-API integration tests depend on the GH_TOKEN environment variable; CI workflow now sets `env.GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}` in `.github/workflows/ci.yml`.
tests/integration/real_api/test_end_to_end_workflows.py (2)
Learnt from: tonyblank
PR: tonyblank/toady-cli#54
File: tests/unit/services/test_fetch_service.py:15-17
Timestamp: 2025-06-12T01:25:15.100Z
Learning: pytest.ini now uses the correct “[pytest]” section header and registers markers `unit`, `service`, `integration`, `model`, `auth`, `resilience`, and `performance`, preventing PytestUnknownMarkWarning in this repository.
Learnt from: tonyblank
PR: tonyblank/toady-cli#54
File: tests/integration/real_api/test_end_to_end_workflows.py:18-20
Timestamp: 2025-06-12T01:25:37.839Z
Learning: pytest.ini now correctly uses the “[pytest]” section header and registers all markers: unit, service, integration, model, auth, resilience, performance, real_api, and slow, eliminating PytestUnknownMarkWarning across the repository.
pyproject.toml (1)
Learnt from: tonyblank
PR: tonyblank/toady-cli#1
File: requirements-dev.txt:13-13
Timestamp: 2025-06-06T19:58:46.962Z
Learning: Type stub packages like types-click should be version-pinned to match their corresponding runtime packages (e.g., if Click is >=8.1.0, then types-click should also be >=8.1.0) to ensure type compatibility and reproducible environments.
tests/unit/test_utils.py (2)
Learnt from: tonyblank
PR: tonyblank/toady-cli#54
File: tests/unit/services/test_fetch_service.py:15-17
Timestamp: 2025-06-12T01:25:15.100Z
Learning: pytest.ini now uses the correct “[pytest]” section header and registers markers `unit`, `service`, `integration`, `model`, `auth`, `resilience`, and `performance`, preventing PytestUnknownMarkWarning in this repository.
Learnt from: tonyblank
PR: tonyblank/toady-cli#54
File: tests/integration/real_api/test_end_to_end_workflows.py:18-20
Timestamp: 2025-06-12T01:25:37.839Z
Learning: pytest.ini now correctly uses the “[pytest]” section header and registers all markers: unit, service, integration, model, auth, resilience, performance, real_api, and slow, eliminating PytestUnknownMarkWarning across the repository.
🧬 Code Graph Analysis (8)
src/toady/formatters/format_interfaces.py (5)
src/toady/formatters/format_selection.py (4)
format_threads(40-42)format_array(54-55)format_primitive(58-59)format_error(62-63)src/toady/formatters/json_formatter.py (5)
format_threads(44-84)format_array(148-187)format_primitive(189-206)format_error(208-232)_safe_serialize(325-385)tests/unit/formatters/test_format_interfaces.py (4)
format_threads(26-28)format_array(34-36)format_primitive(38-40)format_error(42-44)src/toady/models/models.py (5)
ReviewThread(39-317)Comment(321-609)to_dict(198-222)to_dict(470-499)to_dict(805-823)src/toady/exceptions.py (1)
to_dict(107-120)
tests/unit/validators/test_schema_validator.py (2)
tests/integration/test_schema_validation_integration.py (1)
validator(36-39)src/toady/validators/schema_validator.py (3)
GitHubSchemaValidator(43-587)_is_cache_valid(91-104)_load_cached_schema(106-121)
src/toady/models/models.py (5)
src/toady/formatters/format_interfaces.py (1)
to_dict(256-268)src/toady/exceptions.py (1)
to_dict(107-120)tests/unit/formatters/test_json_formatter.py (6)
to_dict(153-154)to_dict(216-217)to_dict(315-316)to_dict(632-633)to_dict(712-713)to_dict(732-733)tests/unit/formatters/test_performance_and_memory.py (1)
to_dict(483-484)tests/unit/formatters/test_comprehensive_formatting.py (1)
to_dict(390-391)
tests/unit/test_cli.py (3)
src/toady/cli.py (2)
cli(23-89)main(99-118)src/toady/exceptions.py (1)
ToadyError(71-120)tests/conftest.py (1)
runner(22-24)
tests/integration/real_api/test_network_resilience.py (3)
src/toady/cli.py (1)
cli(23-89)tests/integration/conftest.py (9)
verify_test_pr_exists(197-244)performance_monitor(342-402)start_timing(352-359)stop_timing(361-373)api_retry_helper(263-296)rate_limit_aware_delay(248-259)skip_if_slow(432-435)assert_performance_threshold(383-400)integration_test_config(23-48)src/toady/parsers/graphql_queries.py (2)
limit(67-82)limit(317-332)
tests/unit/commands/test_resolve.py (9)
src/toady/commands/resolve.py (13)
resolve(621-740)_display_summary(175-216)_fetch_and_filter_threads(28-60)_handle_bulk_resolve(326-377)_handle_bulk_resolve_error(260-323)_handle_confirmation_prompt(63-106)_handle_single_resolve(544-573)_handle_single_resolve_error(474-541)_handle_single_resolve_success(455-471)_process_threads(109-172)_show_single_resolve_progress(441-452)_validate_and_prepare_thread_id(417-438)_validate_resolve_parameters(380-414)src/toady/exceptions.py (7)
GitHubAPIError(338-367)GitHubAuthenticationError(313-335)GitHubRateLimitError(402-431)ResolveServiceError(604-618)ThreadNotFoundError(621-646)ThreadPermissionError(649-674)FetchServiceError(541-556)src/toady/services/fetch_service.py (2)
FetchServiceError(15-16)fetch_review_threads_from_current_repo(122-153)src/toady/models/models.py (1)
is_resolved(304-310)src/toady/services/resolve_service.py (2)
resolve_thread(34-134)unresolve_thread(136-236)tests/conftest.py (1)
runner(22-24)tests/unit/commands/test_fetch.py (1)
runner(731-733)tests/unit/commands/test_reply.py (1)
runner(927-929)tests/unit/test_cli.py (1)
runner(474-476)
src/toady/commands/schema.py (1)
src/toady/exceptions.py (2)
ConfigurationError(167-192)FileOperationError(195-227)
tests/unit/test_utils.py (4)
src/toady/exceptions.py (1)
ValidationError(123-164)src/toady/utils.py (2)
emit_error(105-143)parse_datetime(12-102)tests/unit/formatters/test_format_interfaces.py (1)
NonSerializable(176-178)tests/unit/formatters/test_json_formatter.py (1)
NonSerializable(505-507)
🪛 checkmake (0.2.2)
Makefile
[warning] 9-9: Target body for "help" exceeds allowed length of 5 (40).
(maxbodylength)
[warning] 3-3: Missing required phony target "all"
(minphony)
[warning] 166-166: Target body for "clean" exceeds allowed length of 5 (12).
(maxbodylength)
🪛 Pylint (3.3.7)
tests/unit/formatters/test_json_formatter.py
[refactor] 653-653: Too few public methods (0/2)
(R0903)
[refactor] 672-672: Too few public methods (0/2)
(R0903)
[refactor] 690-690: Too few public methods (0/2)
(R0903)
src/toady/formatters/formatters.py
[refactor] 37-37: Too few public methods (1/2)
(R0903)
[refactor] 187-187: Too many local variables (17/15)
(R0914)
[refactor] 187-187: Too many branches (13/12)
(R0912)
tests/integration/real_api/test_performance_monitoring.py
[refactor] 29-29: Too many local variables (17/15)
(R0914)
[refactor] 490-490: Too many local variables (16/15)
(R0914)
[refactor] 557-557: Too many local variables (17/15)
(R0914)
tests/integration/real_api/test_end_to_end_workflows.py
[refactor] 24-24: Too many arguments (7/5)
(R0913)
[refactor] 24-24: Too many positional arguments (7/5)
(R0917)
[refactor] 24-24: Too many local variables (25/15)
(R0914)
[refactor] 24-24: Too many statements (67/50)
(R0915)
[refactor] 208-208: Too many arguments (7/5)
(R0913)
[refactor] 208-208: Too many positional arguments (7/5)
(R0917)
tests/unit/commands/test_fetch.py
[refactor] 61-61: Too many arguments (6/5)
(R0913)
[refactor] 61-61: Too many positional arguments (6/5)
(R0917)
[refactor] 87-87: Too many arguments (6/5)
(R0913)
[refactor] 87-87: Too many positional arguments (6/5)
(R0917)
src/toady/formatters/pretty_formatter.py
[refactor] 43-43: Too many local variables (20/15)
(R0914)
[refactor] 561-561: Too many local variables (20/15)
(R0914)
[refactor] 561-561: Too many branches (13/12)
(R0912)
src/toady/commands/schema.py
[refactor] 322-322: Too many branches (18/12)
(R0912)
[refactor] 404-404: Too many branches (14/12)
(R0912)
src/toady/parsers/parsers.py
[refactor] 82-82: Too many local variables (23/15)
(R0914)
[refactor] 196-196: Too many local variables (17/15)
(R0914)
tests/integration/conftest.py
[refactor] 52-52: Either all return statements in a function should return an expression, or none of them should.
(R1710)
[refactor] 197-197: Either all return statements in a function should return an expression, or none of them should.
(R1710)
[refactor] 446-446: Either all return statements in a function should return an expression, or none of them should.
(R1710)
tests/unit/commands/test_reply.py
[refactor] 489-489: Too few public methods (1/2)
(R0903)
tests/unit/test_utils.py
[refactor] 15-15: Too few public methods (1/2)
(R0903)
[refactor] 25-25: Too many public methods (22/20)
(R0904)
[refactor] 396-396: Too few public methods (0/2)
(R0903)
🪛 GitHub Actions: CI with uv
tests/integration/real_api/test_network_resilience.py
[error] 263-293: TestRateLimitHandling.test_rate_limit_status_monitoring failed: GitHub CLI returned exit code 4 indicating missing GH_TOKEN environment variable. Error message: 'gh: To use GitHub CLI in a GitHub Actions workflow, set the GH_TOKEN environment variable. Example: env: GH_TOKEN: ${{ github.token }}'.
🪛 actionlint (1.7.7)
.github/workflows/ci-uv.yml
42-42: the runner of "codecov/codecov-action@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue
(action)
⏰ Context from checks skipped due to timeout of 90000ms (4)
- GitHub Check: test (windows-latest, 3.10)
- GitHub Check: test (windows-latest, 3.11)
- GitHub Check: test (windows-latest, 3.12)
- GitHub Check: test (windows-latest, 3.9)
🔇 Additional comments (9)
tests/unit/formatters/test_color_and_terminal.py (1)
224-226: Nice—one-liner TERM purgeReplacing the verbose
if/deldance withpop(..., None)is cleaner and bullet-proof.
Carry on.src/toady/utils.py (1)
62-63: Stringify exceptions like a proSwitching to
{e!s}tightens the f-strings and avoids double conversion noise.
Looks good and doesn’t touch behaviour.Also applies to: 76-77, 101-102
tests/unit/formatters/test_json_formatter.py (1)
645-741: Tests hammer the fallback paths – sweetThe extra cases for objects lacking
to_dictand for forced failures cover the formatter’s ugly edges nicely. No complaints.🧰 Tools
🪛 Pylint (3.3.7)
[refactor] 653-653: Too few public methods (0/2)
(R0903)
[refactor] 672-672: Too few public methods (0/2)
(R0903)
[refactor] 690-690: Too few public methods (0/2)
(R0903)
src/toady/services/resolve_service.py (1)
34-60: Looks goodType-hint switch and
{e!s}formatting are fine; no behavioural change introduced.Also applies to: 70-75
src/toady/models/models.py (1)
30-36: No issuesUpdated error-messages keep prior semantics; nothing further to do.
Also applies to: 192-196
tests/unit/commands/test_schema.py (1)
479-481: Same prefix problem for fetch-side network / file errorsBoth assertions should include
"Error: "to match real output.
Please verify the message template inschema.pyif you believe the prefix is absent.Also applies to: 491-493
src/toady/formatters/format_interfaces.py (1)
65-67: Why dropintfrom the public interface?
PrettyFormatter.format_primitive(and existing callers) still acceptint.
Unless you intend to ban integers, keep the union aligned:-def format_primitive(self, value: Union[str, float, bool, None]) -> str: +def format_primitive(self, value: Union[str, int, float, bool, None]) -> str:tests/unit/test_format_selection.py (1)
244-261: Monkey-patching__import__is risky as fuckSwapping out the built-in importer can grenade parallel tests if they run in the same process. Wrap this in
importlib.reloadtricks or isolate withpytest.subprocessso you don’t fuck neighbouring suites.tests/integration/real_api/test_authentication_flows.py (1)
220-231: This “unauthenticated” test does absolutely nothingYou set an invalid
GH_TOKENthen… exit the test with zero assertions.
Either invoke a command and assert failure, or delete the filler.
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (2)
tests/integration/real_api/test_network_resilience.py (2)
95-101:⚠️ Potential issue
--limit 1000still violates the 1-100 contract
Same issue previously flagged; cap at 100 or pull the value from config.
436-438:⚠️ Potential issueRepeated contract breach (
--limit 1000)Exact same limit violation as above. Please fix all occurrences.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
.github/workflows/ci-uv.yml(1 hunks).github/workflows/ci.yml(3 hunks)pyproject.toml(4 hunks)tests/integration/real_api/test_network_resilience.py(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- pyproject.toml
🧰 Additional context used
🧬 Code Graph Analysis (1)
tests/integration/real_api/test_network_resilience.py (3)
src/toady/cli.py (1)
cli(23-89)tests/integration/conftest.py (9)
verify_test_pr_exists(197-244)performance_monitor(342-402)start_timing(352-359)stop_timing(361-373)api_retry_helper(263-296)rate_limit_aware_delay(248-259)skip_if_slow(432-435)assert_performance_threshold(383-400)integration_test_config(23-48)src/toady/parsers/graphql_queries.py (2)
limit(67-82)limit(317-332)
🪛 actionlint (1.7.7)
.github/workflows/ci-uv.yml
42-42: the runner of "codecov/codecov-action@v3" action is too old to run on GitHub Actions. update the action's version to fix this issue
(action)
🔇 Additional comments (1)
.github/workflows/ci.yml (1)
70-82: Secret fallback expression may not work in all runnersThe
||fallback operator still isn’t universally supported (it requires GHES ≥ 3.8 or Actions runtime ≥ 2023-04-12). Safer pattern:env: GH_TOKEN: ${{ secrets.TOADY_INTEGRATION_TOKEN }}and rely on repository secret-level defaulting, or add a separate conditional step to export
GITHUB_TOKENwhen the custom secret is absent.
- Upgraded `codecov-action` in the CI workflow from v3 to v5 for improved coverage reporting. - Modified error handling in `error_handling.py` to conditionally display error details based on the `TOADY_DEBUG` environment variable. - Enhanced serialization in `format_interfaces.py` to handle exceptions during `to_dict` calls gracefully. - Updated cursor validation in `graphql_queries.py` to raise a `ValueError` for empty cursors instead of returning `False`. - Adjusted test assertions in various test files to improve output handling and error messaging consistency. These changes aim to modernize the CI setup and improve error reporting across the application.
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (6)
tests/integration/real_api/test_end_to_end_workflows.py (1)
214-218: Remove or use theskip_if_slowfixture
skip_if_slowis injected but never referenced, so pytest still resolves it every run with zero benefit. Drop it from the signature or add the logic that actually skips slow runs.tests/unit/commands/test_schema.py (1)
472-477: Duplicaterunnerfixtures across modules can shadow each otherThis file defines its own
runnerfixture, and other test modules do the same. If two of them land in the same pytest collection root, the later import silently overrides the first, leading to confusing fixture-loading order. Prefer placing the sharedCliRunnerfixture intests/conftest.pyand importing it everywhere.tests/integration/real_api/test_performance_monitoring.py (2)
50-67: Test runtime is unnecessarily inflated by fixed 1-second sleepsThe five-iteration loop already measures performance; the extra
time.sleep(1.0)after every call adds 5 s to the wall-clock time of this single test. That slows down local runs and CI without adding meaningful signal.Consider one of:
- # Small delay between calls - time.sleep(1.0) + # Minimal pause just to avoid hammering the API + time.sleep(0.1)or drop the delay entirely if the backend can tolerate the burst.
69-78:print()noise clutters CI logsThe baseline statistics are useful when debugging, but unconditional
print()in tests turns routine CI output into scroll-hell. Preferpytest’s-soption orcapsysfor ad-hoc debugging, or switch tologgingwith a marker-controlled verbosity flag so developers opt-in when needed.tests/integration/real_api/test_network_resilience.py (1)
250-308: Verboseprint()statementsAs with the performance suite, dozens of
print()calls flood logs. Swap tologging.debugguarded by-o log_cli=trueor drop them after local tuning.tests/unit/services/test_github_service.py (1)
747-756:resolve_threadtest asserts no behaviour
resolve_threadcurrently returns raw GraphQL output; this test only re-echoes that behaviour. Either assert expected side-effects (e.g., thread state) or mark as redundant.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
.github/workflows/ci-uv.yml(1 hunks)src/toady/error_handling.py(3 hunks)src/toady/formatters/format_interfaces.py(16 hunks)src/toady/parsers/graphql_queries.py(6 hunks)tests/integration/real_api/test_authentication_flows.py(1 hunks)tests/integration/real_api/test_end_to_end_workflows.py(1 hunks)tests/integration/real_api/test_network_resilience.py(1 hunks)tests/integration/real_api/test_performance_monitoring.py(1 hunks)tests/unit/commands/test_schema.py(1 hunks)tests/unit/services/test_github_service.py(3 hunks)tests/unit/test_cli.py(1 hunks)tests/unit/validators/test_schema_validator.py(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- src/toady/error_handling.py
- tests/unit/validators/test_schema_validator.py
- src/toady/parsers/graphql_queries.py
- src/toady/formatters/format_interfaces.py
🧰 Additional context used
🧠 Learnings (2)
tests/integration/real_api/test_end_to_end_workflows.py (3)
Learnt from: tonyblank
PR: tonyblank/toady-cli#54
File: tests/unit/services/test_fetch_service.py:15-17
Timestamp: 2025-06-12T01:25:15.100Z
Learning: pytest.ini now uses the correct “[pytest]” section header and registers markers `unit`, `service`, `integration`, `model`, `auth`, `resilience`, and `performance`, preventing PytestUnknownMarkWarning in this repository.
Learnt from: tonyblank
PR: tonyblank/toady-cli#54
File: tests/integration/real_api/test_end_to_end_workflows.py:18-20
Timestamp: 2025-06-12T01:25:37.839Z
Learning: pytest.ini now correctly uses the “[pytest]” section header and registers all markers: unit, service, integration, model, auth, resilience, performance, real_api, and slow, eliminating PytestUnknownMarkWarning across the repository.
Learnt from: tonyblank
PR: tonyblank/toady-cli#54
File: tests/integration/real_api/test_end_to_end_workflows.py:53-60
Timestamp: 2025-06-13T15:19:27.384Z
Learning: When reading CLI output in tests, always use
```python
raw_out = getattr(result, "stdout", result.output)
```
before processing, to stay compatible with different Click versions whose `CliRunner.invoke` results may expose either `stdout` or `output`.
tests/integration/real_api/test_authentication_flows.py (1)
Learnt from: tonyblank
PR: tonyblank/toady-cli#54
File: tests/integration/real_api/test_authentication_flows.py:66-73
Timestamp: 2025-06-12T01:25:58.548Z
Learning: Real-API integration tests depend on the GH_TOKEN environment variable; CI workflow now sets `env.GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}` in `.github/workflows/ci.yml`.
🧬 Code Graph Analysis (2)
tests/integration/real_api/test_performance_monitoring.py (3)
src/toady/cli.py (1)
cli(23-89)tests/integration/conftest.py (10)
integration_cli_runner(129-136)verify_test_pr_exists(197-244)performance_monitor(342-402)start_timing(352-359)stop_timing(361-373)skip_if_slow(432-435)assert_performance_threshold(383-400)temp_cache_dir(140-147)network_simulation(300-338)simulate_slow_connection(316-322)src/toady/parsers/graphql_queries.py (2)
limit(67-82)limit(317-332)
tests/unit/commands/test_schema.py (4)
src/toady/commands/schema.py (7)
schema(25-28)_display_query_validation_results(404-459)_display_summary_report(322-401)_has_critical_errors(462-509)check(240-319)fetch(152-224)validate(48-138)src/toady/exceptions.py (1)
ToadyError(71-120)src/toady/validators/schema_validator.py (5)
SchemaValidationError(22-40)fetch_schema(142-192)generate_compatibility_report(557-587)get_schema_version(462-473)validate_query(218-272)tests/conftest.py (1)
runner(22-24)
🪛 Pylint (3.3.7)
tests/integration/real_api/test_end_to_end_workflows.py
[refactor] 24-24: Too many arguments (7/5)
(R0913)
[refactor] 24-24: Too many positional arguments (7/5)
(R0917)
[refactor] 24-24: Too many local variables (26/15)
(R0914)
[refactor] 24-24: Too many statements (68/50)
(R0915)
[refactor] 209-209: Too many arguments (7/5)
(R0913)
[refactor] 209-209: Too many positional arguments (7/5)
(R0917)
tests/integration/real_api/test_performance_monitoring.py
[refactor] 29-29: Too many local variables (17/15)
(R0914)
[refactor] 490-490: Too many local variables (16/15)
(R0914)
[refactor] 557-557: Too many local variables (17/15)
(R0914)
🪛 actionlint (1.7.7)
.github/workflows/ci-uv.yml
44-44: input "file" is not defined in action "codecov/codecov-action@v5". available inputs are "binary", "codecov_yml_path", "commit_parent", "directory", "disable_file_fixes", "disable_safe_directory", "disable_search", "dry_run", "env_vars", "exclude", "fail_ci_if_error", "files", "flags", "gcov_args", "gcov_executable", "gcov_ignore", "gcov_include", "git_service", "handle_no_reports_found", "job_code", "name", "network_filter", "network_prefix", "os", "override_branch", "override_build", "override_build_url", "override_commit", "override_pr", "plugins", "report_code", "report_type", "root_dir", "skip_validation", "slug", "swift_project", "token", "url", "use_legacy_upload_endpoint", "use_oidc", "verbose", "version", "working-directory"
(action)
⏰ Context from checks skipped due to timeout of 90000ms (5)
- GitHub Check: test (windows-latest, 3.12)
- GitHub Check: test (windows-latest, 3.11)
- GitHub Check: test (windows-latest, 3.9)
- GitHub Check: test (windows-latest, 3.10)
- GitHub Check: integration-test
🔇 Additional comments (7)
.github/workflows/ci-uv.yml (6)
1-8: CI triggers configuration looks correct
Push and pull_request events target the intended branches (main,developfor push;mainfor PR).
9-15: Matrix setup is solid
Testing across Python 3.9 through 3.12 ensures compatibility.
16-23: Environment setup is appropriate
Usingastral-sh/setup-uv@v4to installuvbefore bootstrapping Python is a valid approach.
24-30: Dependency installation step is good
Runninguv sync --all-extrascovers all extras and dev dependencies neatly.
31-36: Linting commands are comprehensive
Combining Ruff, Black, and Mypy covers style, formatting, and typing checks.
37-40: Test invocation is correct
uv run pytest --cov=src/toady --cov-report=xmlproperly runs tests and emits coverage.tests/unit/test_cli.py (1)
90-103: Patch target may drift with refactors
patch("toady.commands.fetch.FetchService")assumesFetchServicelives directly intoady.commands.fetch. The implementation recently moved undertoady.services.fetch_service(per earlier commits). If that refactor lands, this patch will silently fail and the test will hit the real service. Search for the authoritative import path and patch that instead.
- Updated `TestFetchCLI` to differentiate error output based on the `TOADY_DEBUG` environment variable, ensuring that error details are only shown in debug mode. - Modified `TestErrorMessageFormatter` to reflect similar changes, verifying that error details are hidden in default mode and displayed in debug mode. - Adjusted cursor validation in `test_graphql_queries.py` to raise a `ValueError` for empty cursors, improving error handling consistency. These changes aim to improve error reporting and enhance test reliability across the application.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
tests/unit/parsers/test_graphql_queries.py (1)
331-335: Good update, but avoid locking tests to private helpersSwitching the expectation from a boolean return to a
ValueErroris correct given the new implementation.
However, the test exercises the private helper_validate_cursor. Relying on a leading-underscore function in a public test suite couples the tests to internal details and can hinder future refactors.Consider driving the same behaviour through the public helpers (
create_paginated_query*) and dropping this direct call, or move the test to an “internal” test module that is clearly scoped for white-box checks.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
tests/integration/cli/test_fetch_cli.py(2 hunks)tests/unit/parsers/test_graphql_queries.py(1 hunks)tests/unit/test_error_handling.py(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- tests/integration/cli/test_fetch_cli.py
🧰 Additional context used
🧬 Code Graph Analysis (2)
tests/unit/test_error_handling.py (1)
src/toady/error_handling.py (2)
ErrorMessageFormatter(247-366)format_error(251-323)
tests/unit/parsers/test_graphql_queries.py (1)
src/toady/parsers/graphql_queries.py (1)
_validate_cursor(8-43)
⏰ Context from checks skipped due to timeout of 90000ms (5)
- GitHub Check: test (windows-latest, 3.12)
- GitHub Check: test (windows-latest, 3.11)
- GitHub Check: test (windows-latest, 3.10)
- GitHub Check: test (windows-latest, 3.9)
- GitHub Check: integration-test
- Changed the `file` parameter to `files` in the Codecov action within the CI workflow for improved compatibility. - Updated `test_authentication_flows.py` to skip a test that cannot properly simulate unauthenticated behavior due to caching issues with the GitHub CLI. - Modified `test_end_to_end_workflows.py` to use `getattr` for accessing command output, ensuring consistent handling of results. - Improved assertions in `test_network_resilience.py` to verify performance thresholds and backoff behavior during network resilience tests. - Refined error handling in `test_error_handling.py` to explicitly clear environment variables during tests. These changes aim to modernize the CI setup and enhance the reliability of integration tests.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (4)
tests/unit/services/test_github_service.py (1)
644-648: Assertion string too strict – likely to break on minor copy edits
assert "timed out after" in str(exc_info.value)couples the test to an exact wording that the service isn’t obligated to keep. Match a shorter token such as"timed out"or inspect the exception class only.tests/integration/real_api/test_end_to_end_workflows.py (1)
64-91: Comment cleanup may silently 404
create_result.stdoutis treated as a URL, yetgh pr commentnormally prints a raw ID unless--json urlis used. Deleting viagh api --method DELETE <id>will fail (suppressed) and leave the test artefact behind.Either request the URL:
- "comment", + "comment", + "--json", + "url",and pass that field to
_cleanup_comment, or build the REST path yourself.tests/integration/real_api/test_network_resilience.py (1)
44-56: Redundant branch – assert success once then drop fallbackSince you already gate on
normal_duration < 30, simply addassert result.exit_code == 0, result.outputand delete the
else:block. The duplicate duration check provides no additional safety.tests/integration/real_api/test_authentication_flows.py (1)
182-189: Header parsing can bleed into JSON body
-iprints headers, blank line, then JSON. Scanning the wholestdoutrisks matching the body. Limit the search:headers, _body = result.stdout.split("\n\n", 1) for line in headers.splitlines(): ...avoids false positives.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
.github/workflows/ci-uv.yml(1 hunks)tests/integration/real_api/test_authentication_flows.py(1 hunks)tests/integration/real_api/test_end_to_end_workflows.py(1 hunks)tests/integration/real_api/test_network_resilience.py(1 hunks)tests/unit/services/test_github_service.py(3 hunks)tests/unit/test_error_handling.py(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- .github/workflows/ci-uv.yml
🚧 Files skipped from review as they are similar to previous changes (1)
- tests/unit/test_error_handling.py
🧰 Additional context used
🧠 Learnings (3)
tests/integration/real_api/test_end_to_end_workflows.py (3)
Learnt from: tonyblank
PR: tonyblank/toady-cli#54
File: tests/unit/services/test_fetch_service.py:15-17
Timestamp: 2025-06-12T01:25:15.100Z
Learning: pytest.ini now uses the correct “[pytest]” section header and registers markers `unit`, `service`, `integration`, `model`, `auth`, `resilience`, and `performance`, preventing PytestUnknownMarkWarning in this repository.
Learnt from: tonyblank
PR: tonyblank/toady-cli#54
File: tests/integration/real_api/test_end_to_end_workflows.py:18-20
Timestamp: 2025-06-12T01:25:37.839Z
Learning: pytest.ini now correctly uses the “[pytest]” section header and registers all markers: unit, service, integration, model, auth, resilience, performance, real_api, and slow, eliminating PytestUnknownMarkWarning across the repository.
Learnt from: tonyblank
PR: tonyblank/toady-cli#54
File: tests/integration/real_api/test_end_to_end_workflows.py:53-60
Timestamp: 2025-06-13T15:19:27.384Z
Learning: When reading CLI output in tests, always use
```python
raw_out = getattr(result, "stdout", result.output)
```
before processing, to stay compatible with different Click versions whose `CliRunner.invoke` results may expose either `stdout` or `output`.
tests/integration/real_api/test_authentication_flows.py (1)
Learnt from: tonyblank
PR: tonyblank/toady-cli#54
File: tests/integration/real_api/test_authentication_flows.py:66-73
Timestamp: 2025-06-12T01:25:58.548Z
Learning: Real-API integration tests depend on the GH_TOKEN environment variable; CI workflow now sets `env.GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}` in `.github/workflows/ci.yml`.
tests/unit/services/test_github_service.py (1)
Learnt from: tonyblank
PR: tonyblank/toady-cli#28
File: src/toady/github_service.py:489-518
Timestamp: 2025-06-09T19:14:20.957Z
Learning: The `_get_review_id_for_comment` method in `src/toady/github_service.py` uses GraphQL to automatically fetch the review ID when replying to node-ID comments, preventing ValueError crashes when review_id is not provided for comment replies.
🪛 Pylint (3.3.7)
tests/integration/real_api/test_end_to_end_workflows.py
[refactor] 24-24: Too many arguments (7/5)
(R0913)
[refactor] 24-24: Too many positional arguments (7/5)
(R0917)
[refactor] 24-24: Too many local variables (26/15)
(R0914)
[refactor] 24-24: Too many statements (69/50)
(R0915)
[refactor] 210-210: Too many arguments (7/5)
(R0913)
[refactor] 210-210: Too many positional arguments (7/5)
(R0917)
⏰ Context from checks skipped due to timeout of 90000ms (5)
- GitHub Check: test (windows-latest, 3.10)
- GitHub Check: test (windows-latest, 3.12)
- GitHub Check: test (windows-latest, 3.9)
- GitHub Check: test (windows-latest, 3.11)
- GitHub Check: integration-test
🔇 Additional comments (1)
tests/integration/real_api/test_end_to_end_workflows.py (1)
50-59: Missing GH_TOKEN guardThese real-API tests assume an authenticated CLI. Add an early
if not os.getenv("GH_TOKEN") and not os.getenv("GITHUB_TOKEN"): pytest.skip("GitHub token not configured")so local runs without a token don’t hard-fail.
pytest.inifor authentication, resilience, and performance tests to enhance test organization and execution.Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Chores
python-dotenvdependency for environment variable management.uvtool.Refactor
list,dict,tuple) instead oftypingimports.{e!s}for consistent string conversion.