Skip to content

Add shellstub and behavioural tests#26

Merged
leynos merged 6 commits intomainfrom
codex/implement-test-helper-for-command-line-stubbing
Jul 7, 2025
Merged

Add shellstub and behavioural tests#26
leynos merged 6 commits intomainfrom
codex/implement-test-helper-for-command-line-stubbing

Conversation

@leynos
Copy link
Copy Markdown
Owner

@leynos leynos commented Jul 6, 2025

Summary

  • add shellstub helper for stubbing command line tools
  • configure pytest to search .github/actions
  • implement behavioural tests for generate-coverage scripts using subprocess and stubs

Testing

  • pytest -q

https://chatgpt.com/codex/tasks/task_e_686af1b0fd348322a84c565ee94e79c9

Summary by Sourcery

Add a reusable shellstub utility and enable behavioural tests for coverage scripts by registering stubs and configuring pytest to include the .github/actions directory

New Features:

  • Add Shellstub StubManager for stubbing command-line tools

Tests:

  • Configure pytest to discover tests under .github/actions
  • Add behavioural tests for generate-coverage scripts using subprocess and shell stubs

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Jul 6, 2025

Reviewer's Guide

This PR introduces a standalone shellstub utility for stubbing CLI tools and integrates behavioural tests for the generate-coverage scripts under a new test directory, updating pytest configuration and adding fixtures to leverage the stubs in subprocess-based tests.

Class diagram for the new shellstub utility

classDiagram
    class Call {
        +list~str~ argv
        +str cwd
        +str timestamp
    }
    class Variant {
        +Sequence~str~ match
        +str stdout = ""
        +str stderr = ""
        +int exit_code = 0
    }
    class StubManager {
        -Path dir
        -Path _calls_file
        -dict~str, dict~ _specs
        +__init__(dir_: Path)
        +register(name: str, variants: list~dict~|None, stdout: str = "", stderr: str = "", exit_code: int = 0)
        +calls_of(name: str) list~Call~
        +env dict~str, str~
        -_wrapper_source(name: str, spec: dict) str
    }
    StubManager --> Call
    StubManager --> Variant
Loading

File-Level Changes

Change Details Files
Introduce a shellstub helper for stubbing CLI commands
  • Define Call and Variant dataclasses for recording invocations and defining response variants
  • Implement StubManager with register, calls_of, env properties
  • Generate executable wrapper scripts that log calls to a JSONL file and dispatch on match or default variant
shellstub.py
Add pytest configuration to include the new test directory
  • Create pytest.ini with testpaths pointing to .github/actions
pytest.ini
Add behavioural tests for generate-coverage scripts
  • Implement run_script helper to invoke scripts via subprocess with stubbed env
  • Write tests for run_rust.py covering success and failure scenarios
  • Write test for merge_cobertura.py validating merge behavior and cleanup
.github/actions/generate-coverage/tests/test_scripts.py
Provide a pytest fixture for shellstub setup
  • Add shell_stubs fixture in conftest.py initializing StubManager in a temp dir
  • Monkeypatch PATH and PYTHONPATH to inject stub wrappers
.github/actions/generate-coverage/tests/conftest.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jul 6, 2025

Summary by CodeRabbit

  • New Features

    • Introduced a framework for stubbing shell commands in tests, enabling controlled simulation of command-line tools.
    • Added comprehensive tests for coverage scripts, including scenarios for successful and failed runs, and merging coverage reports.
    • Added a pytest configuration to specify test discovery paths.
  • Documentation

    • Added and updated docstrings for key functions to clarify their behaviour and intent.
  • Style

    • Reordered import statements and improved spacing in several scripts for consistency and readability.

Summary by CodeRabbit

  • New Features
    • Introduced a framework for creating and managing command-line stubs, enabling controlled simulation of shell commands during testing.
    • Added comprehensive automated tests for coverage-related scripts, including scenarios for successful and failed executions as well as file merging operations.
    • Added a test fixture to streamline shell command stubbing in the test environment.
    • Added a configuration file to specify test discovery paths.

Walkthrough

This update introduces a shell command stubbing framework (shellstub.py), new test fixtures, and comprehensive tests for coverage-related scripts within a GitHub Actions context. It also adds a pytest.ini configuration to define test discovery paths. The changes enable isolated and controlled testing of scripts that interact with external shell commands.

Changes

File(s) Change Summary
.github/actions/generate-coverage/tests/conftest.py Added shell_stubs fixture to set up shell command stubs for use in tests.
.github/actions/generate-coverage/tests/test_scripts.py Introduced tests for coverage scripts, including helpers and tests for Rust and Cobertura merging scripts.
pytest.ini Added pytest configuration to restrict test discovery to .github/actions.
shellstub.py Added shell command stubbing framework with stub registration, call logging, and environment management.

Sequence Diagram(s)

sequenceDiagram
    participant Test as Test Function
    participant Stub as StubManager
    participant Script as Coverage Script
    participant Shell as Shell Stub

    Test->>Stub: Register shell command stub(s)
    Test->>Script: Run script with stubbed environment
    Script->>Shell: Invoke shell command (e.g., cargo, uvx)
    Shell->>Stub: Log call, match variant, return response
    Script->>Test: Output result, write files, exit
    Test->>Stub: Retrieve and assert logged calls
Loading

Possibly related PRs

Poem

