Skip to content

Convert generate-coverage to Python scripts#23

Merged
leynos merged 5 commits intomainfrom
codex/convert-generate-coverage-to-python
Jul 6, 2025
Merged

Convert generate-coverage to Python scripts#23
leynos merged 5 commits intomainfrom
codex/convert-generate-coverage-to-python

Conversation

@leynos
Copy link
Copy Markdown
Owner

@leynos leynos commented Jul 5, 2025

Summary

  • replace bash blocks in generate-coverage with Python helpers
  • add new helper scripts under scripts/generate_coverage
  • document Python script approach in docs/python-action-scripts.md
  • refactor coverage detection logic with match/case and helper functions
  • extract coverage command generation into dedicated helpers
  • add docstrings to coverage helper functions
  • run ruff formatting on helper scripts

Testing

  • uvx ruff format scripts/generate_coverage/
  • uvx ruff check --select I --fix scripts/generate_coverage/
  • python -m py_compile scripts/generate_coverage/*.py scripts/ratchet_coverage/*.py

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

Summary by Sourcery

Convert the generate-coverage GitHub Action to use standalone Python helper scripts orchestrated via uv, replacing inline bash logic with reusable modules and improving readability and maintainability.

New Features:

  • Add Python scripts in scripts/generate_coverage for project detection, Rust coverage, Python coverage, merging Cobertura reports, and setting outputs.
  • Document the Python-based action script approach in docs/python-action-scripts.md

Enhancements:

  • Refactor coverage format and language detection using Typer and match/case in a dedicated detect script.
  • Extract slipcover and cargo llvm-cov command assembly into separate helper functions for cleaner logic.
  • Simplify the composite action YAML by invoking uv-run scripts instead of embedding bash blocks.

Documentation:

  • Introduce a guide for Python action scripts and their uv headers in docs/python-action-scripts.md

Chores:

  • Add docstrings to helper functions and apply ruff formatting to all Python scripts

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Jul 5, 2025

Reviewer's Guide

Replaces inline bash in the generate-coverage composite action with uv-run Python helper scripts, refactors detection and command-generation logic into modular functions with match/case and docstrings, adds documentation for the Python scripting approach, and applies ruff formatting to the new scripts.

Class diagram for new generate_coverage Python helpers

classDiagram
    class CoverageFmt {
        +LCOV
        +COBERTURA
        +COVERAGEPY
    }
    class CoverageFmtParam {
        +name
        +convert(value, param, ctx)
    }
    class detect_py {
        +get_lang() str
        +main(fmt, github_output)
    }
    class run_python_py {
        +coverage_cmd_for_fmt(fmt, out)
        +main(output_path, lang, fmt, github_output)
    }
    class run_rust_py {
        +get_cargo_coverage_cmd(fmt, out, features, with_default)
        +main(output_path, features, with_default, lang, fmt, github_output)
    }
    class merge_cobertura_py {
        +main(rust_file, python_file, output_path)
    }
    class set_outputs_py {
        +main(output_path, fmt, github_output)
    }
    CoverageFmtParam --> CoverageFmt
    detect_py --> CoverageFmt
    detect_py --> CoverageFmtParam
    run_python_py --> detect_py
    run_rust_py --> detect_py
    merge_cobertura_py --> run_rust_py
    merge_cobertura_py --> run_python_py
    set_outputs_py --> detect_py
Loading

File-Level Changes

Change Details Files
Swap out long shell blocks in the composite action for uv-run Python scripts
  • Replace bash detect, rust, python, merge and output steps with uv run commands
  • Pass inputs and outputs via environment variables
  • Remove inline pipefail, case and file-existence logic
.github/actions/generate-coverage/action.yml
Introduce dedicated Python helper scripts under scripts/generate_coverage
  • Add detect.py for language and format detection
  • Add run_rust.py to assemble and run cargo llvm-cov
  • Add run_python.py to run slipcover pytest and handle output
  • Add merge_cobertura.py to merge XML reports
  • Add set_outputs.py to write final outputs
scripts/generate_coverage/detect.py
scripts/generate_coverage/run_rust.py
scripts/generate_coverage/run_python.py
scripts/generate_coverage/merge_cobertura.py
scripts/generate_coverage/set_outputs.py
Refactor coverage logic into reusable functions with match/case
  • Implement get_lang and match/case format validation in detect.py
  • Extract get_cargo_coverage_cmd and coverage_cmd_for_fmt helpers
  • Centralize output-path manipulation for mixed projects
scripts/generate_coverage/detect.py
scripts/generate_coverage/run_rust.py
scripts/generate_coverage/run_python.py
Document the Python action scripting approach
  • Add docs/python-action-scripts.md explaining uv script headers
  • Outline use of Typer and Plumbum for parsing and command execution
docs/python-action-scripts.md
Add docstrings and apply ruff formatting to helper scripts
  • Include descriptive docstrings on all helper functions
  • Run uvx ruff format and uvx ruff check on scripts
scripts/generate_coverage/*.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 5, 2025

Warning

Rate limit exceeded

@leynos has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 2 minutes and 40 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between ececa4c and d89d2e6.

📒 Files selected for processing (1)
  • scripts/generate_coverage/merge_cobertura.py (1 hunks)

Summary by CodeRabbit

  • New Features

    • Introduced Python-based helper scripts to streamline and modularise coverage detection, execution, and merging for Rust, Python, and mixed-language projects within CI workflows.
    • Added comprehensive documentation outlining the use and requirements of the new Python action scripts.
  • Chores

    • Refactored the coverage generation GitHub Action to delegate logic to dedicated Python scripts, improving maintainability and readability.

Summary by CodeRabbit

  • New Features

    • Introduced Python scripts to handle coverage detection, execution, merging, and output setting for Rust, Python, and mixed-language projects within the coverage workflow.
    • Added documentation detailing the use of Python helper scripts for workflow actions.
  • Documentation

    • Added a guide explaining the new Python script-based approach for workflow actions, including usage examples and dependency management.

Walkthrough

The composite GitHub Action for coverage generation has been refactored to replace inline shell scripting with modular Python scripts. These scripts handle language and format detection, run coverage for Rust and Python, merge Cobertura reports for mixed projects, and set outputs, all orchestrated via uv run --script. Documentation was added for this scripting approach.

Changes

Files/Paths Change Summary
.github/actions/generate-coverage/action.yml Replaced shell steps with calls to Python scripts using uv run --script; logic is now externalised.
docs/python-action-scripts.md Added documentation explaining the use and structure of Python action scripts and their execution via uv.
scripts/generate_coverage/detect.py New script: detects project language, validates coverage format, outputs results for downstream steps.
scripts/generate_coverage/merge_cobertura.py New script: merges Rust and Python Cobertura XML files, deletes inputs, outputs merged file.
scripts/generate_coverage/run_python.py New script: runs Python coverage using slipcover/pytest, supports multiple formats, outputs result path.
scripts/generate_coverage/run_rust.py New script: runs Rust coverage with cargo llvm-cov, handles features, output path, and format.
scripts/generate_coverage/set_outputs.py New script: sets GitHub Action outputs for coverage file path and format.

Sequence Diagram(s)

sequenceDiagram
    participant GitHub Action
    participant detect.py
    participant run_rust.py
    participant run_python.py
    participant merge_cobertura.py
    participant set_outputs.py

    GitHub Action->>detect.py: Detect language & format
    detect.py-->>GitHub Action: Outputs language & format

    alt Rust only
        GitHub Action->>run_rust.py: Run Rust coverage
        run_rust.py-->>GitHub Action: Outputs coverage path
    else Python only
        GitHub Action->>run_python.py: Run Python coverage
        run_python.py-->>GitHub Action: Outputs coverage path
    else Mixed (Rust & Python)
        GitHub Action->>run_rust.py: Run Rust coverage
        GitHub Action->>run_python.py: Run Python coverage
        GitHub Action->>merge_cobertura.py: Merge Rust & Python reports
        merge_cobertura.py-->>GitHub Action: Outputs merged path
    end

    GitHub Action->>set_outputs.py: Set outputs for downstream steps
Loading

Possibly related PRs

Poem

🐇
Out with the bash, in with the script,
Python now runs where old logic slipped.
Detect, merge, and cover with flair,
Reports for Rust and Python pair.
With uv and Typer, the actions are neat—
A coverage carrot, oh what a treat!

✨ 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/convert-generate-coverage-to-python

🪧 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 and they look great!

Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments

### Comment 1
<location> `scripts/generate_coverage/run_python.py:48` </location>
<code_context>
+    except ProcessExecutionError as exc:
+        raise typer.Exit(code=exc.retcode or 1) from exc
+
+    if fmt == "coveragepy":
+        Path(".coverage").rename(out)
+
+    with github_output.open("a") as fh:
</code_context>

<issue_to_address>
Potential file overwrite if .coverage already exists at output location.

Path.rename() will fail with FileExistsError if the target file exists. Use Path.replace() or remove the existing file first to avoid unexpected errors.
</issue_to_address>

### Comment 2
<location> `scripts/generate_coverage/merge_cobertura.py:14` </location>
<code_context>
+from plumbum.commands.processes import ProcessExecutionError
+
+
+class ExistingFile(click.ParamType):
+    name = "file"
+
</code_context>

<issue_to_address>
Consider replacing the custom ExistingFile class with Typer's built-in file validation options for input arguments.

```suggestion
@@
-import click
 from pathlib import Path
-import typer
+import typer

-class ExistingFile(click.ParamType):
-    name = "file"
-
-    def __init__(self, kind: str) -> None:
-        """Create a validator that ensures the file exists."""
-        self.kind = kind
-
-    def convert(
-        self, value: str, param: click.Parameter | None, ctx: click.Context | None
-    ) -> Path:  # type: ignore[override]
-        """Validate that the provided path points to an existing file."""
-        path = Path(value)
-        if not path.is_file():
-            self.fail(f"{self.kind} file not found: {value}", param, ctx)
-        return path
@@
-def main(
-    rust_file: Path = typer.Option(
-        ..., envvar="RUST_FILE", type=ExistingFile("Rust coverage")
-    ),
-    python_file: Path = typer.Option(
-        ..., envvar="PYTHON_FILE", type=ExistingFile("Python coverage")
-    ),
-    output_path: Path = typer.Option(..., envvar="OUTPUT_PATH"),
-) -> None:
+def main(
+    rust_file: Path = typer.Option(
+        ..., envvar="RUST_FILE", exists=True, file_okay=True, dir_okay=False
+    ),
+    python_file: Path = typer.Option(
+        ..., envvar="PYTHON_FILE", exists=True, file_okay=True, dir_okay=False
+    ),
+    output_path: Path = typer.Option(..., envvar="OUTPUT_PATH"),
+) -> None:
```


Steps:
1. Remove the `click` import and `ExistingFile` class entirely.
2. For each file argument, use Typer’s built-in `exists`, `file_okay`, and `dir_okay` options.
3. Keep `Path` as the parameter type so Typer still returns a `Path` instance.
4. No change to downstream logic—all functionality is preserved.

</issue_to_address>

### Comment 3
<location> `docs/python-action-scripts.md:18` </location>
<code_context>
+
+The [Typer](https://typer.tiangolo.com/) library is used for argument parsing and
+error handling, while [plumbum](https://plumbum.readthedocs.io/) provides simple
+command execution.  By isolating logic in Python we keep the composite action
+YAML minimal and benefit from better readability and testability.
--- /dev/null
</code_context>

<issue_to_address>
The sentence uses "we", which should be avoided per the instructions.

Please rephrase to avoid "we". For example: "By isolating logic in Python, the composite action YAML remains minimal and benefits from better readability and testability."
</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 scripts/generate_coverage/run_python.py Outdated
Comment on lines +48 to +49
if fmt == "coveragepy":
Path(".coverage").rename(out)
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.

issue (bug_risk): Potential file overwrite if .coverage already exists at output location.

Path.rename() will fail with FileExistsError if the target file exists. Use Path.replace() or remove the existing file first to avoid unexpected errors.

from plumbum.commands.processes import ProcessExecutionError


class ExistingFile(click.ParamType):
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.

issue (complexity): Consider replacing the custom ExistingFile class with Typer's built-in file validation options for input arguments.

Suggested change
class ExistingFile(click.ParamType):
@@
-import click
from pathlib import Path
-import typer
+import typer
-class ExistingFile(click.ParamType):
- name = "file"
-
- def __init__(self, kind: str) -> None:
- """Create a validator that ensures the file exists."""
- self.kind = kind
-
- def convert(
- self, value: str, param: click.Parameter | None, ctx: click.Context | None
- ) -> Path: # type: ignore[override]
- """Validate that the provided path points to an existing file."""
- path = Path(value)
- if not path.is_file():
- self.fail(f"{self.kind} file not found: {value}", param, ctx)
- return path
@@
-def main(
- rust_file: Path = typer.Option(
- ..., envvar="RUST_FILE", type=ExistingFile("Rust coverage")
- ),
- python_file: Path = typer.Option(
- ..., envvar="PYTHON_FILE", type=ExistingFile("Python coverage")
- ),
- output_path: Path = typer.Option(..., envvar="OUTPUT_PATH"),
-) -> None:
+def main(
+ rust_file: Path = typer.Option(
+ ..., envvar="RUST_FILE", exists=True, file_okay=True, dir_okay=False
+ ),
+ python_file: Path = typer.Option(
+ ..., envvar="PYTHON_FILE", exists=True, file_okay=True, dir_okay=False
+ ),
+ output_path: Path = typer.Option(..., envvar="OUTPUT_PATH"),
+) -> None:

Steps:

  1. Remove the click import and ExistingFile class entirely.
  2. For each file argument, use Typer’s built-in exists, file_okay, and dir_okay options.
  3. Keep Path as the parameter type so Typer still returns a Path instance.
  4. No change to downstream logic—all functionality is preserved.

Comment thread docs/python-action-scripts.md Outdated

The [Typer](https://typer.tiangolo.com/) library is used for argument parsing and
error handling, while [plumbum](https://plumbum.readthedocs.io/) provides simple
command execution. By isolating logic in Python we keep the composite action
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.

suggestion (review_instructions): The sentence uses "we", which should be avoided per the instructions.

Please rephrase to avoid "we". For example: "By isolating logic in Python, the composite action YAML remains minimal and benefits from better readability and testability."

Review instructions:

Path patterns: **/*.md

Instructions:
Avoid 2nd person or 1st person pronouns ("I", "you", "we")

Comment on lines +34 to +43
cargo = Path("Cargo.toml").is_file()
python = Path("pyproject.toml").is_file()
if cargo and python:
return "mixed"
if cargo:
return "rust"
if python:
return "python"
typer.echo("Neither Cargo.toml nor pyproject.toml found", err=True)
raise typer.Exit(code=1)
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.

issue (code-quality): We've found these issues:

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: 16

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 4f9e02b and b80f1f6.

📒 Files selected for processing (7)
  • .github/actions/generate-coverage/action.yml (2 hunks)
  • docs/python-action-scripts.md (1 hunks)
  • scripts/generate_coverage/detect.py (1 hunks)
  • scripts/generate_coverage/merge_cobertura.py (1 hunks)
  • scripts/generate_coverage/run_python.py (1 hunks)
  • scripts/generate_coverage/run_rust.py (1 hunks)
  • scripts/generate_coverage/set_outputs.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
`**/*.md`: * Avoid 2nd person or 1st person pronouns ("I", "you", "we") * Use en...

**/*.md: * Avoid 2nd person or 1st person pronouns ("I", "you", "we")

  • Use en-oxendic spelling and grammar.
  • Paragraphs and bullets must be wrapped to 80 columns, except where a long URL would prevent this (in which case, silence MD013 for that line)
  • Code blocks should be wrapped to 120 columns.
  • Headings must not be wrapped.

⚙️ Source: CodeRabbit Configuration File

List of files the instruction was applied to:

  • docs/python-action-scripts.md
`.github/actions/*/{action.yml,README.md,CHANGELOG.md,src/,tests/}`: Each action...

.github/actions/*/{action.yml,README.md,CHANGELOG.md,src/,tests/}: Each action must have its own directory under .github/actions/, containing action.yml, README.md, src/, tests/, and CHANGELOG.md

📄 Source: CodeRabbit Inference Engine (AGENTS.md)

List of files the instruction was applied to:

  • .github/actions/generate-coverage/action.yml
`.github/actions/*/action.yml`: Fill in action.yml with every input and output; ...

.github/actions/*/action.yml: Fill in action.yml with every input and output; mark required ones clearly
For composite actions and path context, use "${{ github.action_path }}" when referencing sibling scripts for portability

📄 Source: CodeRabbit Inference Engine (AGENTS.md)

List of files the instruction was applied to:

  • .github/actions/generate-coverage/action.yml
🧬 Code Graph Analysis (2)
scripts/generate_coverage/set_outputs.py (3)
scripts/generate_coverage/run_python.py (1)
  • main (30-52)
scripts/generate_coverage/detect.py (1)
  • main (46-68)
scripts/generate_coverage/run_rust.py (1)
  • main (26-51)
scripts/generate_coverage/run_python.py (3)
scripts/generate_coverage/detect.py (1)
  • main (46-68)
scripts/generate_coverage/set_outputs.py (1)
  • main (11-19)
scripts/generate_coverage/run_rust.py (1)
  • main (26-51)
🪛 Ruff (0.11.9)
scripts/generate_coverage/set_outputs.py

1-1: Shebang is present but file is not executable

(EXE001)


12-12: Do not perform function call typer.Option in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


14-14: Do not perform function call typer.Option in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)

scripts/generate_coverage/run_rust.py

1-1: Shebang is present but file is not executable

(EXE001)


14-14: Boolean-typed positional argument in function definition

(FBT001)


14-14: Trailing comma missing

Add trailing comma

(COM812)


27-27: Do not perform function call typer.Option in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


29-29: Boolean-typed positional argument in function definition

(FBT001)


29-29: Boolean positional value in function call

(FBT003)


32-32: Do not perform function call typer.Option in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


46-46: Trailing comma missing

Add trailing comma

(COM812)

scripts/generate_coverage/run_python.py

1-1: Shebang is present but file is not executable

(EXE001)


14-14: Missing return type annotation for public function coverage_cmd_for_fmt

(ANN201)


31-31: Do not perform function call typer.Option in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


34-34: Do not perform function call typer.Option in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)

scripts/generate_coverage/merge_cobertura.py

1-1: Shebang is present but file is not executable

(EXE001)


22-22: Trailing comma missing

Add trailing comma

(COM812)


32-34: Do not perform function call typer.Option in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


33-33: Do not perform function call ExistingFile in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


33-33: Trailing comma missing

Add trailing comma

(COM812)


35-37: Do not perform function call typer.Option in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


36-36: Do not perform function call ExistingFile in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


36-36: Trailing comma missing

Add trailing comma

(COM812)


38-38: Do not perform function call typer.Option in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


45-45: Trailing comma missing

Add trailing comma

(COM812)

scripts/generate_coverage/detect.py

1-1: Shebang is present but file is not executable

(EXE001)


23-23: Trailing comma missing

Add trailing comma

(COM812)


47-49: Do not perform function call typer.Option in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


48-48: Do not perform function call CoverageFmtParam in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)


48-48: Trailing comma missing

Add trailing comma

(COM812)


50-50: Do not perform function call typer.Option in argument defaults; instead, perform the call within the function, or read the default from a module-level singleton variable

(B008)

🪛 Pylint (3.3.7)
scripts/generate_coverage/set_outputs.py

[convention] 1-1: Missing module docstring

(C0114)


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

(E0401)

scripts/generate_coverage/run_rust.py

[convention] 1-1: Missing module docstring

(C0114)


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

(E0401)


[error] 9-9: Unable to import 'plumbum.cmd'

(E0401)


[error] 10-10: Unable to import 'plumbum.commands.processes'

(E0401)


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

(R0913)


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

(R0917)

scripts/generate_coverage/run_python.py

[convention] 1-1: Missing module docstring

(C0114)


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

(E0401)


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

(E0401)


[error] 10-10: Unable to import 'plumbum.cmd'

(E0401)


[error] 11-11: Unable to import 'plumbum.commands.processes'

(E0401)

scripts/generate_coverage/merge_cobertura.py

[convention] 1-1: Missing module docstring

(C0114)


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

(E0401)


[error] 10-10: Unable to import 'plumbum.cmd'

(E0401)


[error] 11-11: Unable to import 'plumbum.commands.processes'

(E0401)


[convention] 14-14: Missing class docstring

(C0115)

scripts/generate_coverage/detect.py

[convention] 1-1: Missing module docstring

(C0114)


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

(E0401)


[convention] 13-13: Missing class docstring

(C0115)


[convention] 19-19: Missing class docstring

(C0115)


[refactor] 22-22: Either all return statements in a function should return an expression, or none of them should.

(R1710)

🪛 LanguageTool
docs/python-action-scripts.md

[style] ~5-~5: Since ownership is already implied, this phrasing may be redundant.
Context: ...uv run --script`. Each script declares its own dependencies via the special comment he...

(PRP_OWN)


[uncategorized] ~18-~18: Possible missing comma found.
Context: ...mmand execution. By isolating logic in Python we keep the composite action YAML minim...

(AI_HYDRA_LEO_MISSING_COMMA)

🔇 Additional comments (14)
scripts/generate_coverage/set_outputs.py (2)

11-24: LGTM! Clean and focused implementation.

The script correctly implements the output setting logic with proper error handling and follows the established pattern from other scripts in the same directory.


6-9: Consider adding a module docstring.

Adding a module docstring would improve code documentation and address the static analysis hint.

from pathlib import Path

+"""Set GitHub Actions output variables for coverage workflow."""
+
import typer

Likely an incorrect or invalid review comment.

docs/python-action-scripts.md (1)

1-20: Excellent documentation for the Python script approach.

The documentation clearly explains the rationale and implementation details for using Python helper scripts with uv. The examples are helpful and the explanation of benefits is concise.

scripts/generate_coverage/merge_cobertura.py (2)

14-29: Well-implemented file validation class.

The ExistingFile class provides good validation with clear error messages. The implementation correctly extends click.ParamType and provides meaningful feedback.


31-51: Excellent error handling and cleanup logic.

The script properly handles command execution errors, provides meaningful error messages, and cleans up input files after successful merging. The implementation follows the established pattern from other scripts.

.github/actions/generate-coverage/action.yml (3)

35-43: Excellent refactoring to use Python scripts.

The replacement of inline shell commands with dedicated Python scripts improves maintainability and testability. The environment variables properly pass data between steps.


63-76: Well-structured conditional execution.

The conditional logic for mixed projects is preserved whilst using the new Python scripts. The environment variable passing ensures proper data flow between the Rust and Python coverage steps and the merge operation.


77-81: Clean output setting with environment variables.

The final output setting step correctly uses environment variables to pass the detected format, maintaining consistency with the overall refactoring approach.

scripts/generate_coverage/run_python.py (1)

30-53: Excellent implementation with proper error handling.

The script correctly handles different coverage formats, adjusts output paths for mixed projects, ensures output directories exist, and provides appropriate error handling. The logic for renaming the .coverage file for the coveragepy format is particularly well-implemented.

scripts/generate_coverage/run_rust.py (2)

36-38: LGTM! Excellent handling of mixed language projects.

The logic to append .rust to the output filename for mixed projects is well-implemented and ensures proper separation of coverage files.


50-51: LGTM! Proper GitHub Actions integration.

The output writing to GITHUB_OUTPUT follows the correct format for GitHub Actions.

scripts/generate_coverage/detect.py (3)

32-44: LGTM! Excellent language detection logic.

The function correctly identifies project types based on the presence of Cargo.toml and pyproject.toml files. The logic handles all possible combinations appropriately.


55-65: Brilliant use of match/case for validation.

The validation logic using match/case statements is clean and comprehensive. It properly handles all incompatible format/language combinations:

  • Rust projects can't use coveragepy format
  • Python projects can't use lcov format
  • Mixed projects only support cobertura format

66-68: LGTM! Proper GitHub Actions output format.

The output writing correctly follows GitHub Actions conventions by appending to the output file.

@@ -0,0 +1,23 @@
#!/usr/bin/env -S uv run --script
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)

Make the script executable.

The shebang indicates this script should be executable, but the file lacks executable permissions.

chmod +x scripts/generate_coverage/set_outputs.py
🧰 Tools
🪛 Ruff (0.11.9)

1-1: Shebang is present but file is not executable

(EXE001)

🪛 Pylint (3.3.7)

[convention] 1-1: Missing module docstring

(C0114)

🤖 Prompt for AI Agents
In scripts/generate_coverage/set_outputs.py at line 1, the script has a shebang
indicating it should be executable, but the file currently lacks executable
permissions. Fix this by running the command chmod +x
scripts/generate_coverage/set_outputs.py to add executable permissions to the
file.

Comment thread docs/python-action-scripts.md Outdated
Comment on lines +3 to +6
Some actions use short helper scripts for logic that would otherwise live in bash.
These scripts are stored under `scripts/` and executed with [`uv`](https://github.com/astral-sh/uv) using
`uv run --script`. Each script declares its own dependencies via the
special comment header understood by uv.
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 removing redundant phrasing.

The phrase "its own dependencies" is redundant since ownership is already implied by context.

-Each script declares its own dependencies via the
+Each script declares dependencies via the
📝 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
Some actions use short helper scripts for logic that would otherwise live in bash.
These scripts are stored under `scripts/` and executed with [`uv`](https://github.com/astral-sh/uv) using
`uv run --script`. Each script declares its own dependencies via the
special comment header understood by uv.
Some actions use short helper scripts for logic that would otherwise live in bash.
These scripts are stored under `scripts/` and executed with [`uv`](https://github.com/astral-sh/uv) using
`uv run --script`. Each script declares dependencies via the
special comment header understood by uv.
🧰 Tools
🪛 LanguageTool

[style] ~5-~5: Since ownership is already implied, this phrasing may be redundant.
Context: ...uv run --script`. Each script declares its own dependencies via the special comment he...

(PRP_OWN)

🤖 Prompt for AI Agents
In docs/python-action-scripts.md around lines 3 to 6, remove the phrase "its
own" before "dependencies" to eliminate redundancy, so the sentence simply
states that each script declares dependencies via the special comment header
understood by uv.

@@ -0,0 +1,54 @@
#!/usr/bin/env -S uv run --script
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)

Make the script executable.

The shebang indicates this script should be executable, but the file lacks executable permissions.

chmod +x scripts/generate_coverage/merge_cobertura.py
🧰 Tools
🪛 Pylint (3.3.7)

[convention] 1-1: Missing module docstring

(C0114)

🪛 Ruff (0.11.9)

1-1: Shebang is present but file is not executable

(EXE001)

🤖 Prompt for AI Agents
In scripts/generate_coverage/merge_cobertura.py at line 1, the script has a
shebang indicating it should be executable, but the file currently lacks
executable permissions. Fix this by running the command chmod +x
scripts/generate_coverage/merge_cobertura.py to add executable permissions to
the file.

Comment thread scripts/generate_coverage/merge_cobertura.py
Comment on lines +13 to +24
def get_cargo_coverage_cmd(
fmt: str, out: Path, features: str, with_default: bool
) -> list[str]:
"""Return the cargo llvm-cov command arguments."""
args = ["llvm-cov", "--workspace"]
if not with_default:
args.append("--no-default-features")
if features:
args += ["--features", features]
args += [f"--{fmt}", "--output-path", str(out)]
return args

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 refactoring boolean parameter and add trailing comma.

The function has a boolean positional parameter which can be confusing. Consider making it keyword-only or using an enum for clarity.

 def get_cargo_coverage_cmd(
-    fmt: str, out: Path, features: str, with_default: bool
+    fmt: str, out: Path, features: str, *, with_default: bool,
 ) -> list[str]:

This makes the boolean parameter keyword-only, improving readability at call sites.

📝 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 get_cargo_coverage_cmd(
fmt: str, out: Path, features: str, with_default: bool
) -> list[str]:
"""Return the cargo llvm-cov command arguments."""
args = ["llvm-cov", "--workspace"]
if not with_default:
args.append("--no-default-features")
if features:
args += ["--features", features]
args += [f"--{fmt}", "--output-path", str(out)]
return args
def get_cargo_coverage_cmd(
fmt: str, out: Path, features: str, *, with_default: bool,
) -> list[str]:
"""Return the cargo llvm-cov command arguments."""
args = ["llvm-cov", "--workspace"]
if not with_default:
args.append("--no-default-features")
if features:
args += ["--features", features]
args += [f"--{fmt}", "--output-path", str(out)]
return args
🧰 Tools
🪛 Ruff (0.11.9)

14-14: Boolean-typed positional argument in function definition

(FBT001)


14-14: Trailing comma missing

Add trailing comma

(COM812)

🤖 Prompt for AI Agents
In scripts/generate_coverage/run_rust.py around lines 13 to 24, the function
get_cargo_coverage_cmd uses a boolean positional parameter with_default, which
can be unclear at call sites. Refactor the function to make with_default a
keyword-only parameter by adding a * before it in the parameter list, so callers
must specify it by name. Also, add a trailing comma after the last parameter for
cleaner diffs and consistency.

Comment on lines +1 to +5
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.12"
# dependencies = ["typer"]
# ///
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 module docstring and address shebang permissions.

The script is missing a module docstring and the shebang indicates it should be executable.

 #!/usr/bin/env -S uv run --script
+"""Detect project language and validate coverage format compatibility."""
 # /// script
 # requires-python = ">=3.12"
 # dependencies = ["typer"]
 # ///

Also ensure the script has executable permissions:

chmod +x scripts/generate_coverage/detect.py
🧰 Tools
🪛 Pylint (3.3.7)

[convention] 1-1: Missing module docstring

(C0114)

🪛 Ruff (0.11.9)

1-1: Shebang is present but file is not executable

(EXE001)

🤖 Prompt for AI Agents
In scripts/generate_coverage/detect.py at the top of the file (lines 1 to 5),
add a module-level docstring describing the purpose of the script. Also, ensure
the shebang line is correct for execution and set the file's executable
permissions by running chmod +x on the script file.

Comment thread scripts/generate_coverage/detect.py
Comment thread scripts/generate_coverage/detect.py Outdated
Comment thread scripts/generate_coverage/detect.py
@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Jul 5, 2025

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jul 5, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Jul 5, 2025

@sourcery-ai review

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:

  • Make sure each uv-run script step in your composite action actually exports the required INPUT_* env vars (e.g. INPUT_OUTPUT_PATH, INPUT_FEATURES, INPUT_WITH_DEFAULT_FEATURES) so the scripts don’t error on missing required options.
  • detect.py mixes click.ParamType with Typer; consider using a Typer-native ParamType (or centralizing your enum) to avoid pulling in click directly and keep consistency across scripts.
  • You’ve defined coverage formats as an enum in detect.py but then use raw strings in run_*.py—extract format definitions into a shared module or reuse the enum to prevent drift when formats change.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Make sure each uv-run script step in your composite action actually exports the required INPUT_* env vars (e.g. INPUT_OUTPUT_PATH, INPUT_FEATURES, INPUT_WITH_DEFAULT_FEATURES) so the scripts don’t error on missing required options.
- detect.py mixes click.ParamType with Typer; consider using a Typer-native ParamType (or centralizing your enum) to avoid pulling in click directly and keep consistency across scripts.
- You’ve defined coverage formats as an enum in detect.py but then use raw strings in run_*.py—extract format definitions into a shared module or reuse the enum to prevent drift when formats change.

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 scripts/generate_coverage/detect.py
@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Jul 5, 2025

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jul 5, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Jul 5, 2025

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jul 5, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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 (7)
scripts/generate_coverage/set_outputs.py (1)

1-1: Make the script executable.

The shebang indicates this script should be executable, but the file lacks executable permissions.

chmod +x scripts/generate_coverage/set_outputs.py
scripts/generate_coverage/merge_cobertura.py (1)

1-1: Make the script executable.

The shebang indicates this script should be executable, but the file lacks executable permissions.

chmod +x scripts/generate_coverage/merge_cobertura.py
scripts/generate_coverage/run_python.py (1)

1-1: Make the script executable.

The shebang indicates this script should be executable, but the file lacks executable permissions.

chmod +x scripts/generate_coverage/run_python.py
scripts/generate_coverage/run_rust.py (3)

1-1: Make the script executable.

The shebang indicates this script should be executable, but the file lacks executable permissions.

chmod +x scripts/generate_coverage/run_rust.py

22-24: Address boolean parameter and trailing comma issues.

The function has a boolean positional parameter which can be confusing at call sites, and is missing a trailing comma.

 def get_cargo_coverage_cmd(
-    fmt: str, out: Path, features: str, with_default: bool
+    fmt: str, out: Path, features: str, *, with_default: bool,
 ) -> list[str]:

Making with_default keyword-only improves readability at call sites.


54-56: Add trailing comma for consistency.

Consider adding a trailing comma for better style consistency.

         typer.echo(
-            f"cargo llvm-cov failed with code {exc.retcode}: {exc.stderr}", err=True
+            f"cargo llvm-cov failed with code {exc.retcode}: {exc.stderr}", err=True,
         )
scripts/generate_coverage/detect.py (1)

1-1: Make the script executable.

The shebang indicates this script should be executable, but the file lacks executable permissions.

chmod +x scripts/generate_coverage/detect.py
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 208a7ac and f6d896c.

📒 Files selected for processing (5)
  • scripts/generate_coverage/detect.py (1 hunks)
  • scripts/generate_coverage/merge_cobertura.py (1 hunks)
  • scripts/generate_coverage/run_python.py (1 hunks)
  • scripts/generate_coverage/run_rust.py (1 hunks)
  • scripts/generate_coverage/set_outputs.py (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (4)
scripts/generate_coverage/set_outputs.py (4)
scripts/generate_coverage/merge_cobertura.py (1)
  • main (23-38)
scripts/generate_coverage/detect.py (1)
  • main (63-83)
scripts/generate_coverage/run_python.py (1)
  • main (38-60)
scripts/generate_coverage/run_rust.py (1)
  • main (35-60)
scripts/generate_coverage/detect.py (4)
scripts/generate_coverage/merge_cobertura.py (1)
  • main (23-38)
scripts/generate_coverage/run_python.py (1)
  • main (38-60)
scripts/generate_coverage/run_rust.py (1)
  • main (35-60)
scripts/generate_coverage/set_outputs.py (1)
  • main (17-25)
scripts/generate_coverage/run_rust.py (4)
scripts/generate_coverage/merge_cobertura.py (1)
  • main (23-38)
scripts/generate_coverage/detect.py (1)
  • main (63-83)
scripts/generate_coverage/run_python.py (1)
  • main (38-60)
scripts/generate_coverage/set_outputs.py (1)
  • main (17-25)
scripts/generate_coverage/merge_cobertura.py (3)
scripts/generate_coverage/detect.py (1)
  • main (63-83)
scripts/generate_coverage/run_python.py (1)
  • main (38-60)
scripts/generate_coverage/run_rust.py (1)
  • main (35-60)
🪛 Pylint (3.3.7)
scripts/generate_coverage/set_outputs.py

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

(E0401)

scripts/generate_coverage/detect.py

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

(E0401)


[refactor] 28-28: Either all return statements in a function should return an expression, or none of them should.

(R1710)

scripts/generate_coverage/run_python.py

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

(E0401)


[error] 11-11: Unable to import 'plumbum'

(E0401)


[error] 12-12: Unable to import 'plumbum.cmd'

(E0401)


[error] 13-13: Unable to import 'plumbum.commands.base'

(E0401)


[error] 14-14: Unable to import 'plumbum.commands.processes'

(E0401)

scripts/generate_coverage/run_rust.py

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

(E0401)


[error] 11-11: Unable to import 'plumbum.cmd'

(E0401)


[error] 12-12: Unable to import 'plumbum.commands.processes'

(E0401)


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

(R0913)


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

(R0917)

scripts/generate_coverage/merge_cobertura.py

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

(E0401)


[error] 11-11: Unable to import 'plumbum.cmd'

(E0401)


[error] 12-12: Unable to import 'plumbum.commands.processes'

(E0401)

🪛 Ruff (0.11.9)
scripts/generate_coverage/run_rust.py

16-16: Boolean positional value in function call

(FBT003)


23-23: Boolean-typed positional argument in function definition

(FBT001)


23-23: Trailing comma missing

Add trailing comma

(COM812)


38-38: Boolean-typed positional argument in function definition

(FBT001)


55-55: Trailing comma missing

Add trailing comma

(COM812)

scripts/generate_coverage/merge_cobertura.py

15-15: Trailing comma missing

Add trailing comma

(COM812)


18-18: Trailing comma missing

Add trailing comma

(COM812)


33-33: Trailing comma missing

Add trailing comma

(COM812)

🔇 Additional comments (7)
scripts/generate_coverage/set_outputs.py (1)

17-25: LGTM! Clean and straightforward implementation.

The function correctly writes the coverage file path and format to the GitHub Actions output file. The implementation is simple and follows the established pattern used by other scripts in this suite.

scripts/generate_coverage/merge_cobertura.py (1)

23-38: LGTM! Excellent error handling and cleanup.

The implementation correctly merges Cobertura files, handles command execution errors appropriately, and cleans up input files after successful merging. The use of typer's built-in file validation is a good improvement over custom validation logic.

scripts/generate_coverage/run_python.py (2)

22-35: LGTM! Well-structured helper function.

The function properly returns different slipcover commands based on the format, with correct return type annotation. The logic for cobertura vs coveragepy formats is clear and appropriate.


56-57: Good use of replace() for file handling.

Using Path(".coverage").replace(out) correctly handles potential file overwrites, addressing the concern about FileExistsError that could occur with rename().

scripts/generate_coverage/run_rust.py (1)

44-60: LGTM! Solid coverage execution logic.

The main function correctly handles mixed project file naming, creates output directories, executes cargo commands, and provides good error handling with detailed error messages.

scripts/generate_coverage/detect.py (2)

49-60: LGTM! Robust language detection logic.

The function correctly detects project types based on the presence of Cargo.toml and pyproject.toml files, handling all combinations appropriately including mixed projects.


70-83: Excellent format compatibility validation.

The match/case logic comprehensively validates format compatibility between languages, correctly rejecting invalid combinations like coveragepy for Rust projects or lcov for Python projects. The constraint that mixed projects only support cobertura format is logical and well-enforced.

Comment thread scripts/generate_coverage/merge_cobertura.py
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
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

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between f6d896c and ececa4c.

📒 Files selected for processing (1)
  • scripts/generate_coverage/merge_cobertura.py (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
scripts/generate_coverage/merge_cobertura.py (4)
scripts/generate_coverage/detect.py (1)
  • main (63-83)
scripts/generate_coverage/run_python.py (1)
  • main (38-60)
scripts/generate_coverage/run_rust.py (1)
  • main (35-60)
scripts/generate_coverage/set_outputs.py (1)
  • main (17-25)
🪛 Ruff (0.11.9)
scripts/generate_coverage/merge_cobertura.py

33-33: Trailing comma missing

Add trailing comma

(COM812)

🪛 Pylint (3.3.7)
scripts/generate_coverage/merge_cobertura.py

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

(E0401)


[error] 11-11: Unable to import 'plumbum.cmd'

(E0401)


[error] 12-12: Unable to import 'plumbum.commands.processes'

(E0401)

🔇 Additional comments (1)
scripts/generate_coverage/merge_cobertura.py (1)

23-38: Well-implemented merge logic with proper error handling.

The implementation correctly:

  • Executes the merge command with proper error handling
  • Writes the merged output to the specified path
  • Cleans up input files after successful merge
  • Provides clear error messages on failure

The destructive file deletion is appropriate given the documented behaviour in the function docstring.

Comment thread scripts/generate_coverage/merge_cobertura.py
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@leynos leynos merged commit 662597c into main Jul 6, 2025
1 check passed
@leynos leynos deleted the codex/convert-generate-coverage-to-python branch July 6, 2025 00:29
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