In the warren of code, the rabbits delight,
With stubby new shells and tests running right.
Coverage scripts checked with a hop and a bound,
Each command’s a carrot, each log is a mound.
Now pytest will find us, wherever we hide—
In shell-stubbed meadows, we debug with pride!
🐇

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/implement-test-helper-for-command-line-stubbing

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need 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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai auto-generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey @leynos - I've reviewed your changes - here's some feedback:

  • Rather than inlining the full JSON spec in the generated wrapper, consider writing the spec to a separate file and loading it in the stub to avoid complex escaping and improve maintainability.
  • The tests hard-code calling uv run --script; you might extract that into a configurable helper or fixture to avoid test failures if the CLI tool name or invocation changes.
  • StubManager.env currently merges the entire host environment, which could introduce unintended variables—consider only injecting PATH and PYTHONPATH and clearing or isolating other env vars for more deterministic tests.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Rather than inlining the full JSON spec in the generated wrapper, consider writing the spec to a separate file and loading it in the stub to avoid complex escaping and improve maintainability.
- The tests hard-code calling `uv run --script`; you might extract that into a configurable helper or fixture to avoid test failures if the CLI tool name or invocation changes.
- `StubManager.env` currently merges the entire host environment, which could introduce unintended variables—consider only injecting PATH and PYTHONPATH and clearing or isolating other env vars for more deterministic tests.

## Individual Comments

### Comment 1
<location> `shellstub.py:53` </location>
<code_context>
+        out: list[Call] = []
+        if not self._calls_file.exists():
+            return out
+        for line in self._calls_file.read_text().splitlines():
+            rec = json.loads(line)
+            if rec["cmd"] == name:
+                out.append(Call(rec["argv"], rec["cwd"], rec["ts"]))
</code_context>

<issue_to_address>
No error handling for malformed JSON lines in calls file.

Add error handling around json.loads to skip or log malformed lines, ensuring the function continues processing valid entries.
</issue_to_address>

### Comment 2
<location> `shellstub.py:61` </location>
<code_context>
+
+    @property
+    def env(self) -> dict[str, str]:
+        return {
+            "PATH": f"{self.dir}{os.pathsep}{os.getenv('PATH', '')}",
+            "PYTHONPATH": os.getenv("PYTHONPATH", ""),
+            **os.environ,
+        }
+
</code_context>

<issue_to_address>
Order of environment variable merging may unintentionally override PATH and PYTHONPATH.

Merging os.environ last will overwrite the custom PATH and PYTHONPATH values. To preserve your changes, reverse the merge order or use a more explicit strategy.
</issue_to_address>

### Comment 3
<location> `shellstub.py:29` </location>
<code_context>
+        self._calls_file = self.dir / "calls.jsonl"
+        self._specs: dict[str, dict] = {}
+
+    def register(
+        self,
+        name: str,
</code_context>

<issue_to_address>
Consider writing the stub spec to a separate JSON file and using a static template for the wrapper script instead of embedding the entire spec in a generated f-string.

```suggestion
You don’t need to embed the entire JSON‐spec into a huge f-string at registration time. Instead, write out a small `<name>.json` and use a static template that the stub reads at runtime. You can then drop both the unused `Variant` class and the in-memory `_specs` dict entirely.

1) Define a module‐level template:
```python
_WRAPPER_TEMPLATE = """#!/usr/bin/env python3
import json, os, sys
import datetime as _dt

# load spec from JSON file
with open({spec_path!r}) as f:
    spec = json.load(f)

# record invocation
rec = {{
    "cmd": {cmd!r},
    "argv": sys.argv[1:],
    "cwd": os.getcwd(),
    "ts": _dt.datetime.utcnow().isoformat() + 'Z'
}}
with open({calls_file!r}, "a") as fh:
    json.dump(rec, fh); fh.write("\\n")

# pick matching variant
for var in spec["variants"]:
    if var.get("match") is None or var["match"] == sys.argv[1:]:
        sys.stdout.write(var.get("stdout", ""))
        sys.stderr.write(var.get("stderr", ""))
        sys.exit(var.get("exit_code", 0))

sys.exit(127)
"""
```

2) Simplify `StubManager.register` to write the spec file and plug in paths:
```python
def register(self, name: str, *, variants: list[dict] | None = None, …) -> None:
    # default single‐variant
    if variants is None:
        variants = [{"match": None, "stdout": stdout, "stderr": stderr, "exit_code": exit_code}]
    # write out spec JSON
    spec_path = self.dir / f"{name}.json"
    spec_path.write_text(json.dumps({"variants": variants}))
    # render wrapper
    wrapper = _WRAPPER_TEMPLATE.format(
        spec_path=str(spec_path),
        calls_file=str(self._calls_file),
        cmd=name,
    )
    stub_path = self.dir / name
    stub_path.write_text(wrapper)
    stub_path.chmod(0o755)
```

3) Remove the in‐memory `self._specs` and the `Variant` dataclass entirely, since neither is used outside of generating the JSON file.

This keeps the same behavior while dramatically shrinking `_wrapper_source` and avoiding complex f-string embedding.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread shellstub.py
Comment thread shellstub.py Outdated
Comment thread shellstub.py
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 12

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c8a105e and dbe8162.

📒 Files selected for processing (4)
  • .github/actions/generate-coverage/tests/conftest.py (1 hunks)
  • .github/actions/generate-coverage/tests/test_scripts.py (1 hunks)
  • pytest.ini (1 hunks)
  • shellstub.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
`.github/actions/*/tests/**/*`: Contract tests must validate that declared inputs/outputs round-trip correctly

.github/actions/*/tests/**/*: Contract tests must validate that declared inputs/outputs round-trip correctly

📄 Source: CodeRabbit Inference Engine (AGENTS.md)

List of files the instruction was applied to:

  • .github/actions/generate-coverage/tests/conftest.py
  • .github/actions/generate-coverage/tests/test_scripts.py
🧬 Code Graph Analysis (1)
.github/actions/generate-coverage/tests/conftest.py (1)
shellstub.py (1)
  • StubManager (22-90)
🪛 Ruff (0.11.9)
.github/actions/generate-coverage/tests/conftest.py

12-12: Missing type annotation for function argument tmp_path

(ANN001)


12-12: Missing type annotation for function argument monkeypatch

(ANN001)


17-17: No teardown in fixture shell_stubs, use return instead of yield

Replace yield with return

(PT022)

shellstub.py

4-4: sys imported but unused

Remove unused import: sys

(F401)


7-7: Import from collections.abc instead: Sequence

Import from collections.abc

(UP035)


23-23: Missing return type annotation for special method __init__

Add return type annotation: None

(ANN204)


39-39: Unnecessary dict() call (rewrite as a literal)

Rewrite as a literal

(C408)

.github/actions/generate-coverage/tests/test_scripts.py

9-9: subprocess call: check for execution of untrusted input

(S603)


11-11: Missing return type annotation for public function test_run_rust_success

Add return type annotation: None

(ANN201)


11-11: Missing type annotation for function argument tmp_path

(ANN001)


11-11: Missing type annotation for function argument shell_stubs

(ANN001)


42-42: Missing return type annotation for public function test_run_rust_failure

Add return type annotation: None

(ANN201)


42-42: Missing type annotation for function argument tmp_path

(ANN001)


42-42: Missing type annotation for function argument shell_stubs

(ANN001)


62-62: Missing return type annotation for public function test_merge_cobertura

Add return type annotation: None

(ANN201)


62-62: Missing type annotation for function argument tmp_path

(ANN001)


62-62: Missing type annotation for function argument shell_stubs

(ANN001)


71-71: Unnecessary dict() call (rewrite as a literal)

Rewrite as a literal

(C408)


71-71: Trailing comma missing

Add trailing comma

(COM812)


84-84: Assertion should be broken down into multiple parts

Break down assertion into multiple parts

(PT018)


86-86: Assertion should be broken down into multiple parts

Break down assertion into multiple parts

(PT018)

🪛 Pylint (3.3.7)
.github/actions/generate-coverage/tests/conftest.py

[convention] 1-1: Missing module docstring

(C0114)


[error] 9-9: Unable to import 'shellstub'

(E0401)


[convention] 9-9: Import "from shellstub import StubManager" should be placed at the top of the module

(C0413)


[convention] 12-12: Missing function or method docstring

(C0116)


[convention] 2-2: standard import "os" should be placed before third party import "pytest"

(C0411)


[convention] 3-3: standard import "sys" should be placed before third party import "pytest"

(C0411)


[convention] 4-4: standard import "pathlib.Path" should be placed before third party import "pytest"

(C0411)

shellstub.py

[convention] 1-1: Missing module docstring

(C0114)


[convention] 10-10: Missing class docstring

(C0115)


[convention] 16-16: Missing class docstring

(C0115)


[convention] 22-22: Missing class docstring

(C0115)


[convention] 29-29: Missing function or method docstring

(C0116)


[refactor] 29-29: Too many arguments (6/5)

(R0913)


[refactor] 39-39: Consider using '{"match": None, "stdout": stdout, "stderr": stderr, "exit_code": exit_code, ... }' instead of a call to 'dict'.

(R1735)


[convention] 49-49: Missing function or method docstring

(C0116)


[convention] 60-60: Missing function or method docstring

(C0116)


[warning] 4-4: Unused import sys

(W0611)

.github/actions/generate-coverage/tests/test_scripts.py

[convention] 87-87: Trailing newlines

(C0305)


[convention] 1-1: Missing module docstring

(C0114)


[convention] 7-7: Missing function or method docstring

(C0116)


[warning] 9-9: 'subprocess.run' used without explicitly defining the value for 'check'.

(W1510)


[convention] 11-11: Missing function or method docstring

(C0116)


[convention] 42-42: Missing function or method docstring

(C0116)


[convention] 62-62: Missing function or method docstring

(C0116)


[refactor] 71-71: Consider using '{"match": ['merge-cobertura', str(rust), str(py)], "stdout": '', ... }' instead of a call to 'dict'.

(R1735)

🪛 Flake8 (7.2.0)
shellstub.py

[error] 4-4: 'sys' imported but unused

(F401)

🔇 Additional comments (3)
pytest.ini (1)

1-2: LGTM! Clean pytest configuration.

The configuration correctly restricts test discovery to the .github/actions directory, which aligns with the new test infrastructure being added.

shellstub.py (1)

67-90: No code-injection risk in _wrapper_source
The f-string embeds spec via json.dumps and quotes name/calls_file with repr, so untrusted data is inserted only as JSON or string literals—there’s no eval of user input. You can ignore the earlier security warning.

Likely an incorrect or invalid review comment.

.github/actions/generate-coverage/tests/test_scripts.py (1)

62-87: No changes needed – input/output contract is fully tested.

The existing test in .github/actions/generate-coverage/tests/test_scripts.py already:

  • Sets RUST_FILE, PYTHON_FILE and OUTPUT_PATH via environment variables
  • Stubs and asserts the uvx merge-cobertura <rust> <python> invocation
  • Verifies a zero exit code
  • Confirms the merged output is written to OUTPUT_PATH
  • Confirms the input files are removed post-merge

All declared inputs/outputs are round-tripped and validated according to the guidelines.

Comment thread shellstub.py Outdated
Comment thread shellstub.py
Comment thread shellstub.py
Comment thread shellstub.py
Comment thread shellstub.py
Comment thread .github/actions/generate-coverage/tests/conftest.py Outdated
Comment thread .github/actions/generate-coverage/tests/test_scripts.py Outdated
Comment thread .github/actions/generate-coverage/tests/test_scripts.py Outdated
Comment thread .github/actions/generate-coverage/tests/test_scripts.py Outdated
Comment thread .github/actions/generate-coverage/tests/test_scripts.py Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (8)
shellstub.py (8)

1-1: Add module docstring.

The module lacks documentation explaining its purpose as a shell command stubbing framework for testing.


7-7: Import Sequence from collections.abc for modern Python compatibility.

-from typing import Sequence
+from collections.abc import Sequence

9-21: Add docstrings to dataclasses for better maintainability.

The Call and Variant dataclasses lack documentation explaining their purpose and attributes.


22-28: Add class docstring and return type annotation.

The StubManager class lacks documentation and the __init__ method is missing a return type annotation.


29-39: Add docstring and use dictionary literal.

The method lacks documentation and uses dict() instead of a literal.


51-51: Add method documentation.

The method lacks a docstring explaining its purpose and return value.


55-56: Add error handling for malformed JSON.

No error handling around json.loads which could crash on malformed lines.


61-67: Fix environment variable merging order and add documentation.

The property lacks documentation and the merging order will override custom PATH values.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dbe8162 and b21d9ae.

📒 Files selected for processing (1)
  • shellstub.py (1 hunks)
🧰 Additional context used
🪛 Ruff (0.11.9)
shellstub.py

4-4: sys imported but unused

Remove unused import: sys

(F401)


7-7: Import from collections.abc instead: Sequence

Import from collections.abc

(UP035)


23-23: Missing return type annotation for special method __init__

Add return type annotation: None

(ANN204)


39-39: Unnecessary dict() call (rewrite as a literal)

Rewrite as a literal

(C408)

🪛 Flake8 (7.2.0)
shellstub.py

[error] 4-4: 'sys' imported but unused

(F401)

🪛 Pylint (3.3.7)
shellstub.py

[convention] 1-1: Missing module docstring

(C0114)


[convention] 10-10: Missing class docstring

(C0115)


[convention] 16-16: Missing class docstring

(C0115)


[convention] 22-22: Missing class docstring

(C0115)


[convention] 29-29: Missing function or method docstring

(C0116)


[refactor] 29-29: Too many arguments (6/5)

(R0913)


[refactor] 39-39: Consider using '{"match": None, "stdout": stdout, "stderr": stderr, "exit_code": exit_code, ... }' instead of a call to 'dict'.

(R1735)


[convention] 51-51: Missing function or method docstring

(C0116)


[convention] 62-62: Missing function or method docstring

(C0116)


[warning] 4-4: Unused import sys

(W0611)

🔇 Additional comments (1)
shellstub.py (1)

45-49: Good implementation of external spec file.

The method now correctly saves the spec to an external JSON file and passes its path to the wrapper, which addresses the previous concern about embedding large JSON strings.

Comment thread shellstub.py
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (7)
.github/actions/generate-coverage/tests/conftest.py (2)

1-11: Import organisation needs improvement

The imports should follow standard convention with standard library imports first, then third-party imports.


13-23: Add type annotations to fixture parameters

The fixture parameters tmp_path and monkeypatch need type annotations for clarity.

.github/actions/generate-coverage/tests/test_scripts.py (4)

7-13: Improve type annotation and documentation

The function needs a more specific return type annotation and documentation.


15-44: Contract test must validate complete input/output round-trip

Per coding guidelines, contract tests must validate that declared inputs/outputs round-trip correctly. The test should verify all input parameters are properly passed through to the cargo command.


47-64: Add type annotations

Function parameters need type annotations for consistency.


68-98: Improve code style and assertion clarity

Break down complex assertions and use literal syntax instead of dict() call.

shellstub.py (1)

101-109: Fix environment variable merge order

The current merge order will overwrite your custom PATH and PYTHONPATH with values from os.environ.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b21d9ae and 5367c2f.

📒 Files selected for processing (9)
  • .github/actions/generate-coverage/scripts/ratchet_coverage.py (1 hunks)
  • .github/actions/generate-coverage/scripts/run_python.py (1 hunks)
  • .github/actions/generate-coverage/scripts/run_rust.py (1 hunks)
  • .github/actions/generate-coverage/tests/conftest.py (1 hunks)
  • .github/actions/generate-coverage/tests/test_scripts.py (1 hunks)
  • .github/actions/ratchet-coverage/scripts/install_cargo_llvm_cov.py (1 hunks)
  • .github/actions/ratchet-coverage/scripts/ratchet_coverage.py (1 hunks)
  • .github/actions/ratchet-coverage/scripts/run_coverage.py (1 hunks)
  • shellstub.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
`.github/actions/*/tests/**/*`: Contract tests must validate that declared inputs/outputs round-trip correctly

.github/actions/*/tests/**/*: Contract tests must validate that declared inputs/outputs round-trip correctly

📄 Source: CodeRabbit Inference Engine (AGENTS.md)

List of files the instruction was applied to:

  • .github/actions/generate-coverage/tests/conftest.py
  • .github/actions/generate-coverage/tests/test_scripts.py
🧬 Code Graph Analysis (1)
.github/actions/generate-coverage/tests/conftest.py (1)
shellstub.py (1)
  • StubManager (37-147)
🪛 Pylint (3.3.7)
.github/actions/ratchet-coverage/scripts/install_cargo_llvm_cov.py

[error] 6-6: Unable to import 'typer'

(E0401)

.github/actions/generate-coverage/tests/conftest.py

[convention] 1-1: Missing module docstring

(C0114)


[error] 10-10: Unable to import 'shellstub'

(E0401)


[convention] 10-10: Import "from shellstub import StubManager" should be placed at the top of the module

(C0413)

.github/actions/generate-coverage/tests/test_scripts.py

[convention] 99-99: Trailing newlines

(C0305)


[convention] 1-1: Missing module docstring

(C0114)


[warning] 13-13: 'subprocess.run' used without explicitly defining the value for 'check'.

(W1510)

shellstub.py

[convention] 149-149: Trailing newlines

(C0305)


[convention] 1-1: Missing module docstring

(C0114)


[warning] 3-3: String statement has no effect

(W0105)


[convention] 5-5: Import "import json" should be placed at the top of the module

(C0413)


[convention] 6-6: Import "import os" should be placed at the top of the module

(C0413)


[convention] 7-7: Import "import sys" should be placed at the top of the module

(C0413)


[convention] 8-8: Import "import textwrap" should be placed at the top of the module

(C0413)


[convention] 9-9: Import "from collections.abc import Callable, Sequence" should be placed at the top of the module

(C0413)


[convention] 10-10: Import "from dataclasses import dataclass" should be placed at the top of the module

(C0413)


[convention] 11-11: Import "from pathlib import Path" should be placed at the top of the module

(C0413)


[convention] 32-32: Missing class docstring

(C0115)


[refactor] 48-48: Too many arguments (7/5)

(R0913)


[warning] 7-7: Unused import sys

(W0611)


[warning] 8-8: Unused import textwrap

(W0611)

🪛 Ruff (0.11.9)
.github/actions/generate-coverage/tests/conftest.py

14-14: Missing type annotation for function argument tmp_path

(ANN001)


14-14: Missing type annotation for function argument monkeypatch

(ANN001)


21-21: Trailing comma missing

Add trailing comma

(COM812)


23-23: No teardown in fixture shell_stubs, use return instead of yield

Replace yield with return

(PT022)

.github/actions/generate-coverage/tests/test_scripts.py

8-8: Trailing comma missing

Add trailing comma

(COM812)


13-13: subprocess call: check for execution of untrusted input

(S603)


15-15: Missing type annotation for function argument tmp_path

(ANN001)


15-15: Missing type annotation for function argument shell_stubs

(ANN001)


47-47: Missing type annotation for function argument tmp_path

(ANN001)


47-47: Missing type annotation for function argument shell_stubs

(ANN001)


68-68: Missing type annotation for function argument tmp_path

(ANN001)


68-68: Missing type annotation for function argument shell_stubs

(ANN001)


82-82: Trailing comma missing

Add trailing comma

(COM812)


96-96: Assertion should be broken down into multiple parts

Break down assertion into multiple parts

(PT018)


98-98: Assertion should be broken down into multiple parts

Break down assertion into multiple parts

(PT018)

shellstub.py

5-5: Module level import not at top of file

(E402)


6-6: Module level import not at top of file

(E402)


7-7: Module level import not at top of file

(E402)


7-7: sys imported but unused

Remove unused import: sys

(F401)


8-8: Module level import not at top of file

(E402)


8-8: textwrap imported but unused

Remove unused import: textwrap

(F401)


9-9: Module level import not at top of file

(E402)


10-10: Module level import not at top of file

(E402)


11-11: Module level import not at top of file

(E402)


66-66: Trailing comma missing

Add trailing comma

(COM812)


76-76: Trailing comma missing

Add trailing comma

(COM812)


82-82: Trailing comma missing

Add trailing comma

(COM812)

🪛 Flake8 (7.2.0)
shellstub.py

[error] 7-7: 'sys' imported but unused

(F401)


[error] 8-8: 'textwrap' imported but unused

(F401)

🔇 Additional comments (7)
.github/actions/ratchet-coverage/scripts/ratchet_coverage.py (1)

6-8: Import grouping/spacing looks correct – no action required.

Placing a blank line after the last standard-library import matches PEP 8 and the rest of the codebase; the change is purely cosmetic and safe to merge.

.github/actions/generate-coverage/scripts/ratchet_coverage.py (1)

6-8: Consistent import spacing – good job.

The added newline keeps builtin and third-party imports visually separated. No further feedback.

.github/actions/ratchet-coverage/scripts/install_cargo_llvm_cov.py (1)

6-8: Confirm typer is available in the runtime image.

Static analysis flagged import typer as unresolved (E0401). The shebang’s uv stub will install declared dependencies, but double-check that the CI image used for this step includes typer>=0.9 or pin it explicitly to silence tooling warnings.

.github/actions/generate-coverage/scripts/run_python.py (1)

8-12: Import block tidy-up acknowledged.

Grouping standard-library imports (contextlib, Path) before third-party ones (defusedxml, typer) improves readability and matches the other scripts.

.github/actions/ratchet-coverage/scripts/run_coverage.py (1)

8-9: Import reordering looks good

The reordering of imports maintains proper grouping and improves consistency across the codebase.

shellstub.py (2)

14-35: Well-documented dataclasses

The dataclasses are properly documented with clear docstrings explaining their purpose.


1-11: Fix module docstring placement

The module docstring should be the first statement after the future import, before other imports.

 from __future__ import annotations
 
-"""Minimal framework for stubbing command line tools in tests."""
-
 import json
 import os
 import sys
 import textwrap
 from collections.abc import Callable, Sequence
 from dataclasses import dataclass
 from pathlib import Path

+"""Minimal framework for stubbing command line tools in tests."""

Actually, I need to reconsider - module docstrings should come immediately after imports in Python. The current placement is actually correct. Let me skip this comment.

Comment on lines 8 to 10
import re
from pathlib import Path

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Minor import reorder – verify formatter settings.

re and Path are both std-lib, so the new order is fine; just ensure your isort/black configuration won’t shuffle them back again to avoid future diff noise. Consider a blank line before the first third-party import (typer) if you want strict PEP 8 spacing.

🤖 Prompt for AI Agents
In .github/actions/generate-coverage/scripts/run_rust.py around lines 8 to 10,
the imports of standard library modules 're' and 'Path' are reordered correctly,
but to prevent future unnecessary diffs, verify your isort and black formatter
settings to keep this order stable. Also, add a blank line after the standard
library imports and before the third-party import 'typer' to comply with strict
PEP 8 import grouping and spacing conventions.

Comment thread .github/actions/generate-coverage/tests/conftest.py Outdated
Comment thread shellstub.py
Comment thread shellstub.py Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
.github/actions/generate-coverage/tests/conftest.py (1)

24-24: Add type annotations and keep yield for proper fixture behaviour.

The fixture needs type annotations, and the yield is correct for pytest fixtures that require cleanup context.

-def shell_stubs(tmp_path, monkeypatch) -> StubManager:
+def shell_stubs(tmp_path: pytest.TempPathFactory, monkeypatch: pytest.MonkeyPatch) -> StubManager:
📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8201f1f and d2b4dbb.

📒 Files selected for processing (1)
  • .github/actions/generate-coverage/tests/conftest.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
`.github/actions/*/tests/**/*`: Contract tests must validate that declared inputs/outputs round-trip correctly

.github/actions/*/tests/**/*: Contract tests must validate that declared inputs/outputs round-trip correctly

📄 Source: CodeRabbit Inference Engine (AGENTS.md)

List of files the instruction was applied to:

  • .github/actions/generate-coverage/tests/conftest.py
🧬 Code Graph Analysis (1)
.github/actions/generate-coverage/tests/conftest.py (1)
shellstub.py (1)
  • StubManager (38-156)
🪛 Ruff (0.11.9)
.github/actions/generate-coverage/tests/conftest.py

14-14: Avoid specifying long messages outside the exception class

(TRY003)


24-24: Missing type annotation for function argument tmp_path

(ANN001)


24-24: Missing type annotation for function argument monkeypatch

(ANN001)


33-33: Trailing comma missing

Add trailing comma

(COM812)


35-35: No teardown in fixture shell_stubs, use return instead of yield

Replace yield with return

(PT022)

🔇 Additional comments (2)
.github/actions/generate-coverage/tests/conftest.py (2)

17-18: LGTM! Robust path calculation.

The _find_root function properly addresses the previous fragile path calculation concern by dynamically searching for project markers.


29-30: LGTM! Proper global state management.

Setting the global manager ensures the stubs work correctly across subprocess calls. The yield in the fixture is appropriate for cleanup context.

Comment on lines +32 to +34
monkeypatch.setenv(
"PYTHONPATH", f"{ROOT}{os.pathsep}{os.getenv('PYTHONPATH','')}"
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Add trailing comma for consistency.

     monkeypatch.setenv(
-        "PYTHONPATH", f"{ROOT}{os.pathsep}{os.getenv('PYTHONPATH','')}"
+        "PYTHONPATH", f"{ROOT}{os.pathsep}{os.getenv('PYTHONPATH','')}",
     )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
monkeypatch.setenv(
"PYTHONPATH", f"{ROOT}{os.pathsep}{os.getenv('PYTHONPATH','')}"
)
monkeypatch.setenv(
"PYTHONPATH", f"{ROOT}{os.pathsep}{os.getenv('PYTHONPATH','')}",
)
🧰 Tools
🪛 Ruff (0.11.9)

33-33: Trailing comma missing

Add trailing comma

(COM812)

🤖 Prompt for AI Agents
In .github/actions/generate-coverage/tests/conftest.py around lines 32 to 34,
the call to monkeypatch.setenv is missing a trailing comma after the last
argument. Add a trailing comma after the f-string argument to maintain
consistency and improve code readability.

Comment on lines +8 to +14
def _find_root(start: Path) -> Path:
"""Return the nearest ancestor containing ``pyproject.toml`` or ``.git``."""

for parent in (start, *start.parents):
if (parent / "pyproject.toml").exists() or (parent / ".git").exists():
return parent
raise FileNotFoundError(f"Project root not found from {start}")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Consider shortening the exception message.

The exception message is quite long. Consider using a shorter message or define a custom exception class.

-    raise FileNotFoundError(f"Project root not found from {start}")
+    raise FileNotFoundError("Project root not found")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def _find_root(start: Path) -> Path:
"""Return the nearest ancestor containing ``pyproject.toml`` or ``.git``."""
for parent in (start, *start.parents):
if (parent / "pyproject.toml").exists() or (parent / ".git").exists():
return parent
raise FileNotFoundError(f"Project root not found from {start}")
def _find_root(start: Path) -> Path:
"""Return the nearest ancestor containing ``pyproject.toml`` or ``.git``."""
for parent in (start, *start.parents):
if (parent / "pyproject.toml").exists() or (parent / ".git").exists():
return parent
raise FileNotFoundError("Project root not found")
🧰 Tools
🪛 Ruff (0.11.9)

14-14: Avoid specifying long messages outside the exception class

(TRY003)

🤖 Prompt for AI Agents
In .github/actions/generate-coverage/tests/conftest.py around lines 8 to 14, the
FileNotFoundError exception message is too long. Shorten the message to a
concise phrase like "Project root not found" or create a custom exception class
with a brief message to replace the current long message.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (2)
shellstub.py (1)

96-98: Add error handling for malformed JSON in calls file

The JSON parsing could fail if the calls file contains malformed data. Consider adding error handling to skip invalid lines.

 for line in self._calls_file.read_text().splitlines():
-    rec = json.loads(line)
-    if rec["cmd"] == name:
-        out.append(Call(rec["argv"], rec["cwd"], rec["ts"]))
+    try:
+        rec = json.loads(line)
+        if rec["cmd"] == name:
+            out.append(Call(rec["argv"], rec["cwd"], rec["ts"]))
+    except (json.JSONDecodeError, KeyError) as e:
+        # Log or skip malformed entries
+        continue
.github/actions/generate-coverage/tests/conftest.py (1)

34-36: Add trailing comma for consistency

     monkeypatch.setenv(
-        "PYTHONPATH", f"{ROOT}{os.pathsep}{os.getenv('PYTHONPATH','')}"
+        "PYTHONPATH", f"{ROOT}{os.pathsep}{os.getenv('PYTHONPATH','')}",
     )
📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d2b4dbb and bc32ce0.

📒 Files selected for processing (3)
  • .github/actions/generate-coverage/tests/conftest.py (1 hunks)
  • .github/actions/generate-coverage/tests/test_scripts.py (1 hunks)
  • shellstub.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
`.github/actions/*/tests/**/*`: Contract tests must validate that declared inputs/outputs round-trip correctly

.github/actions/*/tests/**/*: Contract tests must validate that declared inputs/outputs round-trip correctly

📄 Source: CodeRabbit Inference Engine (AGENTS.md)

List of files the instruction was applied to:

  • .github/actions/generate-coverage/tests/conftest.py
  • .github/actions/generate-coverage/tests/test_scripts.py
🧬 Code Graph Analysis (2)
.github/actions/generate-coverage/tests/conftest.py (1)
shellstub.py (1)
  • StubManager (38-155)
.github/actions/generate-coverage/tests/test_scripts.py (2)
shellstub.py (4)
  • StubManager (38-155)
  • env (103-109)
  • register (49-87)
  • calls_of (90-100)
.github/actions/generate-coverage/tests/conftest.py (1)
  • shell_stubs (26-37)
🪛 Ruff (0.11.9)
.github/actions/generate-coverage/tests/conftest.py

16-16: Avoid specifying long messages outside the exception class

(TRY003)


35-35: Trailing comma missing

Add trailing comma

(COM812)


37-37: No teardown in fixture shell_stubs, use return instead of yield

Replace yield with return

(PT022)

.github/actions/generate-coverage/tests/test_scripts.py

10-10: Trailing comma missing

Add trailing comma

(COM812)


15-15: subprocess call: check for execution of untrusted input

(S603)


97-97: Trailing comma missing

Add trailing comma

(COM812)


114-114: Assertion should be broken down into multiple parts

Break down assertion into multiple parts

(PT018)

shellstub.py

5-5: Module level import not at top of file

(E402)


6-6: Module level import not at top of file

(E402)


7-7: Module level import not at top of file

(E402)


7-7: sys imported but unused

Remove unused import: sys

(F401)


8-8: Module level import not at top of file

(E402)


9-9: Module level import not at top of file

(E402)


10-10: Module level import not at top of file

(E402)


67-67: Trailing comma missing

Add trailing comma

(COM812)


77-77: Trailing comma missing

Add trailing comma

(COM812)


83-83: Trailing comma missing

Add trailing comma

(COM812)

🔇 Additional comments (5)
shellstub.py (2)

13-36: Well-structured data model for stub framework

The dataclasses provide a clean and well-documented interface for defining stub behaviour and recording invocations. The use of type annotations and default values is appropriate.


111-155: Excellent wrapper script generation with proper func support

The wrapper source correctly integrates with the global manager to support custom function callbacks, addressing previous concerns. The script properly logs calls, handles variant matching, and executes custom functions when provided.

.github/actions/generate-coverage/tests/conftest.py (1)

10-17: Robust project root detection

The _find_root function provides a reliable way to locate the project root by searching for common project markers. This is more maintainable than using a fixed directory depth.

.github/actions/generate-coverage/tests/test_scripts.py (2)

17-60: Comprehensive contract validation for Rust coverage script

The test properly validates the input/output contract by:

  • Verifying the output path is correctly passed to cargo
  • Confirming the format flag (--lcov) matches the input
  • Ensuring feature flags are properly handled
  • Checking that default features are correctly disabled
  • Validating the coverage percentage output

This meets the coding guideline requirement for contract tests.


62-80: Proper error propagation testing

The test correctly validates that cargo failures are propagated with the same exit code and appropriate error messaging.

Comment thread shellstub.py
Comment on lines +60 to +88
if variants is None:
variants = [
{
"match": None,
"stdout": stdout,
"stderr": stderr,
"exit_code": exit_code,
}
]
parsed = []
for v in variants:
parsed.append(
Variant(
match=v["match"],
stdout=v.get("stdout", ""),
stderr=v.get("stderr", ""),
exit_code=v.get("exit_code", 0),
)
)
spec = StubSpec(parsed, func=func)
self._specs[name] = spec
spec_file = self.dir / f"{name}.json"
spec_file.write_text(
json.dumps({"variants": [v.__dict__ for v in parsed]})
)
path = self.dir / name
path.write_text(self._wrapper_source(name, spec_file))
path.chmod(0o755)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Add trailing commas for consistency

Missing trailing commas in multi-line data structures.

                 {
                     "match": None,
                     "stdout": stdout,
                     "stderr": stderr,
                     "exit_code": exit_code,
-                }
+                },
             ]
         parsed = []
         for v in variants:
             parsed.append(
                 Variant(
                     match=v["match"],
                     stdout=v.get("stdout", ""),
                     stderr=v.get("stderr", ""),
                     exit_code=v.get("exit_code", 0),
-                )
+                ),
             )
         spec = StubSpec(parsed, func=func)
         self._specs[name] = spec
         spec_file = self.dir / f"{name}.json"
         spec_file.write_text(
-            json.dumps({"variants": [v.__dict__ for v in parsed]})
+            json.dumps({"variants": [v.__dict__ for v in parsed]}),
         )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if variants is None:
variants = [
{
"match": None,
"stdout": stdout,
"stderr": stderr,
"exit_code": exit_code,
}
]
parsed = []
for v in variants:
parsed.append(
Variant(
match=v["match"],
stdout=v.get("stdout", ""),
stderr=v.get("stderr", ""),
exit_code=v.get("exit_code", 0),
)
)
spec = StubSpec(parsed, func=func)
self._specs[name] = spec
spec_file = self.dir / f"{name}.json"
spec_file.write_text(
json.dumps({"variants": [v.__dict__ for v in parsed]})
)
path = self.dir / name
path.write_text(self._wrapper_source(name, spec_file))
path.chmod(0o755)
if variants is None:
variants = [
{
"match": None,
"stdout": stdout,
"stderr": stderr,
"exit_code": exit_code,
},
]
parsed = []
for v in variants:
parsed.append(
Variant(
match=v["match"],
stdout=v.get("stdout", ""),
stderr=v.get("stderr", ""),
exit_code=v.get("exit_code", 0),
),
)
spec = StubSpec(parsed, func=func)
self._specs[name] = spec
spec_file = self.dir / f"{name}.json"
spec_file.write_text(
json.dumps({"variants": [v.__dict__ for v in parsed]}),
)
path = self.dir / name
path.write_text(self._wrapper_source(name, spec_file))
path.chmod(0o755)
🧰 Tools
🪛 Ruff (0.11.9)

67-67: Trailing comma missing

Add trailing comma

(COM812)


77-77: Trailing comma missing

Add trailing comma

(COM812)


83-83: Trailing comma missing

Add trailing comma

(COM812)

🤖 Prompt for AI Agents
In shellstub.py between lines 60 and 88, add trailing commas to all multi-line
data structures such as dictionaries and function arguments to maintain
consistency and improve readability. Locate each multi-line dictionary and
function call and ensure a comma is placed after the last item or argument.

Comment on lines +9 to +11
def run_script(
script: Path, env: dict[str, str], *args: str
) -> subprocess.CompletedProcess[str]:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Add trailing comma for consistency

 def run_script(
-    script: Path, env: dict[str, str], *args: str
+    script: Path, env: dict[str, str], *args: str,
 ) -> subprocess.CompletedProcess[str]:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def run_script(
script: Path, env: dict[str, str], *args: str
) -> subprocess.CompletedProcess[str]:
def run_script(
script: Path, env: dict[str, str], *args: str,
) -> subprocess.CompletedProcess[str]:
cmd = ["uv", "run", "--script", str(script), *args]
return subprocess.run(cmd, capture_output=True, text=True, env=env)
🧰 Tools
🪛 Ruff (0.11.9)

10-10: Trailing comma missing

Add trailing comma

(COM812)

🤖 Prompt for AI Agents
In .github/actions/generate-coverage/tests/test_scripts.py around lines 9 to 11,
the function definition for run_script is missing a trailing comma after the
last parameter for consistency. Add a trailing comma after the *args parameter
in the function signature to maintain consistent formatting.

assert not rust.exists()
assert not py.exists()
calls = shell_stubs.calls_of("uvx")
assert calls and calls[0].argv[:1] == ["merge-cobertura"]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Break down complex assertion for clarity

-    assert calls and calls[0].argv[:1] == ["merge-cobertura"]
+    assert len(calls) > 0
+    assert calls[0].argv[0] == "merge-cobertura"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
assert calls and calls[0].argv[:1] == ["merge-cobertura"]
calls = shell_stubs.calls_of("uvx")
assert len(calls) > 0
assert calls[0].argv[0] == "merge-cobertura"
🧰 Tools
🪛 Ruff (0.11.9)

114-114: Assertion should be broken down into multiple parts

Break down assertion into multiple parts

(PT018)

🤖 Prompt for AI Agents
In .github/actions/generate-coverage/tests/test_scripts.py at line 114, the
assertion combines multiple checks into one, which reduces clarity. Split the
assertion into separate statements: first assert that 'calls' is not empty, then
assert that the first element of 'calls[0].argv' matches ["merge-cobertura"].
This makes the test easier to read and debug.

Comment on lines +91 to +99
shell_stubs.register(
"uvx",
variants=[
{
"match": ["merge-cobertura", str(rust), str(py)],
"stdout": "<merged/>",
}
],
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Add trailing comma for consistency

         variants=[
             {
                 "match": ["merge-cobertura", str(rust), str(py)],
                 "stdout": "<merged/>",
-            }
+            },
         ],
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
shell_stubs.register(
"uvx",
variants=[
{
"match": ["merge-cobertura", str(rust), str(py)],
"stdout": "<merged/>",
}
],
)
shell_stubs.register(
"uvx",
variants=[
{
"match": ["merge-cobertura", str(rust), str(py)],
"stdout": "<merged/>",
},
],
)
🧰 Tools
🪛 Ruff (0.11.9)

97-97: Trailing comma missing

Add trailing comma

(COM812)

🤖 Prompt for AI Agents
In .github/actions/generate-coverage/tests/test_scripts.py around lines 91 to
99, the dictionary inside the variants list is missing a trailing comma after
the last key-value pair "stdout": "<merged/>". Add a trailing comma there to
maintain consistency with the surrounding code style.

@leynos leynos merged commit 1bf794a into main Jul 7, 2025
1 check passed
@leynos leynos deleted the codex/implement-test-helper-for-command-line-stubbing branch July 7, 2025 19:18
@coderabbitai coderabbitai Bot mentioned this pull request Jul 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant